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