View Javadoc

1   package org.apache.turbine.services.xslt;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.Reader;
25  import java.io.StringWriter;
26  import java.io.Writer;
27  import java.net.URL;
28  import java.util.Iterator;
29  import java.util.Map;
30  
31  import javax.xml.transform.Result;
32  import javax.xml.transform.Source;
33  import javax.xml.transform.Templates;
34  import javax.xml.transform.Transformer;
35  import javax.xml.transform.TransformerException;
36  import javax.xml.transform.TransformerFactory;
37  import javax.xml.transform.dom.DOMSource;
38  import javax.xml.transform.stream.StreamResult;
39  import javax.xml.transform.stream.StreamSource;
40  
41  import org.apache.commons.collections.map.LRUMap;
42  import org.apache.commons.configuration.Configuration;
43  import org.apache.commons.lang.StringUtils;
44  import org.apache.turbine.services.InitializationException;
45  import org.apache.turbine.services.TurbineBaseService;
46  import org.apache.turbine.services.servlet.TurbineServlet;
47  import org.w3c.dom.Node;
48  
49  /***
50   * Implementation of the Turbine XSLT Service.  It transforms xml with a given
51   * xsl file.  XSL stylesheets are compiled and cached (if the property in
52   * TurbineResources.properties is set) to improve speeds.
53   *
54   * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
55   * @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a>
56   * @author <a href="thomas.vandahl@tewisoft.de">Thomas Vandahl</a>
57   * @version $Id: TurbineXSLTService.java 567398 2007-08-19 13:11:33Z tv $
58   */
59  public class TurbineXSLTService
60          extends TurbineBaseService
61          implements XSLTService
62  {
63      /***
64       * Property to control the caching of StyleSheetRoots.
65       */
66      protected boolean caching = false;
67  
68      /***
69       * Path to style sheets used for tranforming well-formed
70       * XML documents. The path is relative to the webapp context.
71       */
72      protected String path;
73  
74      /***
75       * Cache of compiled StyleSheetRoots.
76       */
77      private LRUMap cache = new LRUMap(20);
78  
79      /***
80       * Factory for producing templates and null transformers
81       */
82      private static TransformerFactory tfactory;
83  
84      /***
85       * Initialize the TurbineXSLT Service.  Load the path to search for
86       * xsl files and initiates the cache.
87       */
88      public void init()
89              throws InitializationException
90      {
91          Configuration conf = getConfiguration();
92  
93          path = conf.getString(STYLESHEET_PATH, STYLESHEET_PATH_DEFAULT);
94          caching = conf.getBoolean(STYLESHEET_CACHING, STYLESHEET_CACHING_DEFAULT);
95  
96          tfactory = TransformerFactory.newInstance();
97  
98          setInit(true);
99      }
100 
101     /***
102      * Try to create a valid url object from the style parameter.
103      *
104      * @param style the xsl-Style
105      * @return a <code>URL</code> object or null if the style sheet could not be found
106      */
107     private URL getStyleURL(String style)
108     {
109         StringBuffer sb = new StringBuffer(128);
110 
111         if (StringUtils.isNotEmpty(path))
112         {
113             if (path.charAt(0) != '/')
114             {
115                 sb.append('/');
116             }
117 
118             sb.append(path);
119 
120             if (path.charAt(path.length() - 1) != '/')
121             {
122                 sb.append('/');
123             }
124         }
125         else
126         {
127             sb.append('/');
128         }
129 
130         // we chop off the existing extension
131         int colon = style.lastIndexOf(".");
132 
133         if (colon > 0)
134         {
135             sb.append(style.substring(0, colon));
136         }
137         else
138         {
139             sb.append(style);
140         }
141 
142         sb.append(".xsl");
143 
144         return TurbineServlet.getResource(sb.toString());
145     }
146 
147     /***
148      * Compile Templates from an input URL.
149      */
150     protected Templates compileTemplates(URL source) throws Exception
151     {
152         InputStream in = source.openStream();
153         StreamSource xslin = new StreamSource(in, source.toString());
154         Templates root = TransformerFactory.newInstance().newTemplates(xslin);
155         in.close();
156         
157         return root;
158     }
159 
160     /***
161      * Retrieves Templates.  If caching is switched on the
162      * first attempt is to load the Templates from the cache.
163      * If caching is switched off or if the Stylesheet is not found
164      * in the cache a new StyleSheetRoot is compiled from an input
165      * file.
166      */
167     protected Templates getTemplates(String xslName) throws Exception
168     {
169         synchronized (cache)
170         {
171             if (caching && cache.containsKey(xslName))
172             {
173                 return (Templates) cache.get(xslName);
174             }
175         }
176 
177         URL url = getStyleURL(xslName);
178 
179         if (url == null)
180         {
181             return null;
182         }
183 
184         Templates sr = compileTemplates(url);
185 
186         synchronized (cache)
187         {
188             if (caching)
189             {
190                 cache.put(xslName, sr);
191             }
192         }
193 
194         return sr;
195     }
196 
197     /***
198      * Transform the input source into the output source using the given style
199      *
200      * @param style the stylesheet parameter
201      * @param in the input source
202      * @param out the output source
203      * @param params XSLT parameter for the style sheet
204      *
205      * @throws TransformerException
206      */
207     protected void transform(String style, Source in, Result out, Map params)
208             throws TransformerException, IOException, Exception
209     {
210         Templates styleTemplate = getTemplates(style);
211 
212         Transformer transformer = (styleTemplate != null)
213                 ? styleTemplate.newTransformer()
214                 : tfactory.newTransformer();
215 
216         if (params != null)
217         {
218             for (Iterator it = params.entrySet().iterator(); it.hasNext();)
219             {
220                 Map.Entry entry = (Map.Entry) it.next();
221                 transformer.setParameter(String.valueOf(entry.getKey()), entry.getValue());
222             }
223         }
224 
225         //      Start the transformation and rendering process
226         transformer.transform(in, out);
227     }
228 
229     /***
230      * Execute an xslt
231      */
232     public void transform(String xslName, Reader in, Writer out)
233             throws Exception
234     {
235         Source xmlin = new StreamSource(in);
236         Result xmlout = new StreamResult(out);
237 
238         transform(xslName, xmlin, xmlout, null);
239     }
240 
241     /***
242      * Execute an xslt
243      */
244     public String transform(String xslName, Reader in)
245             throws Exception
246     {
247         StringWriter sw = new StringWriter();
248         transform(xslName, in, sw);
249         return sw.toString();
250     }
251 
252     /***
253      * Execute an xslt
254      */
255     public void transform (String xslName, Node in, Writer out)
256             throws Exception
257     {
258         Source xmlin = new DOMSource(in);
259         Result xmlout = new StreamResult(out);
260 
261         transform(xslName, xmlin, xmlout, null);
262     }
263 
264     /***
265      * Execute an xslt
266      */
267     public String transform (String xslName, Node in)
268             throws Exception
269     {
270         StringWriter sw = new StringWriter();
271         transform(xslName, in, sw);
272         return sw.toString();
273     }
274 
275     /***
276      * Execute an xslt
277      */
278     public void transform(String xslName, Reader in, Writer out, Map params)
279             throws Exception
280     {
281         Source xmlin = new StreamSource(in);
282         Result xmlout = new StreamResult(out);
283 
284         transform(xslName, xmlin, xmlout, params);
285     }
286 
287     /***
288      * Execute an xslt
289      */
290     public String transform(String xslName, Reader in, Map params) throws Exception
291     {
292         StringWriter sw = new StringWriter();
293         transform(xslName, in, sw, params);
294         return sw.toString();
295     }
296 
297     /***
298      * Execute an xslt
299      */
300     public void transform (String xslName, Node in, Writer out, Map params)
301             throws Exception
302     {
303         Source xmlin = new DOMSource(in);
304         Result xmlout = new StreamResult(out);
305 
306         transform(xslName, xmlin, xmlout, params);
307     }
308 
309     /***
310      * Execute an xslt
311      */
312     public String transform (String xslName, Node in, Map params)
313             throws Exception
314     {
315         StringWriter sw = new StringWriter();
316         transform(xslName, in, sw, params);
317         return sw.toString();
318     }
319 
320 }