aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: /* aoqi@0: * EfficientStreamingTransformer.java aoqi@0: * aoqi@0: * Created on July 29, 2002, 3:49 PM aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.messaging.saaj.util.transform; aoqi@0: aoqi@0: import java.io.*; aoqi@0: aoqi@0: import java.net.URISyntaxException; aoqi@0: import javax.xml.transform.dom.DOMSource; aoqi@0: import javax.xml.transform.dom.DOMResult; aoqi@0: import javax.xml.transform.stream.StreamResult; aoqi@0: import javax.xml.transform.stream.StreamSource; aoqi@0: aoqi@0: import org.w3c.dom.Document; aoqi@0: aoqi@0: import com.sun.xml.internal.messaging.saaj.util.XMLDeclarationParser; aoqi@0: import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection; aoqi@0: import java.net.URI; aoqi@0: import javax.xml.transform.Transformer; aoqi@0: import javax.xml.transform.TransformerException; aoqi@0: import javax.xml.transform.TransformerFactory; aoqi@0: aoqi@0: /** aoqi@0: * This class is a proxy for a Transformer object with optimizations aoqi@0: * for certain cases. If source and result are of type stream, then aoqi@0: * bytes are simply copied whenever possible (note that this assumes aoqi@0: * that the input is well formed). In addition, it provides support for aoqi@0: * FI using native DOM parsers and serializers. aoqi@0: * aoqi@0: * @author Panos Kougiouris panos@acm.org aoqi@0: * @author Santiago.PericasGeertsen@sun.com aoqi@0: * aoqi@0: */ aoqi@0: public class EfficientStreamingTransformer aoqi@0: extends javax.xml.transform.Transformer { aoqi@0: aoqi@0: //static final String version; aoqi@0: //static final String vendor; aoqi@0: // removing static : security issue : CR 6813167Z aoqi@0: private final TransformerFactory transformerFactory = TransformerFactory.newInstance(); aoqi@0: aoqi@0: /** aoqi@0: removing support for Java 1.4 and 1.3 : CR6658158 aoqi@0: static { aoqi@0: version = System.getProperty("java.vm.version"); aoqi@0: vendor = System.getProperty("java.vm.vendor"); aoqi@0: if (vendor.startsWith("Sun") && aoqi@0: (version.startsWith("1.4") || version.startsWith("1.3"))) { aoqi@0: transformerFactory = aoqi@0: new com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl(); aoqi@0: } aoqi@0: }*/ aoqi@0: aoqi@0: /** aoqi@0: * TransformerFactory instance. aoqi@0: */ aoqi@0: aoqi@0: /** aoqi@0: * Underlying XSLT transformer. aoqi@0: */ aoqi@0: private Transformer m_realTransformer = null; aoqi@0: aoqi@0: /** aoqi@0: * Undelying FI DOM parser. aoqi@0: */ aoqi@0: private Object m_fiDOMDocumentParser = null; aoqi@0: aoqi@0: /** aoqi@0: * Underlying FI DOM serializer. aoqi@0: */ aoqi@0: private Object m_fiDOMDocumentSerializer = null; aoqi@0: aoqi@0: private EfficientStreamingTransformer() { aoqi@0: } aoqi@0: aoqi@0: private void materialize() throws TransformerException { aoqi@0: if (m_realTransformer == null) { aoqi@0: m_realTransformer = transformerFactory.newTransformer(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void clearParameters() { aoqi@0: if (m_realTransformer != null) aoqi@0: m_realTransformer.clearParameters(); aoqi@0: } aoqi@0: aoqi@0: public javax.xml.transform.ErrorListener getErrorListener() { aoqi@0: try { aoqi@0: materialize(); aoqi@0: return m_realTransformer.getErrorListener(); aoqi@0: } catch (TransformerException e) { aoqi@0: // will be caught later aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public java.util.Properties getOutputProperties() { aoqi@0: try { aoqi@0: materialize(); aoqi@0: return m_realTransformer.getOutputProperties(); aoqi@0: } catch (TransformerException e) { aoqi@0: // will be caught later aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public String getOutputProperty(String str) aoqi@0: throws java.lang.IllegalArgumentException { aoqi@0: try { aoqi@0: materialize(); aoqi@0: return m_realTransformer.getOutputProperty(str); aoqi@0: } catch (TransformerException e) { aoqi@0: // will be caught later aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public Object getParameter(String str) { aoqi@0: try { aoqi@0: materialize(); aoqi@0: return m_realTransformer.getParameter(str); aoqi@0: } catch (TransformerException e) { aoqi@0: // will be caught later aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public javax.xml.transform.URIResolver getURIResolver() { aoqi@0: try { aoqi@0: materialize(); aoqi@0: return m_realTransformer.getURIResolver(); aoqi@0: } catch (TransformerException e) { aoqi@0: // will be caught later aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public void setErrorListener( aoqi@0: javax.xml.transform.ErrorListener errorListener) aoqi@0: throws java.lang.IllegalArgumentException { aoqi@0: try { aoqi@0: materialize(); aoqi@0: m_realTransformer.setErrorListener(errorListener); aoqi@0: } catch (TransformerException e) { aoqi@0: // will be caught later aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void setOutputProperties(java.util.Properties properties) aoqi@0: throws java.lang.IllegalArgumentException { aoqi@0: try { aoqi@0: materialize(); aoqi@0: m_realTransformer.setOutputProperties(properties); aoqi@0: } catch (TransformerException e) { aoqi@0: // will be caught later aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void setOutputProperty(String str, String str1) aoqi@0: throws java.lang.IllegalArgumentException { aoqi@0: try { aoqi@0: materialize(); aoqi@0: m_realTransformer.setOutputProperty(str, str1); aoqi@0: } catch (TransformerException e) { aoqi@0: // will be caught later aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void setParameter(String str, Object obj) { aoqi@0: try { aoqi@0: materialize(); aoqi@0: m_realTransformer.setParameter(str, obj); aoqi@0: } catch (TransformerException e) { aoqi@0: // will be caught later aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void setURIResolver(javax.xml.transform.URIResolver uRIResolver) { aoqi@0: try { aoqi@0: materialize(); aoqi@0: m_realTransformer.setURIResolver(uRIResolver); aoqi@0: } catch (TransformerException e) { aoqi@0: // will be caught later aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private InputStream getInputStreamFromSource(StreamSource s) aoqi@0: throws TransformerException { aoqi@0: aoqi@0: InputStream stream = s.getInputStream(); aoqi@0: if (stream != null) aoqi@0: return stream; aoqi@0: aoqi@0: if (s.getReader() != null) aoqi@0: return null; aoqi@0: aoqi@0: String systemId = s.getSystemId(); aoqi@0: if (systemId != null) { aoqi@0: try { aoqi@0: String fileURL = systemId; aoqi@0: aoqi@0: if (systemId.startsWith("file:///")) aoqi@0: { aoqi@0: /* aoqi@0: systemId is: aoqi@0: file:///:/some/path/file.xml aoqi@0: or aoqi@0: file:///some/path/file.xml aoqi@0: */ aoqi@0: aoqi@0: String absolutePath = systemId.substring(7); aoqi@0: /* aoqi@0: /:/some/path/file.xml aoqi@0: or aoqi@0: /some/path/file.xml aoqi@0: */ aoqi@0: aoqi@0: boolean hasDriveDesignator = absolutePath.indexOf(":") > 0; aoqi@0: if (hasDriveDesignator) { aoqi@0: String driveDesignatedPath = absolutePath.substring(1); aoqi@0: /* aoqi@0: :/some/path/file.xml */ aoqi@0: fileURL = driveDesignatedPath; aoqi@0: } aoqi@0: else { aoqi@0: /* aoqi@0: /some/path/file.xml */ aoqi@0: fileURL = absolutePath; aoqi@0: } aoqi@0: } aoqi@0: //return new FileInputStream(fileURL); aoqi@0: try { aoqi@0: return new FileInputStream(new File(new URI(fileURL))); aoqi@0: } catch (URISyntaxException ex) { aoqi@0: throw new TransformerException(ex); aoqi@0: } aoqi@0: } catch (IOException e) { aoqi@0: throw new TransformerException(e.toString()); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: throw new TransformerException("Unexpected StreamSource object"); aoqi@0: } aoqi@0: aoqi@0: //------------------------------------------------------------------------ aoqi@0: aoqi@0: public void transform( aoqi@0: javax.xml.transform.Source source, aoqi@0: javax.xml.transform.Result result) aoqi@0: throws javax.xml.transform.TransformerException aoqi@0: { aoqi@0: // StreamSource -> StreamResult aoqi@0: if ((source instanceof StreamSource) aoqi@0: && (result instanceof StreamResult)) { aoqi@0: try { aoqi@0: StreamSource streamSource = (StreamSource) source; aoqi@0: InputStream is = getInputStreamFromSource(streamSource); aoqi@0: aoqi@0: OutputStream os = ((StreamResult) result).getOutputStream(); aoqi@0: if (os == null) aoqi@0: // TODO: We might want to fix this if it were to be used beyond aoqi@0: // XmlDataContentHandler that we know uses only OutputStream aoqi@0: throw new TransformerException("Unexpected StreamResult object contains null OutputStream"); aoqi@0: aoqi@0: if (is != null) { aoqi@0: if (is.markSupported()) aoqi@0: is.mark(Integer.MAX_VALUE); aoqi@0: int num; aoqi@0: byte[] b = new byte[8192]; aoqi@0: while ((num = is.read(b)) != -1) { aoqi@0: os.write(b, 0, num); aoqi@0: } aoqi@0: if (is.markSupported()) aoqi@0: is.reset(); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: Reader reader = streamSource.getReader(); aoqi@0: if (reader != null) { aoqi@0: aoqi@0: if (reader.markSupported()) aoqi@0: reader.mark(Integer.MAX_VALUE); aoqi@0: aoqi@0: PushbackReader pushbackReader = new PushbackReader(reader, 4096); aoqi@0: //some size to unread aoqi@0: XMLDeclarationParser ev = aoqi@0: new XMLDeclarationParser(pushbackReader); aoqi@0: try { aoqi@0: ev.parse(); aoqi@0: } catch (Exception ex) { aoqi@0: throw new TransformerException( aoqi@0: "Unable to run the JAXP transformer on a stream " aoqi@0: + ex.getMessage()); aoqi@0: } aoqi@0: Writer writer = aoqi@0: new OutputStreamWriter(os /*, ev.getEncoding()*/); aoqi@0: ev.writeTo(writer); // doesn't write any, if no header aoqi@0: aoqi@0: int num; aoqi@0: char[] ac = new char[8192]; aoqi@0: while ((num = pushbackReader.read(ac)) != -1) { aoqi@0: writer.write(ac, 0, num); aoqi@0: } aoqi@0: writer.flush(); aoqi@0: aoqi@0: if (reader.markSupported()) aoqi@0: reader.reset(); aoqi@0: return; aoqi@0: } aoqi@0: } catch (IOException e) { aoqi@0: e.printStackTrace(); aoqi@0: throw new TransformerException(e.toString()); aoqi@0: } aoqi@0: aoqi@0: throw new TransformerException("Unexpected StreamSource object"); aoqi@0: } aoqi@0: // FastInfosetSource -> DOMResult aoqi@0: else if (FastInfosetReflection.isFastInfosetSource(source) aoqi@0: && (result instanceof DOMResult)) aoqi@0: { aoqi@0: try { aoqi@0: // Use reflection to avoid a static dep with FI aoqi@0: if (m_fiDOMDocumentParser == null) { aoqi@0: m_fiDOMDocumentParser = FastInfosetReflection.DOMDocumentParser_new(); aoqi@0: } aoqi@0: aoqi@0: // m_fiDOMDocumentParser.parse(document, source.getInputStream()) aoqi@0: FastInfosetReflection.DOMDocumentParser_parse( aoqi@0: m_fiDOMDocumentParser, aoqi@0: (Document) ((DOMResult) result).getNode(), aoqi@0: FastInfosetReflection.FastInfosetSource_getInputStream(source)); aoqi@0: aoqi@0: // We're done! aoqi@0: return; aoqi@0: } aoqi@0: catch (Exception e) { aoqi@0: throw new TransformerException(e); aoqi@0: } aoqi@0: } aoqi@0: // DOMSource -> FastInfosetResult aoqi@0: else if ((source instanceof DOMSource) aoqi@0: && FastInfosetReflection.isFastInfosetResult(result)) aoqi@0: { aoqi@0: try { aoqi@0: // Use reflection to avoid a static dep with FI aoqi@0: if (m_fiDOMDocumentSerializer == null) { aoqi@0: m_fiDOMDocumentSerializer = FastInfosetReflection.DOMDocumentSerializer_new(); aoqi@0: } aoqi@0: aoqi@0: // m_fiDOMDocumentSerializer.setOutputStream(result.getOutputStream()) aoqi@0: FastInfosetReflection.DOMDocumentSerializer_setOutputStream( aoqi@0: m_fiDOMDocumentSerializer, aoqi@0: FastInfosetReflection.FastInfosetResult_getOutputStream(result)); aoqi@0: aoqi@0: // m_fiDOMDocumentSerializer.serialize(node) aoqi@0: FastInfosetReflection.DOMDocumentSerializer_serialize( aoqi@0: m_fiDOMDocumentSerializer, aoqi@0: ((DOMSource) source).getNode()); aoqi@0: aoqi@0: // We're done! aoqi@0: return; aoqi@0: } aoqi@0: catch (Exception e) { aoqi@0: throw new TransformerException(e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // All other cases -- use transformer object aoqi@0: aoqi@0: materialize(); aoqi@0: m_realTransformer.transform(source, result); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Threadlocal to hold a Transformer instance for this thread. aoqi@0: * CR : 6813167 aoqi@0: */ aoqi@0: //private static ThreadLocal effTransformer = new ThreadLocal(); aoqi@0: aoqi@0: /** aoqi@0: * Return Transformer instance for this thread, allocating a new one if aoqi@0: * necessary. Note that this method does not clear global parameters, aoqi@0: * properties or any other data set on a previously used transformer. aoqi@0: */ aoqi@0: public static Transformer newTransformer() { aoqi@0: //CR : 6813167 aoqi@0: /*Transformer tt = (Transformer) effTransformer.get(); aoqi@0: if (tt == null) { aoqi@0: effTransformer.set(tt = new EfficientStreamingTransformer()); aoqi@0: } aoqi@0: return tt;*/ aoqi@0: return new EfficientStreamingTransformer(); aoqi@0: } aoqi@0: aoqi@0: }