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