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.xpath;
  58. import java.net.MalformedURLException;
  59. import java.io.File;
  60. import java.io.IOException;
  61. import java.util.StringTokenizer;
  62. import java.util.Vector;
  63. import org.apache.xpath.objects.XString;
  64. //import org.w3c.dom.Node;
  65. //import org.w3c.dom.Document;
  66. import org.apache.xml.dtm.DTM;
  67. import javax.xml.transform.URIResolver;
  68. import javax.xml.transform.TransformerException;
  69. import org.xml.sax.InputSource;
  70. import org.xml.sax.helpers.XMLReaderFactory;
  71. import org.xml.sax.XMLReader;
  72. import org.xml.sax.ContentHandler;
  73. import org.xml.sax.EntityResolver;
  74. // import org.xml.sax.Locator;
  75. import org.apache.xalan.res.XSLMessages;
  76. import org.apache.xml.utils.SystemIDResolver;
  77. import org.apache.xml.utils.SAXSourceLocator;
  78. import org.apache.xpath.res.XPATHErrorResources;
  79. import javax.xml.transform.SourceLocator;
  80. import javax.xml.transform.Source;
  81. import javax.xml.transform.sax.SAXSource;
  82. import javax.xml.transform.dom.DOMSource;
  83. import javax.xml.transform.stream.StreamSource;
  84. import javax.xml.transform.TransformerException;
  85. /**
  86. * This class bottlenecks all management of source trees. The methods
  87. * in this class should allow easy garbage collection of source
  88. * trees (not yet!), and should centralize parsing for those source trees.
  89. */
  90. public class SourceTreeManager
  91. {
  92. /** Vector of SourceTree objects that this manager manages. */
  93. private Vector m_sourceTree = new Vector();
  94. /**
  95. * Reset the list of SourceTree objects that this manager manages.
  96. *
  97. */
  98. public void reset()
  99. {
  100. m_sourceTree = new Vector();
  101. }
  102. /** The TrAX URI resolver used to obtain source trees. */
  103. URIResolver m_uriResolver;
  104. /**
  105. * Set an object that will be used to resolve URIs used in
  106. * document(), etc.
  107. * @param resolver An object that implements the URIResolver interface,
  108. * or null.
  109. */
  110. public void setURIResolver(URIResolver resolver)
  111. {
  112. m_uriResolver = resolver;
  113. }
  114. /**
  115. * Get the object that will be used to resolve URIs used in
  116. * document(), etc.
  117. * @return An object that implements the URIResolver interface,
  118. * or null.
  119. */
  120. public URIResolver getURIResolver()
  121. {
  122. return m_uriResolver;
  123. }
  124. /**
  125. * Given a document, find the URL associated with that document.
  126. * @param owner Document that was previously processed by this liaison.
  127. *
  128. * @return The base URI of the owner argument.
  129. */
  130. public String findURIFromDoc(int owner)
  131. {
  132. int n = m_sourceTree.size();
  133. for (int i = 0; i < n; i++)
  134. {
  135. SourceTree sTree = (SourceTree) m_sourceTree.elementAt(i);
  136. if (owner == sTree.m_root)
  137. return sTree.m_url;
  138. }
  139. return null;
  140. }
  141. /**
  142. * This will be called by the processor when it encounters
  143. * an xsl:include, xsl:import, or document() function.
  144. *
  145. * @param base The base URI that should be used.
  146. * @param urlString Value from an xsl:import or xsl:include's href attribute,
  147. * or a URI specified in the document() function.
  148. *
  149. * @return a Source that can be used to process the resource.
  150. *
  151. * @throws IOException
  152. * @throws TransformerException
  153. */
  154. public Source resolveURI(
  155. String base, String urlString, SourceLocator locator)
  156. throws TransformerException, IOException
  157. {
  158. Source source = null;
  159. if (null != m_uriResolver)
  160. {
  161. source = m_uriResolver.resolve(urlString, base);
  162. }
  163. if (null == source)
  164. {
  165. String uri = SystemIDResolver.getAbsoluteURI(urlString, base);
  166. source = new StreamSource(uri);
  167. }
  168. return source;
  169. }
  170. /** JJK: Support <?xalan:doc_cache_off?> kluge in ElemForEach.
  171. * TODO: This function is highly dangerous. Cache management must be improved.
  172. *
  173. * @param n The node to remove.
  174. */
  175. public void removeDocumentFromCache(int n)
  176. {
  177. if(DTM.NULL ==n)
  178. return;
  179. for(int i=m_sourceTree.size()-1;i>=0;--i)
  180. {
  181. SourceTree st=(SourceTree)m_sourceTree.elementAt(i);
  182. if(st!=null && st.m_root==n)
  183. {
  184. m_sourceTree.removeElementAt(i);
  185. return;
  186. }
  187. }
  188. }
  189. /**
  190. * Put the source tree root node in the document cache.
  191. * TODO: This function needs to be a LOT more sophisticated.
  192. *
  193. * @param n The node to cache.
  194. * @param source The Source object to cache.
  195. */
  196. public void putDocumentInCache(int n, Source source)
  197. {
  198. int cachedNode = getNode(source);
  199. if (DTM.NULL != cachedNode)
  200. {
  201. if (!(cachedNode == n))
  202. throw new RuntimeException(
  203. "Programmer's Error! "
  204. + "putDocumentInCache found reparse of doc: "
  205. + source.getSystemId());
  206. return;
  207. }
  208. if (null != source.getSystemId())
  209. {
  210. m_sourceTree.addElement(new SourceTree(n, source.getSystemId()));
  211. }
  212. }
  213. /**
  214. * Given a Source object, find the node associated with it.
  215. *
  216. * @param source The Source object to act as the key.
  217. *
  218. * @return The node that is associated with the Source, or null if not found.
  219. */
  220. public int getNode(Source source)
  221. {
  222. // if (source instanceof DOMSource)
  223. // return ((DOMSource) source).getNode();
  224. // TODO: Not sure if the BaseID is really the same thing as the ID.
  225. String url = source.getSystemId();
  226. if (null == url)
  227. return DTM.NULL;
  228. int n = m_sourceTree.size();
  229. // System.out.println("getNode: "+n);
  230. for (int i = 0; i < n; i++)
  231. {
  232. SourceTree sTree = (SourceTree) m_sourceTree.elementAt(i);
  233. // System.out.println("getNode - url: "+url);
  234. // System.out.println("getNode - sTree.m_url: "+sTree.m_url);
  235. if (url.equals(sTree.m_url))
  236. return sTree.m_root;
  237. }
  238. // System.out.println("getNode - returning: "+node);
  239. return DTM.NULL;
  240. }
  241. /**
  242. * Get the source tree from the a base URL and a URL string.
  243. *
  244. * @param base The base URI to use if the urlString is relative.
  245. * @param urlString An absolute or relative URL string.
  246. * @param locator The location of the caller, for diagnostic purposes.
  247. *
  248. * @return should be a non-null reference to the node identified by the
  249. * base and urlString.
  250. *
  251. * @throws TransformerException If the URL can not resolve to a node.
  252. */
  253. public int getSourceTree(
  254. String base, String urlString, SourceLocator locator, XPathContext xctxt)
  255. throws TransformerException
  256. {
  257. // System.out.println("getSourceTree");
  258. try
  259. {
  260. Source source = this.resolveURI(base, urlString, locator);
  261. // System.out.println("getSourceTree - base: "+base+", urlString: "+urlString+", source: "+source.getSystemId());
  262. return getSourceTree(source, locator, xctxt);
  263. }
  264. catch (IOException ioe)
  265. {
  266. throw new TransformerException(ioe.getMessage(), locator, ioe);
  267. }
  268. /* catch (TransformerException te)
  269. {
  270. throw new TransformerException(te.getMessage(), locator, te);
  271. }*/
  272. }
  273. /**
  274. * Get the source tree from the input source.
  275. *
  276. * @param source The Source object that should identify the desired node.
  277. * @param locator The location of the caller, for diagnostic purposes.
  278. *
  279. * @return non-null reference to a node.
  280. *
  281. * @throws TransformerException if the Source argument can't be resolved to
  282. * a node.
  283. */
  284. public int getSourceTree(Source source, SourceLocator locator, XPathContext xctxt)
  285. throws TransformerException
  286. {
  287. int n = getNode(source);
  288. if (DTM.NULL != n)
  289. return n;
  290. n = parseToNode(source, locator, xctxt);
  291. if (DTM.NULL != n)
  292. putDocumentInCache(n, source);
  293. return n;
  294. }
  295. /**
  296. * Try to create a DOM source tree from the input source.
  297. *
  298. * @param source The Source object that identifies the source node.
  299. * @param locator The location of the caller, for diagnostic purposes.
  300. *
  301. * @return non-null reference to node identified by the source argument.
  302. *
  303. * @throws TransformerException if the source argument can not be resolved
  304. * to a source node.
  305. */
  306. public int parseToNode(Source source, SourceLocator locator, XPathContext xctxt)
  307. throws TransformerException
  308. {
  309. try
  310. {
  311. Object xowner = xctxt.getOwnerObject();
  312. DTM dtm;
  313. if(null != xowner && xowner instanceof org.apache.xml.dtm.DTMWSFilter)
  314. {
  315. dtm = xctxt.getDTM(source, false,
  316. (org.apache.xml.dtm.DTMWSFilter)xowner, false, true);
  317. }
  318. else
  319. {
  320. dtm = xctxt.getDTM(source, false, null, false, true);
  321. }
  322. return dtm.getDocument();
  323. }
  324. catch (Exception e)
  325. {
  326. //e.printStackTrace();
  327. throw new TransformerException(e.getMessage(), locator, e);
  328. }
  329. }
  330. /**
  331. * This method returns the SAX2 parser to use with the InputSource
  332. * obtained from this URI.
  333. * It may return null if any SAX2-conformant XML parser can be used,
  334. * or if getInputSource() will also return null. The parser must
  335. * be free for use (i.e.
  336. * not currently in use for another parse().
  337. *
  338. * @param inputSource The value returned from the URIResolver.
  339. * @returns a SAX2 XMLReader to use to resolve the inputSource argument.
  340. * @param locator The location of the original caller, for diagnostic purposes.
  341. *
  342. * @return non-null XMLReader reference ready to parse.
  343. *
  344. * @throws TransformerException if the reader can not be created.
  345. */
  346. public static XMLReader getXMLReader(Source inputSource, SourceLocator locator)
  347. throws TransformerException
  348. {
  349. try
  350. {
  351. XMLReader reader = (inputSource instanceof SAXSource)
  352. ? ((SAXSource) inputSource).getXMLReader() : null;
  353. boolean isUserReader = (reader != null);
  354. if (null == reader)
  355. {
  356. try {
  357. javax.xml.parsers.SAXParserFactory factory=
  358. javax.xml.parsers.SAXParserFactory.newInstance();
  359. factory.setNamespaceAware( true );
  360. javax.xml.parsers.SAXParser jaxpParser=
  361. factory.newSAXParser();
  362. reader=jaxpParser.getXMLReader();
  363. } catch( javax.xml.parsers.ParserConfigurationException ex ) {
  364. throw new org.xml.sax.SAXException( ex );
  365. } catch( javax.xml.parsers.FactoryConfigurationError ex1 ) {
  366. throw new org.xml.sax.SAXException( ex1.toString() );
  367. } catch( NoSuchMethodError ex2 ) {
  368. }
  369. catch (AbstractMethodError ame){}
  370. if(null == reader)
  371. reader = XMLReaderFactory.createXMLReader();
  372. }
  373. try
  374. {
  375. reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
  376. true);
  377. // Commented out as per discussion with Thomas2.Maesing@bgs-ag.de
  378. // about bug 2124.
  379. // if(!isUserReader)
  380. // reader.setFeature("http://apache.org/xml/features/validation/dynamic",
  381. // true);
  382. }
  383. catch (org.xml.sax.SAXException se)
  384. {
  385. // What can we do?
  386. // TODO: User diagnostics.
  387. }
  388. return reader;
  389. }
  390. catch (org.xml.sax.SAXException se)
  391. {
  392. throw new TransformerException(se.getMessage(), locator, se);
  393. }
  394. }
  395. }