1 /* 2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * EfficientStreamingTransformer.java 28 * 29 * Created on July 29, 2002, 3:49 PM 30 */ 31 32 package com.sun.xml.internal.messaging.saaj.util.transform; 33 34 import java.io.*; 35 36 import java.net.URISyntaxException; 37 import javax.xml.transform.dom.DOMSource; 38 import javax.xml.transform.dom.DOMResult; 39 import javax.xml.transform.stream.StreamResult; 40 import javax.xml.transform.stream.StreamSource; 41 42 import org.w3c.dom.Document; 43 44 import com.sun.xml.internal.messaging.saaj.util.XMLDeclarationParser; 45 import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection; 46 import java.net.URI; 47 import javax.xml.transform.Transformer; 48 import javax.xml.transform.TransformerException; 49 import javax.xml.transform.TransformerFactory; 50 51 /** 52 * This class is a proxy for a Transformer object with optimizations 53 * for certain cases. If source and result are of type stream, then 54 * bytes are simply copied whenever possible (note that this assumes 55 * that the input is well formed). In addition, it provides support for 56 * FI using native DOM parsers and serializers. 57 * 58 * @author Panos Kougiouris panos@acm.org 59 * @author Santiago.PericasGeertsen@sun.com 60 * 61 */ 62 public class EfficientStreamingTransformer 63 extends javax.xml.transform.Transformer { 64 65 //static final String version; 66 //static final String vendor; 67 // removing static : security issue : CR 6813167Z 68 private final TransformerFactory transformerFactory = TransformerFactory.newInstance(); 69 70 /** 71 removing support for Java 1.4 and 1.3 : CR6658158 72 static { 73 version = System.getProperty("java.vm.version"); 74 vendor = System.getProperty("java.vm.vendor"); 75 if (vendor.startsWith("Sun") && 76 (version.startsWith("1.4") || version.startsWith("1.3"))) { 77 transformerFactory = 78 new com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl(); 79 } 80 }*/ 81 82 /** 83 * TransformerFactory instance. 84 */ 85 86 /** 87 * Underlying XSLT transformer. 88 */ 89 private Transformer m_realTransformer = null; 90 91 /** 92 * Undelying FI DOM parser. 93 */ 94 private Object m_fiDOMDocumentParser = null; 95 96 /** 97 * Underlying FI DOM serializer. 98 */ 99 private Object m_fiDOMDocumentSerializer = null; 100 101 private EfficientStreamingTransformer() { 102 } 103 104 private void materialize() throws TransformerException { 105 if (m_realTransformer == null) { 106 m_realTransformer = transformerFactory.newTransformer(); 107 } 108 } 109 110 @Override 111 public void clearParameters() { 112 if (m_realTransformer != null) 113 m_realTransformer.clearParameters(); 114 } 115 116 @Override 117 public javax.xml.transform.ErrorListener getErrorListener() { 118 try { 119 materialize(); 120 return m_realTransformer.getErrorListener(); 121 } catch (TransformerException e) { 122 // will be caught later 123 } 124 return null; 125 } 126 127 @Override 128 public java.util.Properties getOutputProperties() { 129 try { 130 materialize(); 131 return m_realTransformer.getOutputProperties(); 132 } catch (TransformerException e) { 133 // will be caught later 134 } 135 return null; 136 } 137 138 @Override 139 public String getOutputProperty(String str) 140 throws java.lang.IllegalArgumentException { 141 try { 142 materialize(); 143 return m_realTransformer.getOutputProperty(str); 144 } catch (TransformerException e) { 145 // will be caught later 146 } 147 return null; 148 } 149 150 @Override 151 public Object getParameter(String str) { 152 try { 153 materialize(); 154 return m_realTransformer.getParameter(str); 155 } catch (TransformerException e) { 156 // will be caught later 157 } 158 return null; 159 } 160 161 @Override 162 public javax.xml.transform.URIResolver getURIResolver() { 163 try { 164 materialize(); 165 return m_realTransformer.getURIResolver(); 166 } catch (TransformerException e) { 167 // will be caught later 168 } 169 return null; 170 } 171 172 @Override 173 public void setErrorListener( 174 javax.xml.transform.ErrorListener errorListener) 175 throws java.lang.IllegalArgumentException { 176 try { 177 materialize(); 178 m_realTransformer.setErrorListener(errorListener); 179 } catch (TransformerException e) { 180 // will be caught later 181 } 182 } 183 184 @Override 185 public void setOutputProperties(java.util.Properties properties) 186 throws java.lang.IllegalArgumentException { 187 try { 188 materialize(); 189 m_realTransformer.setOutputProperties(properties); 190 } catch (TransformerException e) { 191 // will be caught later 192 } 193 } 194 195 @Override 196 public void setOutputProperty(String str, String str1) 197 throws java.lang.IllegalArgumentException { 198 try { 199 materialize(); 200 m_realTransformer.setOutputProperty(str, str1); 201 } catch (TransformerException e) { 202 // will be caught later 203 } 204 } 205 206 @Override 207 public void setParameter(String str, Object obj) { 208 try { 209 materialize(); 210 m_realTransformer.setParameter(str, obj); 211 } catch (TransformerException e) { 212 // will be caught later 213 } 214 } 215 216 @Override 217 public void setURIResolver(javax.xml.transform.URIResolver uRIResolver) { 218 try { 219 materialize(); 220 m_realTransformer.setURIResolver(uRIResolver); 221 } catch (TransformerException e) { 222 // will be caught later 223 } 224 } 225 226 private InputStream getInputStreamFromSource(StreamSource s) 227 throws TransformerException { 228 229 InputStream stream = s.getInputStream(); 230 if (stream != null) 231 return stream; 232 233 if (s.getReader() != null) 234 return null; 235 236 String systemId = s.getSystemId(); 237 if (systemId != null) { 238 try { 239 String fileURL = systemId; 240 241 if (systemId.startsWith("file:///")) 242 { 243 /* 244 systemId is: 245 file:///<drive>:/some/path/file.xml 246 or 247 file:///some/path/file.xml 248 */ 249 250 String absolutePath = systemId.substring(7); 251 /* 252 /<drive>:/some/path/file.xml 253 or 254 /some/path/file.xml 255 */ 256 257 boolean hasDriveDesignator = absolutePath.indexOf(":") > 0; 258 if (hasDriveDesignator) { 259 String driveDesignatedPath = absolutePath.substring(1); 260 /* 261 <drive>:/some/path/file.xml */ 262 fileURL = driveDesignatedPath; 263 } 264 else { 265 /* 266 /some/path/file.xml */ 267 fileURL = absolutePath; 268 } 269 } 270 //return new FileInputStream(fileURL); 271 try { 272 return new FileInputStream(new File(new URI(fileURL))); 273 } catch (URISyntaxException ex) { 274 throw new TransformerException(ex); 275 } 276 } catch (IOException e) { 277 throw new TransformerException(e.toString()); 278 } 279 } 280 281 throw new TransformerException("Unexpected StreamSource object"); 282 } 283 284 //------------------------------------------------------------------------ 285 286 @Override 287 public void transform( 288 javax.xml.transform.Source source, 289 javax.xml.transform.Result result) 290 throws javax.xml.transform.TransformerException 291 { 292 // StreamSource -> StreamResult 293 if ((source instanceof StreamSource) 294 && (result instanceof StreamResult)) { 295 try { 296 StreamSource streamSource = (StreamSource) source; 297 InputStream is = getInputStreamFromSource(streamSource); 298 299 OutputStream os = ((StreamResult) result).getOutputStream(); 300 if (os == null) 301 // TODO: We might want to fix this if it were to be used beyond 302 // XmlDataContentHandler that we know uses only OutputStream 303 throw new TransformerException("Unexpected StreamResult object contains null OutputStream"); 304 305 if (is != null) { 306 if (is.markSupported()) 307 is.mark(Integer.MAX_VALUE); 308 int num; 309 byte[] b = new byte[8192]; 310 while ((num = is.read(b)) != -1) { 311 os.write(b, 0, num); 312 } 313 if (is.markSupported()) 314 is.reset(); 315 return; 316 } 317 318 Reader reader = streamSource.getReader(); 319 if (reader != null) { 320 321 if (reader.markSupported()) 322 reader.mark(Integer.MAX_VALUE); 323 324 PushbackReader pushbackReader = new PushbackReader(reader, 4096); 325 //some size to unread <?xml ....?> 326 XMLDeclarationParser ev = 327 new XMLDeclarationParser(pushbackReader); 328 try { 329 ev.parse(); 330 } catch (Exception ex) { 331 throw new TransformerException( 332 "Unable to run the JAXP transformer on a stream " 333 + ex.getMessage()); 334 } 335 Writer writer = 336 new OutputStreamWriter(os /*, ev.getEncoding()*/); 337 ev.writeTo(writer); // doesn't write any, if no header 338 339 int num; 340 char[] ac = new char[8192]; 341 while ((num = pushbackReader.read(ac)) != -1) { 342 writer.write(ac, 0, num); 343 } 344 writer.flush(); 345 346 if (reader.markSupported()) 347 reader.reset(); 348 return; 349 } 350 } catch (IOException e) { 351 e.printStackTrace(); 352 throw new TransformerException(e.toString()); 353 } 354 355 throw new TransformerException("Unexpected StreamSource object"); 356 } 357 // FastInfosetSource -> DOMResult 358 else if (FastInfosetReflection.isFastInfosetSource(source) 359 && (result instanceof DOMResult)) 360 { 361 try { 362 // Use reflection to avoid a static dep with FI 363 if (m_fiDOMDocumentParser == null) { 364 m_fiDOMDocumentParser = FastInfosetReflection.DOMDocumentParser_new(); 365 } 366 367 // m_fiDOMDocumentParser.parse(document, source.getInputStream()) 368 FastInfosetReflection.DOMDocumentParser_parse( 369 m_fiDOMDocumentParser, 370 (Document) ((DOMResult) result).getNode(), 371 FastInfosetReflection.FastInfosetSource_getInputStream(source)); 372 373 // We're done! 374 return; 375 } 376 catch (Exception e) { 377 throw new TransformerException(e); 378 } 379 } 380 // DOMSource -> FastInfosetResult 381 else if ((source instanceof DOMSource) 382 && FastInfosetReflection.isFastInfosetResult(result)) 383 { 384 try { 385 // Use reflection to avoid a static dep with FI 386 if (m_fiDOMDocumentSerializer == null) { 387 m_fiDOMDocumentSerializer = FastInfosetReflection.DOMDocumentSerializer_new(); 388 } 389 390 // m_fiDOMDocumentSerializer.setOutputStream(result.getOutputStream()) 391 FastInfosetReflection.DOMDocumentSerializer_setOutputStream( 392 m_fiDOMDocumentSerializer, 393 FastInfosetReflection.FastInfosetResult_getOutputStream(result)); 394 395 // m_fiDOMDocumentSerializer.serialize(node) 396 FastInfosetReflection.DOMDocumentSerializer_serialize( 397 m_fiDOMDocumentSerializer, 398 ((DOMSource) source).getNode()); 399 400 // We're done! 401 return; 402 } 403 catch (Exception e) { 404 throw new TransformerException(e); 405 } 406 } 407 408 // All other cases -- use transformer object 409 410 materialize(); 411 m_realTransformer.transform(source, result); 412 } 413 414 /** 415 * Threadlocal to hold a Transformer instance for this thread. 416 * CR : 6813167 417 */ 418 //private static ThreadLocal effTransformer = new ThreadLocal(); 419 420 /** 421 * Return Transformer instance for this thread, allocating a new one if 422 * necessary. Note that this method does not clear global parameters, 423 * properties or any other data set on a previously used transformer. 424 * 425 * @return Transformer instance 426 */ 427 public static Transformer newTransformer() { 428 //CR : 6813167 429 /*Transformer tt = (Transformer) effTransformer.get(); 430 if (tt == null) { 431 effTransformer.set(tt = new EfficientStreamingTransformer()); 432 } 433 return tt;*/ 434 return new EfficientStreamingTransformer(); 435 } 436 437 }