|
1 /* |
|
2 * Copyright (c) 1997, 2012, 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 } |