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