001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/framework/xml/XSLTDocument.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    package org.deegree.framework.xml;
037    
038    import java.io.IOException;
039    import java.io.InputStream;
040    import java.io.OutputStream;
041    import java.io.Reader;
042    import java.net.MalformedURLException;
043    import java.net.URL;
044    import java.util.Iterator;
045    import java.util.Map;
046    import java.util.Properties;
047    
048    import javax.xml.transform.Result;
049    import javax.xml.transform.Source;
050    import javax.xml.transform.Transformer;
051    import javax.xml.transform.TransformerException;
052    import javax.xml.transform.TransformerFactory;
053    import javax.xml.transform.dom.DOMResult;
054    import javax.xml.transform.dom.DOMSource;
055    import javax.xml.transform.stream.StreamResult;
056    import javax.xml.transform.stream.StreamSource;
057    
058    import org.deegree.framework.log.ILogger;
059    import org.deegree.framework.log.LoggerFactory;
060    import org.deegree.framework.util.BootLogger;
061    import org.w3c.dom.Document;
062    import org.xml.sax.SAXException;
063    
064    /**
065     * Encapsulates the DOM representation of an XSLT stylesheet.
066     *
067     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
068     *
069     * @author last edited by: $Author: mschneider $
070     *
071     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18 Jun 2009) $
072     *
073     */
074    public class XSLTDocument extends XMLFragment {
075    
076        private static final long serialVersionUID = -2079718341146916400L;
077    
078        private static final ILogger LOG = LoggerFactory.getLogger( XSLTDocument.class );
079    
080        private static final TransformerFactory factory = TransformerFactory.newInstance();
081    
082        static {
083            LOG.logDebug( "XSLT implementation in use (TransformerFactory): " + factory.getClass().getName() );
084            try {
085                LOG.logDebug( "XSLT implementation in use (Transformer): " + factory.newTransformer().getClass().getName() );
086            } catch ( Exception e ) {
087                BootLogger.logError( "Error creating test Transformer instance.", e );
088            }
089        }
090    
091        /**
092         * An empty xslt document.
093         */
094        public XSLTDocument() {
095            super();
096        }
097    
098        /**
099         *
100         * @param url
101         * @throws IOException
102         * @throws SAXException
103         */
104        public XSLTDocument( URL url ) throws IOException, SAXException {
105            super( url );
106        }
107    
108        /**
109         * Transforms the given <code>XMLFragment</code> instance.
110         *
111         * @param xmlDocument
112         *            can not be null
113         * @param systemId
114         *            SystemID for the resulting <code>XMLFragment</code>, may be null
115         * @param outputProperties
116         *            transformation properties, may be null
117         * @param params
118         *            transformation parameters, may be null
119         * @return the transformed xml file.
120         * @throws TransformerException
121         * @throws MalformedURLException
122         *             if systemId is no valid <code>URL</code>
123         */
124        public synchronized XMLFragment transform( XMLFragment xmlDocument, String systemId, Properties outputProperties,
125                                                   Map<String, ?> params )
126                                throws TransformerException, MalformedURLException {
127    
128            XMLFragment resultFragment = null;
129            DOMSource xmlSource = new DOMSource( xmlDocument.getRootElement() );
130            DOMSource xslSource = new DOMSource( this.getRootElement().getOwnerDocument(),
131                                                 this.getSystemId() == null ? null : this.getSystemId().toString() );
132            Result result = transform( xmlSource, xslSource, new DOMResult(), outputProperties, params );
133            Document resultDocument = (Document) ( (DOMResult) result ).getNode();
134            resultFragment = new XMLFragment( resultDocument, systemId );
135    
136            return resultFragment;
137        }
138    
139        /**
140         * Transforms the given <code>XMLFragment</code> instance.
141         *
142         * @param xmlDocument
143         *            can not be null
144         * @return the transformed xml file.
145         * @throws TransformerException
146         */
147        public synchronized XMLFragment transform( XMLFragment xmlDocument )
148                                throws TransformerException {
149    
150            XMLFragment resultFragment;
151            try {
152                resultFragment = transform( xmlDocument, null, null, null );
153            } catch ( MalformedURLException e ) {
154                LOG.logError( "Internal Error. This should not happen." );
155                throw new TransformerException( "Internal Error. This should not happen.", e );
156            }
157    
158            return resultFragment;
159        }
160    
161        /**
162         * Transforms the given <code>XMLFragment</code> instance.
163         *
164         * @param xmlDocument
165         *            can not be null
166         * @param target
167         *            output stream where the result of the transformation will be written to
168         * @throws TransformerException
169         */
170        public synchronized void transform( XMLFragment xmlDocument, OutputStream target )
171                                throws TransformerException {
172    
173            DOMSource xmlSource = new DOMSource( xmlDocument.getRootElement() );
174            DOMSource xslSource = new DOMSource( this.getRootElement().getOwnerDocument(),
175                                                 this.getSystemId() == null ? null : this.getSystemId().toString() );
176            StreamResult sr = new StreamResult( target );
177            transform( xmlSource, xslSource, sr, null, null );
178    
179        }
180    
181        /**
182         * Transforms an input XML stream to an output stream using this <code>XSLTDocument</code>.
183         *
184         * @param input
185         *            provides the input xml as a stream
186         * @param target
187         *            output stream where the result of the transformation will be written to
188         * @throws TransformerException
189         */
190        public synchronized void transform( InputStream input, OutputStream target )
191                                throws TransformerException {
192    
193            Source xmlSource = new StreamSource( input );
194            DOMSource xslSource = new DOMSource( this.getRootElement().getOwnerDocument(),
195                                                 this.getSystemId() == null ? null : this.getSystemId().toString() );
196            StreamResult sr = new StreamResult( target );
197            transform( xmlSource, xslSource, sr, null, null );
198    
199        }
200    
201        /**
202         * Transforms the XML from the given <code>InputStream</code>.
203         * <p>
204         * NOTE: You have to make sure that the <code>InputStream</code> provides a valid XML document.
205         *
206         * @param instream
207         * @param systemId
208         *            SystemID for the resulting <code>XMLFragment</code>
209         * @param outputProperties
210         *            transformation properties, may be null
211         * @param params
212         *            transformation parameters, may be null
213         * @return the transformed xml file.
214         * @throws TransformerException
215         *             if transformation fails
216         * @throws MalformedURLException
217         *             if given systemId is no valid <code>URL</code>
218         */
219        public synchronized XMLFragment transform( InputStream instream, String systemId, Properties outputProperties,
220                                                   Map<String, ?> params )
221                                throws TransformerException, MalformedURLException {
222    
223            DOMSource xslSource = new DOMSource( getRootElement().getOwnerDocument(),
224                                                 this.getSystemId() == null ? null : this.getSystemId().toString() );
225            Result result = transform( new StreamSource( instream ), xslSource, new DOMResult(), outputProperties, params );
226            Document resultDocument = (Document) ( (DOMResult) result ).getNode();
227    
228            return new XMLFragment( resultDocument, systemId );
229        }
230    
231        /**
232         * Transforms the XML from the given <code>Reader</code>.
233         * <p>
234         * NOTE: You have to make sure that the <code>Reader</code> provides a valid XML document.
235         *
236         * @param reader
237         * @param systemId
238         *            SystemID for the resulting <code>XMLFragment</code>
239         * @param outputProperties
240         *            transformation properties, may be null
241         * @param params
242         *            transformation parameters, may be null
243         * @return the transformed xml file.
244         * @throws TransformerException
245         *             if transformation fails
246         * @throws MalformedURLException
247         *             if given systemId is no valid <code>URL</code>
248         */
249        public synchronized XMLFragment transform( Reader reader, String systemId, Properties outputProperties,
250                                                   Map<String, ?> params )
251                                throws TransformerException, MalformedURLException {
252    
253            DOMSource xslSource = new DOMSource( getRootElement().getOwnerDocument(),
254                                                 this.getSystemId() == null ? null : this.getSystemId().toString() );
255            Result result = transform( new StreamSource( reader ), xslSource, new DOMResult(), outputProperties, params );
256            Document resultDocument = (Document) ( (DOMResult) result ).getNode();
257    
258            return new XMLFragment( resultDocument, systemId );
259        }
260    
261        /**
262         * Transforms the given XML <code>Source</code> instance using the also submitted XSLT stylesheet
263         * <code>Source</code>.
264         *
265         * @param xmlSource
266         * @param xslSource
267         * @param result
268         * @param outputProperties
269         *            may be null
270         * @param params
271         *            may be null
272         * @return the transformed xml file.
273         * @throws TransformerException
274         * @throws TransformerException
275         */
276        public static Result transform( Source xmlSource, Source xslSource, Result result, Properties outputProperties,
277                                        Map<String, ?> params )
278                                throws TransformerException {
279    
280            try {
281                Transformer transformer = factory.newTransformer( xslSource );
282    
283                if ( params != null ) {
284                    Iterator<String> it = params.keySet().iterator();
285                    while ( it.hasNext() ) {
286                        String key = it.next();
287                        transformer.setParameter( key, params.get( key ) );
288                    }
289                }
290                if ( outputProperties != null ) {
291                    transformer.setOutputProperties( outputProperties );
292                }
293    
294                transformer.transform( xmlSource, result );
295            } catch ( TransformerException e ) {
296                String transformerClassName = null;
297                String transformerFactoryClassName = factory.getClass().getName();
298                try {
299                    transformerClassName = factory.newTransformer().getClass().getName();
300                } catch ( Exception e2 ) {
301                    LOG.logError( "Error creating Transformer instance." );
302                }
303                String errorMsg = "XSL transformation using stylesheet with systemId '" + xslSource.getSystemId()
304                                  + "' and xml source with systemId '" + xmlSource.getSystemId()
305                                  + "' failed. TransformerFactory class: " + transformerFactoryClassName
306                                  + "', Transformer class: " + transformerClassName;
307                LOG.logError( errorMsg, e );
308                throw new TransformerException( errorMsg, e );
309            }
310    
311            return result;
312        }
313    }