blob: 0ba44cffd1a8ed857bca5968f27f12312ae9ba03 [file] [log] [blame]
Aurimas Liutikasdc3f8852024-07-11 10:07:48 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: SourceTreeManager.java 468655 2006-10-28 07:12:06Z minchau $
20 */
21package org.apache.xpath;
22
23import java.io.IOException;
24import java.util.Vector;
25
26import javax.xml.transform.Source;
27import javax.xml.transform.SourceLocator;
28import javax.xml.transform.TransformerException;
29import javax.xml.transform.URIResolver;
30import javax.xml.transform.sax.SAXSource;
31import javax.xml.transform.stream.StreamSource;
32
33import org.apache.xml.dtm.DTM;
34import org.apache.xml.utils.SystemIDResolver;
35
36import org.xml.sax.XMLReader;
37import org.xml.sax.helpers.XMLReaderFactory;
38
39/**
40 * This class bottlenecks all management of source trees. The methods
41 * in this class should allow easy garbage collection of source
42 * trees (not yet!), and should centralize parsing for those source trees.
43 */
44public class SourceTreeManager
45{
46
47 /** Vector of SourceTree objects that this manager manages. */
48 private Vector m_sourceTree = new Vector();
49
50 /**
51 * Reset the list of SourceTree objects that this manager manages.
52 *
53 */
54 public void reset()
55 {
56 m_sourceTree = new Vector();
57 }
58
59 /** The TrAX URI resolver used to obtain source trees. */
60 URIResolver m_uriResolver;
61
62 /**
63 * Set an object that will be used to resolve URIs used in
64 * document(), etc.
65 * @param resolver An object that implements the URIResolver interface,
66 * or null.
67 */
68 public void setURIResolver(URIResolver resolver)
69 {
70 m_uriResolver = resolver;
71 }
72
73 /**
74 * Get the object that will be used to resolve URIs used in
75 * document(), etc.
76 * @return An object that implements the URIResolver interface,
77 * or null.
78 */
79 public URIResolver getURIResolver()
80 {
81 return m_uriResolver;
82 }
83
84 /**
85 * Given a document, find the URL associated with that document.
86 * @param owner Document that was previously processed by this liaison.
87 *
88 * @return The base URI of the owner argument.
89 */
90 public String findURIFromDoc(int owner)
91 {
92 int n = m_sourceTree.size();
93
94 for (int i = 0; i < n; i++)
95 {
96 SourceTree sTree = (SourceTree) m_sourceTree.elementAt(i);
97
98 if (owner == sTree.m_root)
99 return sTree.m_url;
100 }
101
102 return null;
103 }
104
105 /**
106 * This will be called by the processor when it encounters
107 * an xsl:include, xsl:import, or document() function.
108 *
109 * @param base The base URI that should be used.
110 * @param urlString Value from an xsl:import or xsl:include's href attribute,
111 * or a URI specified in the document() function.
112 *
113 * @return a Source that can be used to process the resource.
114 *
115 * @throws IOException
116 * @throws TransformerException
117 */
118 public Source resolveURI(
119 String base, String urlString, SourceLocator locator)
120 throws TransformerException, IOException
121 {
122
123 Source source = null;
124
125 if (null != m_uriResolver)
126 {
127 source = m_uriResolver.resolve(urlString, base);
128 }
129
130 if (null == source)
131 {
132 String uri = SystemIDResolver.getAbsoluteURI(urlString, base);
133
134 source = new StreamSource(uri);
135 }
136
137 return source;
138 }
139
140 /** JJK: Support <?xalan:doc_cache_off?> kluge in ElemForEach.
141 * TODO: This function is highly dangerous. Cache management must be improved.
142 *
143 * @param n The node to remove.
144 */
145 public void removeDocumentFromCache(int n)
146 {
147 if(DTM.NULL ==n)
148 return;
149 for(int i=m_sourceTree.size()-1;i>=0;--i)
150 {
151 SourceTree st=(SourceTree)m_sourceTree.elementAt(i);
152 if(st!=null && st.m_root==n)
153 {
154 m_sourceTree.removeElementAt(i);
155 return;
156 }
157 }
158 }
159
160
161
162 /**
163 * Put the source tree root node in the document cache.
164 * TODO: This function needs to be a LOT more sophisticated.
165 *
166 * @param n The node to cache.
167 * @param source The Source object to cache.
168 */
169 public void putDocumentInCache(int n, Source source)
170 {
171
172 int cachedNode = getNode(source);
173
174 if (DTM.NULL != cachedNode)
175 {
176 if (!(cachedNode == n))
177 throw new RuntimeException(
178 "Programmer's Error! "
179 + "putDocumentInCache found reparse of doc: "
180 + source.getSystemId());
181 return;
182 }
183 if (null != source.getSystemId())
184 {
185 m_sourceTree.addElement(new SourceTree(n, source.getSystemId()));
186 }
187 }
188
189 /**
190 * Given a Source object, find the node associated with it.
191 *
192 * @param source The Source object to act as the key.
193 *
194 * @return The node that is associated with the Source, or null if not found.
195 */
196 public int getNode(Source source)
197 {
198
199// if (source instanceof DOMSource)
200// return ((DOMSource) source).getNode();
201
202 // TODO: Not sure if the BaseID is really the same thing as the ID.
203 String url = source.getSystemId();
204
205 if (null == url)
206 return DTM.NULL;
207
208 int n = m_sourceTree.size();
209
210 // System.out.println("getNode: "+n);
211 for (int i = 0; i < n; i++)
212 {
213 SourceTree sTree = (SourceTree) m_sourceTree.elementAt(i);
214
215 // System.out.println("getNode - url: "+url);
216 // System.out.println("getNode - sTree.m_url: "+sTree.m_url);
217 if (url.equals(sTree.m_url))
218 return sTree.m_root;
219 }
220
221 // System.out.println("getNode - returning: "+node);
222 return DTM.NULL;
223 }
224
225 /**
226 * Get the source tree from the a base URL and a URL string.
227 *
228 * @param base The base URI to use if the urlString is relative.
229 * @param urlString An absolute or relative URL string.
230 * @param locator The location of the caller, for diagnostic purposes.
231 *
232 * @return should be a non-null reference to the node identified by the
233 * base and urlString.
234 *
235 * @throws TransformerException If the URL can not resolve to a node.
236 */
237 public int getSourceTree(
238 String base, String urlString, SourceLocator locator, XPathContext xctxt)
239 throws TransformerException
240 {
241
242 // System.out.println("getSourceTree");
243 try
244 {
245 Source source = this.resolveURI(base, urlString, locator);
246
247 // System.out.println("getSourceTree - base: "+base+", urlString: "+urlString+", source: "+source.getSystemId());
248 return getSourceTree(source, locator, xctxt);
249 }
250 catch (IOException ioe)
251 {
252 throw new TransformerException(ioe.getMessage(), locator, ioe);
253 }
254
255 /* catch (TransformerException te)
256 {
257 throw new TransformerException(te.getMessage(), locator, te);
258 }*/
259 }
260
261 /**
262 * Get the source tree from the input source.
263 *
264 * @param source The Source object that should identify the desired node.
265 * @param locator The location of the caller, for diagnostic purposes.
266 *
267 * @return non-null reference to a node.
268 *
269 * @throws TransformerException if the Source argument can't be resolved to
270 * a node.
271 */
272 public int getSourceTree(Source source, SourceLocator locator, XPathContext xctxt)
273 throws TransformerException
274 {
275
276 int n = getNode(source);
277
278 if (DTM.NULL != n)
279 return n;
280
281 n = parseToNode(source, locator, xctxt);
282
283 if (DTM.NULL != n)
284 putDocumentInCache(n, source);
285
286 return n;
287 }
288
289 /**
290 * Try to create a DOM source tree from the input source.
291 *
292 * @param source The Source object that identifies the source node.
293 * @param locator The location of the caller, for diagnostic purposes.
294 *
295 * @return non-null reference to node identified by the source argument.
296 *
297 * @throws TransformerException if the source argument can not be resolved
298 * to a source node.
299 */
300 public int parseToNode(Source source, SourceLocator locator, XPathContext xctxt)
301 throws TransformerException
302 {
303
304 try
305 {
306 Object xowner = xctxt.getOwnerObject();
307 DTM dtm;
308 if(null != xowner && xowner instanceof org.apache.xml.dtm.DTMWSFilter)
309 {
310 dtm = xctxt.getDTM(source, false,
311 (org.apache.xml.dtm.DTMWSFilter)xowner, false, true);
312 }
313 else
314 {
315 dtm = xctxt.getDTM(source, false, null, false, true);
316 }
317 return dtm.getDocument();
318 }
319 catch (Exception e)
320 {
321 //e.printStackTrace();
322 throw new TransformerException(e.getMessage(), locator, e);
323 }
324
325 }
326
327 /**
328 * This method returns the SAX2 parser to use with the InputSource
329 * obtained from this URI.
330 * It may return null if any SAX2-conformant XML parser can be used,
331 * or if getInputSource() will also return null. The parser must
332 * be free for use (i.e.
333 * not currently in use for another parse().
334 *
335 * @param inputSource The value returned from the URIResolver.
336 * @return a SAX2 XMLReader to use to resolve the inputSource argument.
337 * @param locator The location of the original caller, for diagnostic purposes.
338 *
339 * @throws TransformerException if the reader can not be created.
340 */
341 public static XMLReader getXMLReader(Source inputSource, SourceLocator locator)
342 throws TransformerException
343 {
344
345 try
346 {
347 XMLReader reader = (inputSource instanceof SAXSource)
348 ? ((SAXSource) inputSource).getXMLReader() : null;
349
350 if (null == reader)
351 {
352 try {
353 javax.xml.parsers.SAXParserFactory factory=
354 javax.xml.parsers.SAXParserFactory.newInstance();
355 factory.setNamespaceAware( true );
356 javax.xml.parsers.SAXParser jaxpParser=
357 factory.newSAXParser();
358 reader=jaxpParser.getXMLReader();
359
360 } catch( javax.xml.parsers.ParserConfigurationException ex ) {
361 throw new org.xml.sax.SAXException( ex );
362 } catch( javax.xml.parsers.FactoryConfigurationError ex1 ) {
363 throw new org.xml.sax.SAXException( ex1.toString() );
364 } catch( NoSuchMethodError ex2 ) {
365 }
366 catch (AbstractMethodError ame){}
367 if(null == reader)
368 reader = XMLReaderFactory.createXMLReader();
369 }
370
371 try
372 {
373 reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
374 true);
375 }
376 catch (org.xml.sax.SAXException se)
377 {
378
379 // What can we do?
380 // TODO: User diagnostics.
381 }
382
383 return reader;
384 }
385 catch (org.xml.sax.SAXException se)
386 {
387 throw new TransformerException(se.getMessage(), locator, se);
388 }
389 }
390}