1 /* 2 * Copyright (c) 1997, 2013, 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 public void clearParameters() { 111 if (m_realTransformer != null) 112 m_realTransformer.clearParameters(); 113 } 114 115 public javax.xml.transform.ErrorListener getErrorListener() { 116 try { 117 materialize(); 118 return m_realTransformer.getErrorListener(); 119 } catch (TransformerException e) { 120 // will be caught later 121 } 122 return null; 123 } 124 125 public java.util.Properties getOutputProperties() { 126 try { 127 materialize(); 128 return m_realTransformer.getOutputProperties(); 129 } catch (TransformerException e) { 130 // will be caught later 131 } 132 return null; 133 } 134 135 public String getOutputProperty(String str) 136 throws java.lang.IllegalArgumentException { 137 try { 138 materialize(); 139 return m_realTransformer.getOutputProperty(str); 140 } catch (TransformerException e) { 141 // will be caught later 142 } 143 return null; 144 } 145 146 public Object getParameter(String str) { 147 try { 148 materialize(); 149 return m_realTransformer.getParameter(str); 150 } catch (TransformerException e) { 151 // will be caught later 152 } 153 return null; 154 } 155 156 public javax.xml.transform.URIResolver getURIResolver() { 157 try { 158 materialize(); 159 return m_realTransformer.getURIResolver(); 160 } catch (TransformerException e) { 161 // will be caught later 162 } 163 return null; 164 } 165 166 public void setErrorListener( 167 javax.xml.transform.ErrorListener errorListener) 168 throws java.lang.IllegalArgumentException { 169 try { 170 materialize(); 171 m_realTransformer.setErrorListener(errorListener); 172 } catch (TransformerException e) { 173 // will be caught later 174 } 175 } 176 177 public void setOutputProperties(java.util.Properties properties) 178 throws java.lang.IllegalArgumentException { 179 try { 180 materialize(); 181 m_realTransformer.setOutputProperties(properties); 182 } catch (TransformerException e) { 183 // will be caught later 184 } 185 } 186 187 public void setOutputProperty(String str, String str1) 188 throws java.lang.IllegalArgumentException { 189 try { 190 materialize(); 191 m_realTransformer.setOutputProperty(str, str1); 192 } catch (TransformerException e) { 193 // will be caught later 194 } 195 } 196 197 public void setParameter(String str, Object obj) { 198 try { 199 materialize(); 200 m_realTransformer.setParameter(str, obj); 201 } catch (TransformerException e) { 202 // will be caught later 203 } 204 } 205 206 public void setURIResolver(javax.xml.transform.URIResolver uRIResolver) { 207 try { 208 materialize(); 209 m_realTransformer.setURIResolver(uRIResolver); 210 } catch (TransformerException e) { 211 // will be caught later 212 } 213 } 214 215 private InputStream getInputStreamFromSource(StreamSource s) 216 throws TransformerException { 217 218 InputStream stream = s.getInputStream(); 219 if (stream != null) 220 return stream; 221 222 if (s.getReader() != null) 223 return null; 224 225 String systemId = s.getSystemId(); 226 if (systemId != null) { 227 try { 228 String fileURL = systemId; 229 230 if (systemId.startsWith("file:///")) 231 { 232 /* 233 systemId is: 234 file:///<drive>:/some/path/file.xml 235 or 236 file:///some/path/file.xml 237 */ 238 239 String absolutePath = systemId.substring(7); 240 /* 241 /<drive>:/some/path/file.xml 242 or 243 /some/path/file.xml 244 */ 245 246 boolean hasDriveDesignator = absolutePath.indexOf(":") > 0; 247 if (hasDriveDesignator) { 248 String driveDesignatedPath = absolutePath.substring(1); 249 /* 250 <drive>:/some/path/file.xml */ 251 fileURL = driveDesignatedPath; 252 } 253 else { 254 /* 255 /some/path/file.xml */ 256 fileURL = absolutePath; 257 } 258 } 259 //return new FileInputStream(fileURL); 260 try { 261 return new FileInputStream(new File(new URI(fileURL))); 262 } catch (URISyntaxException ex) { 263 throw new TransformerException(ex); 264 } 265 } catch (IOException e) { 266 throw new TransformerException(e.toString()); 267 } 268 } 269 270 throw new TransformerException("Unexpected StreamSource object"); 271 } 272 273 //------------------------------------------------------------------------ 274 275 public void transform( 276 javax.xml.transform.Source source, 277 javax.xml.transform.Result result) 278 throws javax.xml.transform.TransformerException 279 { 280 // StreamSource -> StreamResult 281 if ((source instanceof StreamSource) 282 && (result instanceof StreamResult)) { 283 try { 284 StreamSource streamSource = (StreamSource) source; 285 InputStream is = getInputStreamFromSource(streamSource); 286 287 OutputStream os = ((StreamResult) result).getOutputStream(); 288 if (os == null) 289 // TODO: We might want to fix this if it were to be used beyond 290 // XmlDataContentHandler that we know uses only OutputStream 291 throw new TransformerException("Unexpected StreamResult object contains null OutputStream"); 292 293 if (is != null) { 294 if (is.markSupported()) 295 is.mark(Integer.MAX_VALUE); 296 int num; 297 byte[] b = new byte[8192]; 298 while ((num = is.read(b)) != -1) { 299 os.write(b, 0, num); 300 } 301 if (is.markSupported()) 302 is.reset(); 303 return; 304 } 305 306 Reader reader = streamSource.getReader(); 307 if (reader != null) { 308 309 if (reader.markSupported()) 310 reader.mark(Integer.MAX_VALUE); 311 312 PushbackReader pushbackReader = new PushbackReader(reader, 4096); 313 //some size to unread <?xml ....?> 314 XMLDeclarationParser ev = 315 new XMLDeclarationParser(pushbackReader); 316 try { 317 ev.parse(); 318 } catch (Exception ex) { 319 throw new TransformerException( 320 "Unable to run the JAXP transformer on a stream " 321 + ex.getMessage()); 322 } 323 Writer writer = 324 new OutputStreamWriter(os /*, ev.getEncoding()*/); 325 ev.writeTo(writer); // doesn't write any, if no header 326 327 int num; 328 char[] ac = new char[8192]; 329 while ((num = pushbackReader.read(ac)) != -1) { 330 writer.write(ac, 0, num); 331 } 332 writer.flush(); 333 334 if (reader.markSupported()) 335 reader.reset(); 336 return; 337 } 338 } catch (IOException e) { 339 e.printStackTrace(); 340 throw new TransformerException(e.toString()); 341 } 342 343 throw new TransformerException("Unexpected StreamSource object"); 344 } 345 // FastInfosetSource -> DOMResult 346 else if (FastInfosetReflection.isFastInfosetSource(source) 347 && (result instanceof DOMResult)) 348 { 349 try { 350 // Use reflection to avoid a static dep with FI 351 if (m_fiDOMDocumentParser == null) { 352 m_fiDOMDocumentParser = FastInfosetReflection.DOMDocumentParser_new(); 353 } 354 355 // m_fiDOMDocumentParser.parse(document, source.getInputStream()) 356 FastInfosetReflection.DOMDocumentParser_parse( 357 m_fiDOMDocumentParser, 358 (Document) ((DOMResult) result).getNode(), 359 FastInfosetReflection.FastInfosetSource_getInputStream(source)); 360 361 // We're done! 362 return; 363 } 364 catch (Exception e) { 365 throw new TransformerException(e); 366 } 367 } 368 // DOMSource -> FastInfosetResult 369 else if ((source instanceof DOMSource) 370 && FastInfosetReflection.isFastInfosetResult(result)) 371 { 372 try { 373 // Use reflection to avoid a static dep with FI 374 if (m_fiDOMDocumentSerializer == null) { 375 m_fiDOMDocumentSerializer = FastInfosetReflection.DOMDocumentSerializer_new(); 376 } 377 378 // m_fiDOMDocumentSerializer.setOutputStream(result.getOutputStream()) 379 FastInfosetReflection.DOMDocumentSerializer_setOutputStream( 380 m_fiDOMDocumentSerializer, 381 FastInfosetReflection.FastInfosetResult_getOutputStream(result)); 382 383 // m_fiDOMDocumentSerializer.serialize(node) 384 FastInfosetReflection.DOMDocumentSerializer_serialize( 385 m_fiDOMDocumentSerializer, 386 ((DOMSource) source).getNode()); 387 388 // We're done! 389 return; 390 } 391 catch (Exception e) { 392 throw new TransformerException(e); 393 } 394 } 395 396 // All other cases -- use transformer object 397 398 materialize(); 399 m_realTransformer.transform(source, result); 400 } 401 402 /** 403 * Threadlocal to hold a Transformer instance for this thread. 404 * CR : 6813167 405 */ 406 //private static ThreadLocal effTransformer = new ThreadLocal(); 407 408 /** 409 * Return Transformer instance for this thread, allocating a new one if 410 * necessary. Note that this method does not clear global parameters, 411 * properties or any other data set on a previously used transformer. 412 */ 413 public static Transformer newTransformer() { 414 //CR : 6813167 415 /*Transformer tt = (Transformer) effTransformer.get(); 416 if (tt == null) { 417 effTransformer.set(tt = new EfficientStreamingTransformer()); 418 } 419 return tt;*/ 420 return new EfficientStreamingTransformer(); 421 } 422 423 }