View Javadoc

1   package org.apache.turbine.services.xslt;
2   
3   /*
4    * Copyright 2001-2004 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.File;
20  import java.io.Reader;
21  import java.io.StringWriter;
22  import java.io.Writer;
23  
24  import java.util.HashMap;
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.TransformerFactory;
32  import javax.xml.transform.dom.DOMSource;
33  import javax.xml.transform.stream.StreamResult;
34  import javax.xml.transform.stream.StreamSource;
35  
36  import org.apache.commons.configuration.Configuration;
37  
38  import org.apache.commons.lang.StringUtils;
39  
40  import org.apache.turbine.Turbine;
41  import org.apache.turbine.services.InitializationException;
42  import org.apache.turbine.services.TurbineBaseService;
43  
44  import org.w3c.dom.Node;
45  
46  /***
47   * Implementation of the Turbine XSLT Service.  It transforms xml with a given
48   * xsl file.  XSL stylesheets are compiled and cached (if the property in
49   * TurbineResources.properties is set) to improve speeds.
50   *
51   * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
52   * @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a>
53   * @version $Id: TurbineXSLTService.java,v 1.10.2.2 2004/05/20 03:06:52 seade Exp $
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      protected Map cache = new HashMap();
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 = Turbine.getRealPath(conf.getString(STYLESHEET_PATH, null));
90  
91          if (StringUtils.isNotEmpty(path))
92          {
93              if (!path.endsWith("/") && !path.endsWith ("//"))
94              {
95                  path = path + File.separator;
96              }
97          }
98  
99          caching = conf.getBoolean(STYLESHEET_CACHING);
100 
101         tfactory = TransformerFactory.newInstance();
102 
103         setInit(true);
104     }
105 
106     /***
107      * Get a valid and existing filename from a template name.
108      * The extension is removed and replaced with .xsl.  If this
109      * file does not exist the method attempts to find default.xsl.
110      * If it fails to find default.xsl it returns null.
111      */
112     protected String getFileName(String templateName)
113     {
114         // First we chop of the existing extension
115         int colon = templateName.lastIndexOf(".");
116         if (colon > 0)
117         {
118             templateName = templateName.substring(0, colon);
119         }
120 
121         // Now we try to find the file ...
122         File f = new File(path + templateName + ".xsl");
123         if (f.exists())
124         {
125             return path + templateName + ".xsl";
126         }
127         else
128         {
129             // ... or the default file
130             f = new File(path + "default.xsl");
131             if (f.exists())
132             {
133                 return path + "default.xsl";
134             }
135             else
136             {
137                 return null;
138             }
139         }
140     }
141 
142     /***
143      * Compile Templates from an input file.
144      */
145     protected Templates compileTemplates(String source) throws Exception
146     {
147         StreamSource xslin = new StreamSource(new File(source));
148         Templates root = tfactory.newTemplates(xslin);
149         return root;
150     }
151 
152     /***
153      * Retrieves Templates.  If caching is switched on the
154      * first attempt is to load the Templates from the cache.
155      * If caching is switched of or if the Stylesheet is not found
156      * in the cache a new StyleSheetRoot is compiled from an input
157      * file.
158      * <p>
159      * This method is synchronized on the xsl cache so that a thread
160      * does not attempt to load a StyleSheetRoot from the cache while
161      * it is still being compiled.
162      */
163     protected Templates getTemplates(String xslName) throws Exception
164     {
165         synchronized (cache)
166         {
167             if (caching && cache.containsKey(xslName))
168             {
169                 return (Templates) cache.get(xslName);
170             }
171 
172             String fn = getFileName(xslName);
173 
174             if (fn == null) return null;
175 
176             Templates sr = compileTemplates(fn);
177 
178             if (caching)
179             {
180                 cache.put(xslName, sr);
181             }
182 
183             return sr;
184         }
185 
186     }
187 
188     protected void transform(String xslName, Source xmlin, Result xmlout)
189             throws Exception
190     {
191         Templates sr = getTemplates(xslName);
192         Transformer transformer;
193 
194 
195         // If there is no stylesheet we just echo the xml
196         if (sr == null)
197         {
198             transformer = tfactory.newTransformer();
199         }
200         else
201         {
202             transformer = sr.newTransformer();
203         }
204 
205         transformer.transform(xmlin, xmlout);
206     }
207 
208     /***
209      * Execute an xslt
210      */
211     public void transform(String xslName, Reader in, Writer out)
212             throws Exception
213     {
214         Source xmlin = new StreamSource(in);
215         Result xmlout = new StreamResult(out);
216 
217         transform(xslName, xmlin, xmlout);
218     }
219 
220     /***
221      * Execute an xslt
222      */
223     public String transform(String xslName, Reader in) throws Exception
224     {
225         StringWriter sw = new StringWriter();
226         transform(xslName, in, sw);
227         return sw.toString();
228     }
229 
230     /***
231      * Execute an xslt
232      */
233     public void transform (String xslName, Node in, Writer out)
234         throws Exception
235     {
236         Source xmlin = new DOMSource(in);
237         Result xmlout = new StreamResult(out);
238 
239         transform(xslName, xmlin, xmlout);
240     }
241 
242     /***
243      * Execute an xslt
244      */
245     public String transform (String xslName, Node in)
246         throws Exception
247     {
248         StringWriter sw = new StringWriter();
249         transform(xslName, in, sw);
250         return sw.toString();
251     }
252 
253 }