View Javadoc

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