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