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