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