001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: /*
027: * EfficientStreamingTransformer.java
028: *
029: * Created on July 29, 2002, 3:49 PM
030: */
031:
032: package com.sun.xml.internal.messaging.saaj.util.transform;
033:
034: import java.io.*;
035:
036: import javax.xml.parsers.DocumentBuilder;
037: import javax.xml.parsers.DocumentBuilderFactory;
038:
039: import javax.xml.transform.*;
040: import javax.xml.transform.dom.DOMSource;
041: import javax.xml.transform.dom.DOMResult;
042: import javax.xml.transform.stream.StreamResult;
043: import javax.xml.transform.stream.StreamSource;
044:
045: import org.w3c.dom.Document;
046:
047: import com.sun.xml.internal.messaging.saaj.util.XMLDeclarationParser;
048: import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection;
049:
050: /**
051: * This class is a proxy for a Transformer object with optimizations
052: * for certain cases. If source and result are of type stream, then
053: * bytes are simply copied whenever possible (note that this assumes
054: * that the input is well formed). In addition, it provides support for
055: * FI using native DOM parsers and serializers.
056: *
057: * @author Panos Kougiouris panos@acm.org
058: * @author Santiago.PericasGeertsen@sun.com
059: *
060: */
061: public class EfficientStreamingTransformer extends
062: javax.xml.transform.Transformer {
063:
064: static final String version;
065: static final String vendor;
066:
067: protected static TransformerFactory transformerFactory = TransformerFactory
068: .newInstance();
069:
070: static {
071: version = System.getProperty("java.vm.version");
072: vendor = System.getProperty("java.vm.vendor");
073: if (vendor.startsWith("Sun")
074: && (version.startsWith("1.4") || version
075: .startsWith("1.3"))) {
076: transformerFactory = new com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl();
077: }
078: }
079:
080: /**
081: * TransformerFactory instance.
082: */
083:
084: /**
085: * Underlying XSLT transformer.
086: */
087: private Transformer m_realTransformer = null;
088:
089: /**
090: * Undelying FI DOM parser.
091: */
092: private Object m_fiDOMDocumentParser = null;
093:
094: /**
095: * Underlying FI DOM serializer.
096: */
097: private Object m_fiDOMDocumentSerializer = null;
098:
099: private EfficientStreamingTransformer() {
100: }
101:
102: private void materialize() throws TransformerException {
103: if (m_realTransformer == null) {
104: m_realTransformer = transformerFactory.newTransformer();
105: }
106: }
107:
108: public void clearParameters() {
109: if (m_realTransformer != null)
110: m_realTransformer.clearParameters();
111: }
112:
113: public javax.xml.transform.ErrorListener getErrorListener() {
114: try {
115: materialize();
116: return m_realTransformer.getErrorListener();
117: } catch (TransformerException e) {
118: // will be caught later
119: }
120: return null;
121: }
122:
123: public java.util.Properties getOutputProperties() {
124: try {
125: materialize();
126: return m_realTransformer.getOutputProperties();
127: } catch (TransformerException e) {
128: // will be caught later
129: }
130: return null;
131: }
132:
133: public String getOutputProperty(String str)
134: throws java.lang.IllegalArgumentException {
135: try {
136: materialize();
137: return m_realTransformer.getOutputProperty(str);
138: } catch (TransformerException e) {
139: // will be caught later
140: }
141: return null;
142: }
143:
144: public Object getParameter(String str) {
145: try {
146: materialize();
147: return m_realTransformer.getParameter(str);
148: } catch (TransformerException e) {
149: // will be caught later
150: }
151: return null;
152: }
153:
154: public javax.xml.transform.URIResolver getURIResolver() {
155: try {
156: materialize();
157: return m_realTransformer.getURIResolver();
158: } catch (TransformerException e) {
159: // will be caught later
160: }
161: return null;
162: }
163:
164: public void setErrorListener(
165: javax.xml.transform.ErrorListener errorListener)
166: throws java.lang.IllegalArgumentException {
167: try {
168: materialize();
169: m_realTransformer.setErrorListener(errorListener);
170: } catch (TransformerException e) {
171: // will be caught later
172: }
173: }
174:
175: public void setOutputProperties(java.util.Properties properties)
176: throws java.lang.IllegalArgumentException {
177: try {
178: materialize();
179: m_realTransformer.setOutputProperties(properties);
180: } catch (TransformerException e) {
181: // will be caught later
182: }
183: }
184:
185: public void setOutputProperty(String str, String str1)
186: throws java.lang.IllegalArgumentException {
187: try {
188: materialize();
189: m_realTransformer.setOutputProperty(str, str1);
190: } catch (TransformerException e) {
191: // will be caught later
192: }
193: }
194:
195: public void setParameter(String str, Object obj) {
196: try {
197: materialize();
198: m_realTransformer.setParameter(str, obj);
199: } catch (TransformerException e) {
200: // will be caught later
201: }
202: }
203:
204: public void setURIResolver(
205: javax.xml.transform.URIResolver uRIResolver) {
206: try {
207: materialize();
208: m_realTransformer.setURIResolver(uRIResolver);
209: } catch (TransformerException e) {
210: // will be caught later
211: }
212: }
213:
214: private InputStream getInputStreamFromSource(StreamSource s)
215: throws TransformerException {
216:
217: InputStream stream = s.getInputStream();
218: if (stream != null)
219: return stream;
220:
221: if (s.getReader() != null)
222: return null;
223:
224: String systemId = s.getSystemId();
225: if (systemId != null) {
226: try {
227: String fileURL = systemId;
228:
229: if (systemId.startsWith("file:///")) {
230: /*
231: systemId is:
232: file:///<drive>:/some/path/file.xml
233: or
234: file:///some/path/file.xml
235: */
236:
237: String absolutePath = systemId.substring(7);
238: /*
239: /<drive>:/some/path/file.xml
240: or
241: /some/path/file.xml
242: */
243:
244: boolean hasDriveDesignator = absolutePath
245: .indexOf(":") > 0;
246: if (hasDriveDesignator) {
247: String driveDesignatedPath = absolutePath
248: .substring(1);
249: /*
250: <drive>:/some/path/file.xml */
251: fileURL = driveDesignatedPath;
252: } else {
253: /*
254: /some/path/file.xml */
255: fileURL = absolutePath;
256: }
257: }
258: return new FileInputStream(fileURL);
259: } catch (IOException e) {
260: throw new TransformerException(e.toString());
261: }
262: }
263:
264: throw new TransformerException("Unexpected StreamSource object");
265: }
266:
267: //------------------------------------------------------------------------
268:
269: public void transform(javax.xml.transform.Source source,
270: javax.xml.transform.Result result)
271: throws javax.xml.transform.TransformerException {
272: // StreamSource -> StreamResult
273: if ((source instanceof StreamSource)
274: && (result instanceof StreamResult)) {
275: try {
276: StreamSource streamSource = (StreamSource) source;
277: InputStream is = getInputStreamFromSource(streamSource);
278:
279: OutputStream os = ((StreamResult) result)
280: .getOutputStream();
281: if (os == null)
282: // TODO: We might want to fix this if it were to be used beyond
283: // XmlDataContentHandler that we know uses only OutputStream
284: throw new TransformerException(
285: "Unexpected StreamResult object contains null OutputStream");
286:
287: if (is != null) {
288: if (is.markSupported())
289: is.mark(Integer.MAX_VALUE);
290: int num;
291: byte[] b = new byte[8192];
292: while ((num = is.read(b)) != -1) {
293: os.write(b, 0, num);
294: }
295: if (is.markSupported())
296: is.reset();
297: return;
298: }
299:
300: Reader reader = streamSource.getReader();
301: if (reader != null) {
302:
303: if (reader.markSupported())
304: reader.mark(Integer.MAX_VALUE);
305:
306: PushbackReader pushbackReader = new PushbackReader(
307: reader, 4096);
308: //some size to unread <?xml ....?>
309: XMLDeclarationParser ev = new XMLDeclarationParser(
310: pushbackReader);
311: try {
312: ev.parse();
313: } catch (Exception ex) {
314: throw new TransformerException(
315: "Unable to run the JAXP transformer on a stream "
316: + ex.getMessage());
317: }
318: Writer writer = new OutputStreamWriter(os /*, ev.getEncoding()*/);
319: ev.writeTo(writer); // doesn't write any, if no header
320:
321: int num;
322: char[] ac = new char[8192];
323: while ((num = pushbackReader.read(ac)) != -1) {
324: writer.write(ac, 0, num);
325: }
326: writer.flush();
327:
328: if (reader.markSupported())
329: reader.reset();
330: return;
331: }
332: } catch (IOException e) {
333: e.printStackTrace();
334: throw new TransformerException(e.toString());
335: }
336:
337: throw new TransformerException(
338: "Unexpected StreamSource object");
339: }
340: // FastInfosetSource -> DOMResult
341: else if (FastInfosetReflection.isFastInfosetSource(source)
342: && (result instanceof DOMResult)) {
343: try {
344: // Use reflection to avoid a static dep with FI
345: if (m_fiDOMDocumentParser == null) {
346: m_fiDOMDocumentParser = FastInfosetReflection
347: .DOMDocumentParser_new();
348: }
349:
350: // m_fiDOMDocumentParser.parse(document, source.getInputStream())
351: FastInfosetReflection
352: .DOMDocumentParser_parse(
353: m_fiDOMDocumentParser,
354: (Document) ((DOMResult) result)
355: .getNode(),
356: FastInfosetReflection
357: .FastInfosetSource_getInputStream(source));
358:
359: // We're done!
360: return;
361: } catch (Exception e) {
362: throw new TransformerException(e);
363: }
364: }
365: // DOMSource -> FastInfosetResult
366: else if ((source instanceof DOMSource)
367: && FastInfosetReflection.isFastInfosetResult(result)) {
368: try {
369: // Use reflection to avoid a static dep with FI
370: if (m_fiDOMDocumentSerializer == null) {
371: m_fiDOMDocumentSerializer = FastInfosetReflection
372: .DOMDocumentSerializer_new();
373: }
374:
375: // m_fiDOMDocumentSerializer.setOutputStream(result.getOutputStream())
376: FastInfosetReflection
377: .DOMDocumentSerializer_setOutputStream(
378: m_fiDOMDocumentSerializer,
379: FastInfosetReflection
380: .FastInfosetResult_getOutputStream(result));
381:
382: // m_fiDOMDocumentSerializer.serialize(node)
383: FastInfosetReflection.DOMDocumentSerializer_serialize(
384: m_fiDOMDocumentSerializer, ((DOMSource) source)
385: .getNode());
386:
387: // We're done!
388: return;
389: } catch (Exception e) {
390: throw new TransformerException(e);
391: }
392: }
393:
394: // All other cases -- use transformer object
395:
396: materialize();
397: m_realTransformer.transform(source, result);
398: }
399:
400: /**
401: * Threadlocal to hold a Transformer instance for this thread.
402: */
403: private static ThreadLocal effTransformer = new ThreadLocal();
404:
405: /**
406: * Return Transformer instance for this thread, allocating a new one if
407: * necessary. Note that this method does not clear global parameters,
408: * properties or any other data set on a previously used transformer.
409: */
410: public static Transformer newTransformer() {
411: Transformer tt = (Transformer) effTransformer.get();
412: if (tt == null) {
413: effTransformer
414: .set(tt = new EfficientStreamingTransformer());
415: }
416: return tt;
417: }
418:
419: }
|