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