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