1 /* 2 * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package com.sun.org.apache.xml.internal.dtm.ref; 22 23 import com.sun.org.apache.xalan.internal.utils.FactoryImpl; 24 import com.sun.org.apache.xml.internal.dtm.DTM; 25 import com.sun.org.apache.xml.internal.dtm.DTMException; 26 import com.sun.org.apache.xml.internal.dtm.DTMFilter; 27 import com.sun.org.apache.xml.internal.dtm.DTMIterator; 28 import com.sun.org.apache.xml.internal.dtm.DTMManager; 29 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter; 30 import com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTM; 31 import com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTMdefaultNamespaceDeclarationNode; 32 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM; 33 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2RTFDTM; 34 import com.sun.org.apache.xml.internal.res.XMLErrorResources; 35 import com.sun.org.apache.xml.internal.res.XMLMessages; 36 import com.sun.org.apache.xml.internal.utils.PrefixResolver; 37 import com.sun.org.apache.xml.internal.utils.SystemIDResolver; 38 import com.sun.org.apache.xml.internal.utils.WrappedRuntimeException; 39 import com.sun.org.apache.xml.internal.utils.XMLReaderManager; 40 import com.sun.org.apache.xml.internal.utils.XMLStringFactory; 41 import javax.xml.parsers.DocumentBuilder; 42 import javax.xml.parsers.DocumentBuilderFactory; 43 import javax.xml.transform.Source; 44 import javax.xml.transform.dom.DOMSource; 45 import javax.xml.transform.sax.SAXSource; 46 import javax.xml.transform.stream.StreamSource; 47 import jdk.xml.internal.JdkXmlUtils; 48 import org.w3c.dom.Document; 49 import org.w3c.dom.Node; 50 import org.xml.sax.InputSource; 51 import org.xml.sax.SAXException; 52 import org.xml.sax.SAXNotRecognizedException; 53 import org.xml.sax.SAXNotSupportedException; 54 import org.xml.sax.XMLReader; 55 import org.xml.sax.helpers.DefaultHandler; 56 57 /** 58 * The default implementation for the DTMManager. 59 * 60 * %REVIEW% There is currently a reentrancy issue, since the finalizer 61 * for XRTreeFrag (which runs in the GC thread) wants to call 62 * DTMManager.release(), and may do so at the same time that the main 63 * transformation thread is accessing the manager. Our current solution is 64 * to make most of the manager's methods <code>synchronized</code>. 65 * Early tests suggest that doing so is not causing a significant 66 * performance hit in Xalan. However, it should be noted that there 67 * is a possible alternative solution: rewrite release() so it merely 68 * posts a request for release onto a threadsafe queue, and explicitly 69 * process that queue on an infrequent basis during main-thread 70 * activity (eg, when getDTM() is invoked). The downside of that solution 71 * would be a greater delay before the DTM's storage is actually released 72 * for reuse. 73 * */ 74 public class DTMManagerDefault extends DTMManager { 75 76 /** 77 * Map from DTM identifier numbers to DTM objects that this manager manages. 78 * One DTM may have several prefix numbers, if extended node indexing 79 * is in use; in that case, m_dtm_offsets[] will used to control which 80 * prefix maps to which section of the DTM. 81 * 82 * This array grows as necessary; see addDTM(). 83 * 84 * This array grows as necessary; see addDTM(). Growth is uncommon... but 85 * access needs to be blindingly fast since it's used in node addressing. 86 */ 87 protected DTM m_dtms[] = new DTM[256]; 88 89 /** Map from DTM identifier numbers to offsets. For small DTMs with a 90 * single identifier, this will always be 0. In overflow addressing, where 91 * additional identifiers are allocated to access nodes beyond the range of 92 * a single Node Handle, this table is used to map the handle's node field 93 * into the actual node identifier. 94 * 95 * This array grows as necessary; see addDTM(). 96 * 97 * This array grows as necessary; see addDTM(). Growth is uncommon... but 98 * access needs to be blindingly fast since it's used in node addressing. 99 * (And at the moment, that includes accessing it from DTMDefaultBase, 100 * which is why this is not Protected or Private.) 101 */ 102 int m_dtm_offsets[] = new int[256]; 103 104 /** 105 * The cache for XMLReader objects to be used if the user did not 106 * supply an XMLReader for a SAXSource or supplied a StreamSource. 107 */ 108 protected XMLReaderManager m_readerManager = null; 109 110 /** 111 * The default implementation of ContentHandler, DTDHandler and ErrorHandler. 112 */ 113 protected DefaultHandler m_defaultHandler = new DefaultHandler(); 114 115 /** 116 * Add a DTM to the DTM table. This convenience call adds it as the 117 * "base DTM ID", with offset 0. The other version of addDTM should 118 * be used if you want to add "extended" DTM IDs with nonzero offsets. 119 * 120 * @param dtm Should be a valid reference to a DTM. 121 * @param id Integer DTM ID to be bound to this DTM 122 */ 123 synchronized public void addDTM(DTM dtm, int id) { 124 addDTM(dtm,id,0); 125 } 126 127 /** 128 * Add a DTM to the DTM table. 129 * 130 * @param dtm Should be a valid reference to a DTM. 131 * @param id Integer DTM ID to be bound to this DTM. 132 * @param offset Integer addressing offset. The internal DTM Node ID is 133 * obtained by adding this offset to the node-number field of the 134 * public DTM Handle. For the first DTM ID accessing each DTM, this is 0; 135 * for overflow addressing it will be a multiple of 1<<IDENT_DTM_NODE_BITS. 136 */ 137 synchronized public void addDTM(DTM dtm, int id, int offset) { 138 if (id >= IDENT_MAX_DTMS) { 139 // TODO: %REVIEW% Not really the right error message. 140 throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_DTMIDS_AVAIL, null)); //"No more DTM IDs are available!"); 141 } 142 143 // We used to just allocate the array size to IDENT_MAX_DTMS. 144 // But we expect to increase that to 16 bits, and I'm not willing 145 // to allocate that much space unless needed. We could use one of our 146 // handy-dandy Fast*Vectors, but this will do for now. 147 // %REVIEW% 148 int oldlen = m_dtms.length; 149 if(oldlen <= id) { 150 // Various growth strategies are possible. I think we don't want 151 // to over-allocate excessively, and I'm willing to reallocate 152 // more often to get that. See also Fast*Vector classes. 153 // 154 // %REVIEW% Should throw a more diagnostic error if we go over the max... 155 int newlen = Math.min((id+256),IDENT_MAX_DTMS); 156 DTM new_m_dtms[] = new DTM[newlen]; 157 System.arraycopy(m_dtms,0,new_m_dtms,0,oldlen); 158 m_dtms=new_m_dtms; 159 int new_m_dtm_offsets[] = new int[newlen]; 160 System.arraycopy(m_dtm_offsets,0,new_m_dtm_offsets,0,oldlen); 161 m_dtm_offsets=new_m_dtm_offsets; 162 } 163 164 m_dtms[id] = dtm; 165 m_dtm_offsets[id]=offset; 166 dtm.documentRegistration(); 167 // The DTM should have been told who its manager was when we created it. 168 // Do we need to allow for adopting DTMs _not_ created by this manager? 169 } 170 171 /** 172 * Get the first free DTM ID available. %OPT% Linear search is inefficient! 173 */ 174 synchronized public int getFirstFreeDTMID() { 175 int n = m_dtms.length; 176 for (int i = 1; i < n; i++) { 177 if(null == m_dtms[i]) { 178 return i; 179 } 180 } 181 return n; // count on addDTM() to throw exception if out of range 182 } 183 184 /** 185 * The default table for exandedNameID lookups. 186 */ 187 private ExpandedNameTable m_expandedNameTable = new ExpandedNameTable(); 188 189 /** 190 * Constructor DTMManagerDefault 191 * 192 */ 193 public DTMManagerDefault() {} 194 195 /** 196 * Get an instance of a DTM, loaded with the content from the 197 * specified source. If the unique flag is true, a new instance will 198 * always be returned. Otherwise it is up to the DTMManager to return a 199 * new instance or an instance that it already created and may be being used 200 * by someone else. 201 * 202 * A bit of magic in this implementation: If the source is null, unique is true, 203 * and incremental and doIndexing are both false, we return an instance of 204 * SAX2RTFDTM, which see. 205 * 206 * (I think more parameters will need to be added for error handling, and entity 207 * resolution, and more explicit control of the RTF situation). 208 * 209 * @param source the specification of the source object. 210 * @param unique true if the returned DTM must be unique, probably because it 211 * is going to be mutated. 212 * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may 213 * be null. 214 * @param incremental true if the DTM should be built incrementally, if 215 * possible. 216 * @param doIndexing true if the caller considers it worth it to use 217 * indexing schemes. 218 * 219 * @return a non-null DTM reference. 220 */ 221 synchronized public DTM getDTM(Source source, boolean unique, 222 DTMWSFilter whiteSpaceFilter, 223 boolean incremental, boolean doIndexing) 224 { 225 /* Uncomment for debugging 226 if (null != source) { 227 System.out.println("Starting " + 228 (unique ? "UNIQUE" : "shared") + 229 " source: " + source.getSystemId()); 230 } 231 */ 232 233 XMLStringFactory xstringFactory = m_xsf; 234 int dtmPos = getFirstFreeDTMID(); 235 int documentID = dtmPos << IDENT_DTM_NODE_BITS; 236 237 if ((null != source) && source instanceof DOMSource) { 238 DOM2DTM dtm = new DOM2DTM(this, (DOMSource) source, documentID, 239 whiteSpaceFilter, xstringFactory, doIndexing); 240 241 addDTM(dtm, dtmPos, 0); 242 243 /* Uncomment for debugging 244 dtm.dumpDTM(); 245 */ 246 247 return dtm; 248 } else { 249 boolean isSAXSource = (null != source) ? (source instanceof SAXSource) : true; 250 boolean isStreamSource = (null != source) ? (source instanceof StreamSource) : false; 251 252 if (isSAXSource || isStreamSource) { 253 XMLReader reader = null; 254 SAX2DTM dtm; 255 256 try { 257 InputSource xmlSource; 258 259 if (null == source) { 260 xmlSource = null; 261 } else { 262 reader = getXMLReader(source); 263 xmlSource = SAXSource.sourceToInputSource(source); 264 265 String urlOfSource = xmlSource.getSystemId(); 266 267 if (null != urlOfSource) { 268 try { 269 urlOfSource = SystemIDResolver.getAbsoluteURI(urlOfSource); 270 } catch (Exception e) { 271 // %REVIEW% Is there a better way to send a warning? 272 System.err.println("Can not absolutize URL: " + urlOfSource); 273 } 274 275 xmlSource.setSystemId(urlOfSource); 276 } 277 } 278 279 if (source==null && unique && !incremental && !doIndexing) { 280 // Special case to support RTF construction into shared DTM. 281 // It should actually still work for other uses, 282 // but may be slightly deoptimized relative to the base 283 // to allow it to deal with carrying multiple documents. 284 // 285 // %REVIEW% This is a sloppy way to request this mode; 286 // we need to consider architectural improvements. 287 dtm = new SAX2RTFDTM(this, source, documentID, whiteSpaceFilter, 288 xstringFactory, doIndexing); 289 } else { 290 // Create the basic SAX2DTM. 291 dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter, 292 xstringFactory, doIndexing); 293 } 294 295 // Go ahead and add the DTM to the lookup table. This needs to be 296 // done before any parsing occurs. Note offset 0, since we've just 297 // created a new DTM. 298 addDTM(dtm, dtmPos, 0); 299 300 boolean haveXercesParser = 301 (null != reader) 302 && (reader.getClass() 303 .getName() 304 .equals("com.sun.org.apache.xerces.internal.parsers.SAXParser")); 305 306 if (haveXercesParser) { 307 incremental = true; // No matter what. %REVIEW% 308 } 309 310 // If the reader is null, but they still requested an incremental 311 // build, then we still want to set up the IncrementalSAXSource stuff. 312 if (m_incremental && incremental) { 313 IncrementalSAXSource coParser=null; 314 315 if (haveXercesParser) { 316 // IncrementalSAXSource_Xerces to avoid threading. 317 try { 318 coParser = new IncrementalSAXSource_Xerces(); 319 } catch( Exception ex ) { 320 ex.printStackTrace(); 321 coParser=null; 322 } 323 } 324 325 if (coParser==null ) { 326 // Create a IncrementalSAXSource to run on the secondary thread. 327 if (null == reader) { 328 coParser = new IncrementalSAXSource_Filter(); 329 } else { 330 IncrementalSAXSource_Filter filter = 331 new IncrementalSAXSource_Filter(); 332 filter.setXMLReader(reader); 333 coParser=filter; 334 } 335 } 336 337 // Have the DTM set itself up as IncrementalSAXSource's listener. 338 dtm.setIncrementalSAXSource(coParser); 339 340 if (null == xmlSource) { 341 // Then the user will construct it themselves. 342 return dtm; 343 } 344 345 if (null == reader.getErrorHandler()) { 346 reader.setErrorHandler(dtm); 347 } 348 reader.setDTDHandler(dtm); 349 350 try { 351 // Launch parsing coroutine. Launches a second thread, 352 // if we're using IncrementalSAXSource.filter(). 353 354 coParser.startParse(xmlSource); 355 } catch (RuntimeException re) { 356 dtm.clearCoRoutine(); 357 throw re; 358 } catch (Exception e) { 359 dtm.clearCoRoutine(); 360 throw new WrappedRuntimeException(e); 361 } 362 } else { 363 if (null == reader) { 364 // Then the user will construct it themselves. 365 return dtm; 366 } 367 368 // not incremental 369 reader.setContentHandler(dtm); 370 reader.setDTDHandler(dtm); 371 if (null == reader.getErrorHandler()) { 372 reader.setErrorHandler(dtm); 373 } 374 375 JdkXmlUtils.setXMLReaderPropertyIfSupport(reader, 376 "http://xml.org/sax/properties/lexical-handler", dtm, false); 377 378 try { 379 reader.parse(xmlSource); 380 } catch (RuntimeException re) { 381 dtm.clearCoRoutine(); 382 throw re; 383 } catch (Exception e) { 384 dtm.clearCoRoutine(); 385 throw new WrappedRuntimeException(e); 386 } 387 } 388 389 /* Uncomment for debugging 390 System.out.println("Dumping SAX2DOM"); 391 dtm.dumpDTM(System.err); 392 */ 393 394 return dtm; 395 } finally { 396 // Reset the ContentHandler, DTDHandler, ErrorHandler to the DefaultHandler 397 // after creating the DTM. 398 if (reader != null && !(m_incremental && incremental)) { 399 reader.setContentHandler(m_defaultHandler); 400 reader.setDTDHandler(m_defaultHandler); 401 reader.setErrorHandler(m_defaultHandler); 402 403 // Reset the LexicalHandler to null after creating the DTM. 404 try { 405 reader.setProperty("http://xml.org/sax/properties/lexical-handler", null); 406 } 407 catch (Exception e) {} 408 } 409 releaseXMLReader(reader); 410 } 411 } else { 412 // It should have been handled by a derived class or the caller 413 // made a mistake. 414 throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NOT_SUPPORTED, new Object[]{source})); //"Not supported: " + source); 415 } 416 } 417 } 418 419 /** 420 * Given a W3C DOM node, try and return a DTM handle. 421 * Note: calling this may be non-optimal, and there is no guarantee that 422 * the node will be found in any particular DTM. 423 * 424 * @param node Non-null reference to a DOM node. 425 * 426 * @return a valid DTM handle. 427 */ 428 synchronized public int getDTMHandleFromNode(Node node) 429 { 430 if (node == null) { 431 throw new IllegalArgumentException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NODE_NON_NULL, null)); //"node must be non-null for getDTMHandleFromNode!"); 432 } 433 434 if (node instanceof DTMNodeProxy) { 435 return ((DTMNodeProxy)node).getDTMNodeNumber(); 436 } else { 437 // Find the DOM2DTMs wrapped around this Document (if any) 438 // and check whether they contain the Node in question. 439 // 440 // NOTE that since a DOM2DTM may represent a subtree rather 441 // than a full document, we have to be prepared to check more 442 // than one -- and there is no guarantee that we will find 443 // one that contains ancestors or siblings of the node we're 444 // seeking. 445 // 446 // %REVIEW% We could search for the one which contains this 447 // node at the deepest level, and thus covers the widest 448 // subtree, but that's going to entail additional work 449 // checking more DTMs... and getHandleOfNode is not a 450 // cheap operation in most implementations. 451 // 452 // TODO: %REVIEW% If overflow addressing, we may recheck a DTM 453 // already examined. Ouch. But with the increased number of DTMs, 454 // scanning back to check this is painful. 455 // POSSIBLE SOLUTIONS: 456 // Generate a list of _unique_ DTM objects? 457 // Have each DTM cache last DOM node search? 458 int max = m_dtms.length; 459 for (int i = 0; i < max; i++) { 460 DTM thisDTM = m_dtms[i]; 461 if ((null != thisDTM) && thisDTM instanceof DOM2DTM) { 462 int handle=((DOM2DTM)thisDTM).getHandleOfNode(node); 463 if (handle!=DTM.NULL) { 464 return handle; 465 } 466 } 467 } 468 469 // Not found; generate a new DTM. 470 // 471 // %REVIEW% Is this really desirable, or should we return null 472 // and make folks explicitly instantiate from a DOMSource? The 473 // latter is more work but gives the caller the opportunity to 474 // explicitly add the DTM to a DTMManager... and thus to know when 475 // it can be discarded again, which is something we need to pay much 476 // more attention to. (Especially since only DTMs which are assigned 477 // to a manager can use the overflow addressing scheme.) 478 // 479 // %BUG% If the source node was a DOM2DTM$defaultNamespaceDeclarationNode 480 // and the DTM wasn't registered with this DTMManager, we will create 481 // a new DTM and _still_ not be able to find the node (since it will 482 // be resynthesized). Another reason to push hard on making all DTMs 483 // be managed DTMs. 484 485 // Since the real root of our tree may be a DocumentFragment, we need to 486 // use getParent to find the root, instead of getOwnerDocument. Otherwise 487 // DOM2DTM#getHandleOfNode will be very unhappy. 488 Node root = node; 489 Node p = (root.getNodeType() == Node.ATTRIBUTE_NODE) ? ((org.w3c.dom.Attr)root).getOwnerElement() : root.getParentNode(); 490 for (; p != null; p = p.getParentNode()) { 491 root = p; 492 } 493 494 DOM2DTM dtm = (DOM2DTM) getDTM(new javax.xml.transform.dom.DOMSource(root), false, null, true, true); 495 496 int handle; 497 498 if (node instanceof DOM2DTMdefaultNamespaceDeclarationNode) { 499 // Can't return the same node since it's unique to a specific DTM, 500 // but can return the equivalent node -- find the corresponding 501 // Document Element, then ask it for the xml: namespace decl. 502 handle = dtm.getHandleOfNode(((org.w3c.dom.Attr)node).getOwnerElement()); 503 handle = dtm.getAttributeNode(handle, node.getNamespaceURI(), node.getLocalName()); 504 } else { 505 handle = ((DOM2DTM)dtm).getHandleOfNode(node); 506 } 507 508 if (DTM.NULL == handle) { 509 throw new RuntimeException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COULD_NOT_RESOLVE_NODE, null)); //"Could not resolve the node to a handle!"); 510 } 511 512 return handle; 513 } 514 } 515 516 /** 517 * This method returns the SAX2 parser to use with the InputSource 518 * obtained from this URI. 519 * It may return null if any SAX2-conformant XML parser can be used, 520 * or if getInputSource() will also return null. The parser must 521 * be free for use (i.e., not currently in use for another parse(). 522 * After use of the parser is completed, the releaseXMLReader(XMLReader) 523 * must be called. 524 * 525 * @param inputSource The value returned from the URIResolver. 526 * @return a SAX2 XMLReader to use to resolve the inputSource argument. 527 * 528 * @return non-null XMLReader reference ready to parse. 529 */ 530 synchronized public XMLReader getXMLReader(Source inputSource) { 531 try { 532 XMLReader reader = (inputSource instanceof SAXSource) 533 ? ((SAXSource) inputSource).getXMLReader() : null; 534 535 // If user did not supply a reader, ask for one from the reader manager 536 if (null == reader) { 537 if (m_readerManager == null) { 538 m_readerManager = XMLReaderManager.getInstance(super.useServicesMechnism()); 539 } 540 541 reader = m_readerManager.getXMLReader(); 542 } 543 544 return reader; 545 } catch (SAXException se) { 546 throw new DTMException(se.getMessage(), se); 547 } 548 } 549 550 /** 551 * Indicates that the XMLReader object is no longer in use for the transform. 552 * 553 * Note that the getXMLReader method may return an XMLReader that was 554 * specified on the SAXSource object by the application code. Such a 555 * reader should still be passed to releaseXMLReader, but the reader manager 556 * will only re-use XMLReaders that it created. 557 * 558 * @param reader The XMLReader to be released. 559 */ 560 synchronized public void releaseXMLReader(XMLReader reader) { 561 if (m_readerManager != null) { 562 m_readerManager.releaseXMLReader(reader); 563 } 564 } 565 566 /** 567 * Return the DTM object containing a representation of this node. 568 * 569 * @param nodeHandle DTM Handle indicating which node to retrieve 570 * 571 * @return a reference to the DTM object containing this node. 572 */ 573 synchronized public DTM getDTM(int nodeHandle) { 574 try { 575 // Performance critical function. 576 return m_dtms[nodeHandle >>> IDENT_DTM_NODE_BITS]; 577 } catch(java.lang.ArrayIndexOutOfBoundsException e) { 578 if (nodeHandle==DTM.NULL) 579 return null; // Accept as a special case. 580 else 581 throw e; // Programming error; want to know about it. 582 } 583 } 584 585 /** 586 * Given a DTM, find the ID number in the DTM tables which addresses 587 * the start of the document. If overflow addressing is in use, other 588 * DTM IDs may also be assigned to this DTM. 589 * 590 * @param dtm The DTM which (hopefully) contains this node. 591 * 592 * @return The DTM ID (as the high bits of a NodeHandle, not as our 593 * internal index), or -1 if the DTM doesn't belong to this manager. 594 */ 595 synchronized public int getDTMIdentity(DTM dtm) { 596 // Shortcut using DTMDefaultBase's extension hooks 597 // %REVIEW% Should the lookup be part of the basic DTM API? 598 if (dtm instanceof DTMDefaultBase) { 599 DTMDefaultBase dtmdb = (DTMDefaultBase)dtm; 600 if (dtmdb.getManager() == this) 601 return dtmdb.getDTMIDs().elementAt(0); 602 else 603 return -1; 604 } 605 606 int n = m_dtms.length; 607 608 for (int i = 0; i < n; i++) { 609 DTM tdtm = m_dtms[i]; 610 611 if (tdtm == dtm && m_dtm_offsets[i]==0) 612 return i << IDENT_DTM_NODE_BITS; 613 } 614 615 return -1; 616 } 617 618 /** 619 * Release the DTMManager's reference(s) to a DTM, making it unmanaged. 620 * This is typically done as part of returning the DTM to the heap after 621 * we're done with it. 622 * 623 * @param dtm the DTM to be released. 624 * 625 * @param shouldHardDelete If false, this call is a suggestion rather than an 626 * order, and we may not actually release the DTM. This is intended to 627 * support intelligent caching of documents... which is not implemented 628 * in this version of the DTM manager. 629 * 630 * @return true if the DTM was released, false if shouldHardDelete was set 631 * and we decided not to. 632 */ 633 synchronized public boolean release(DTM dtm, boolean shouldHardDelete) { 634 /* Uncomment for debugging 635 System.out.println("Releasing "+ 636 (shouldHardDelete ? "HARD" : "soft") + 637 " dtm=" + 638 // Following shouldn't need a nodeHandle, but does... 639 // and doesn't seem to report the intended value 640 dtm.getDocumentBaseURI()); 641 */ 642 643 if (dtm instanceof SAX2DTM) { 644 ((SAX2DTM)dtm).clearCoRoutine(); 645 } 646 647 // Multiple DTM IDs may be assigned to a single DTM. 648 // The Right Answer is to ask which (if it supports 649 // extension, the DTM will need a list anyway). The 650 // Wrong Answer, applied if the DTM can't help us, 651 // is to linearly search them all; this may be very 652 // painful. 653 // 654 // %REVIEW% Should the lookup move up into the basic DTM API? 655 if (dtm instanceof DTMDefaultBase) { 656 com.sun.org.apache.xml.internal.utils.SuballocatedIntVector ids=((DTMDefaultBase)dtm).getDTMIDs(); 657 for (int i=ids.size() - 1; i >= 0; --i) { 658 m_dtms[ids.elementAt(i)>>>DTMManager.IDENT_DTM_NODE_BITS] = null; 659 } 660 } else { 661 int i = getDTMIdentity(dtm); 662 if (i >= 0) { 663 m_dtms[i >>> DTMManager.IDENT_DTM_NODE_BITS] = null; 664 } 665 } 666 667 dtm.documentRelease(); 668 return true; 669 } 670 671 /** 672 * Method createDocumentFragment 673 * 674 * 675 * NEEDSDOC (createDocumentFragment) @return 676 */ 677 synchronized public DTM createDocumentFragment() { 678 try { 679 DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(super.useServicesMechnism()); 680 dbf.setNamespaceAware(true); 681 682 DocumentBuilder db = dbf.newDocumentBuilder(); 683 Document doc = db.newDocument(); 684 Node df = doc.createDocumentFragment(); 685 686 return getDTM(new DOMSource(df), true, null, false, false); 687 } catch (Exception e) { 688 throw new DTMException(e); 689 } 690 } 691 692 /** 693 * NEEDSDOC Method createDTMIterator 694 * 695 * 696 * NEEDSDOC @param whatToShow 697 * NEEDSDOC @param filter 698 * NEEDSDOC @param entityReferenceExpansion 699 * 700 * NEEDSDOC (createDTMIterator) @return 701 */ 702 synchronized public DTMIterator createDTMIterator(int whatToShow, DTMFilter filter, 703 boolean entityReferenceExpansion) { 704 /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */ 705 return null; 706 } 707 708 /** 709 * NEEDSDOC Method createDTMIterator 710 * 711 * 712 * NEEDSDOC @param xpathString 713 * NEEDSDOC @param presolver 714 * 715 * NEEDSDOC (createDTMIterator) @return 716 */ 717 synchronized public DTMIterator createDTMIterator(String xpathString, 718 PrefixResolver presolver) { 719 /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */ 720 return null; 721 } 722 723 /** 724 * NEEDSDOC Method createDTMIterator 725 * 726 * 727 * NEEDSDOC @param node 728 * 729 * NEEDSDOC (createDTMIterator) @return 730 */ 731 synchronized public DTMIterator createDTMIterator(int node) { 732 /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */ 733 return null; 734 } 735 736 /** 737 * NEEDSDOC Method createDTMIterator 738 * 739 * 740 * NEEDSDOC @param xpathCompiler 741 * NEEDSDOC @param pos 742 * 743 * NEEDSDOC (createDTMIterator) @return 744 */ 745 synchronized public DTMIterator createDTMIterator(Object xpathCompiler, int pos) { 746 /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */ 747 return null; 748 } 749 750 /** 751 * return the expanded name table. 752 * 753 * NEEDSDOC @param dtm 754 * 755 * NEEDSDOC ($objectName$) @return 756 */ 757 public ExpandedNameTable getExpandedNameTable(DTM dtm) { 758 return m_expandedNameTable; 759 } 760 }