View Javadoc

1   package net.sourceforge.blogentis.turbine;
2   
3   /*
4    * ==================================================================== The
5    * Apache Software License, Version 1.1
6    * 
7    * Copyright (c) 2001-2003 The Apache Software Foundation. All rights reserved.
8    * 
9    * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions are met:
11   * 
12   * 1. Redistributions of source code must retain the above copyright notice,
13   * this list of conditions and the following disclaimer.
14   * 
15   * 2. Redistributions in binary form must reproduce the above copyright notice,
16   * this list of conditions and the following disclaimer in the documentation
17   * and/or other materials provided with the distribution.
18   * 
19   * 3. The end-user documentation included with the redistribution, if any, must
20   * include the following acknowledgment: "This product includes software
21   * developed by the Apache Software Foundation (http://www.apache.org/)."
22   * Alternately, this acknowledgment may appear in the software itself, if and
23   * wherever such third-party acknowledgments normally appear.
24   * 
25   * 4. The names "Apache" and "Apache Software Foundation" and "Apache Turbine"
26   * must not be used to endorse or promote products derived from this software
27   * without prior written permission. For written permission, please contact
28   * apache@apache.org.
29   * 
30   * 5. Products derived from this software may not be called "Apache", "Apache
31   * Turbine", nor may "Apache" appear in their name, without prior written
32   * permission of the Apache Software Foundation.
33   * 
34   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE
37   * SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
38   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
40   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
41   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
42   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
43   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44   * ====================================================================
45   * 
46   * This software consists of voluntary contributions made by many individuals on
47   * behalf of the Apache Software Foundation. For more information on the Apache
48   * Software Foundation, please see <http://www.apache.org/>.
49   * ==================================================================== Modified
50   * by Tassos Bassoukos (abas@aix.meng.auth.gr).
51   */
52  
53  import java.io.File;
54  import java.io.FileNotFoundException;
55  import java.io.InputStream;
56  import java.io.Reader;
57  import java.io.StringWriter;
58  import java.io.Writer;
59  import java.util.HashMap;
60  import java.util.Map;
61  
62  import javax.xml.transform.Result;
63  import javax.xml.transform.Source;
64  import javax.xml.transform.Templates;
65  import javax.xml.transform.Transformer;
66  import javax.xml.transform.TransformerException;
67  import javax.xml.transform.TransformerFactory;
68  import javax.xml.transform.URIResolver;
69  import javax.xml.transform.dom.DOMSource;
70  import javax.xml.transform.stream.StreamResult;
71  import javax.xml.transform.stream.StreamSource;
72  
73  import net.sourceforge.blogentis.om.Blog;
74  import net.sourceforge.blogentis.storage.FileRetrieverService;
75  
76  import org.apache.commons.configuration.Configuration;
77  import org.apache.commons.lang.StringUtils;
78  import org.apache.commons.logging.Log;
79  import org.apache.commons.logging.LogFactory;
80  import org.apache.turbine.services.InitializationException;
81  import org.apache.turbine.services.TurbineBaseService;
82  import org.apache.turbine.services.xslt.XSLTService;
83  import org.w3c.dom.Node;
84  
85  /***
86   * Implementation of the Turbine XSLT Service. It transforms xml with a given
87   * xsl file. XSL stylesheets are compiled and cached (if the property in
88   * TurbineResources.properties is set) to improve speeds.
89   * 
90   * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt </a>
91   * @author <a href="mailto:rubys@us.ibm.com">Sam Ruby </a>
92   */
93  public class BlogXSLTService
94          extends TurbineBaseService
95          implements XSLTService {
96  
97      private static class FileResolver
98              implements URIResolver {
99          private static Log log = LogFactory.getLog(FileResolver.class);
100 
101         public Source resolve(String href, String base)
102                 throws TransformerException {
103             log.info("Fetching " + href + " from " + base);
104             try {
105                 Blog blog = BlogRunDataService.getCurrentRunData().getBlog();
106                 return new StreamSource(FileRetrieverService.getInstance()
107                     .getFile(blog, href).getFileAsInputStream());
108             } catch (FileNotFoundException e) {
109                 throw new TransformerException(e);
110             }
111         }
112     }
113 
114     /***
115      * Property to control the caching of StyleSheetRoots.
116      */
117     protected boolean caching = false;
118 
119     /***
120      * Path to style sheets used for tranforming well-formed XML documents. The
121      * path is relative to the webapp context.
122      */
123     protected String path;
124 
125     /***
126      * Cache of compiled StyleSheetRoots.
127      */
128     protected Map cache = new HashMap();
129 
130     /***
131      * Factory for producing templates and null transformers
132      */
133     private static TransformerFactory tfactory;
134 
135     /***
136      * Initialize the TurbineXSLT Service. Load the path to search for xsl files
137      * and initiates the cache.
138      */
139     public void init()
140             throws InitializationException {
141         Configuration conf = getConfiguration();
142 
143         path = conf.getString(STYLESHEET_PATH, null);
144 
145         if (StringUtils.isNotEmpty(path)) {
146             if (!path.endsWith("/") && !path.endsWith("//")) {
147                 path = path + File.separator;
148             }
149         }
150 
151         caching = conf.getBoolean(STYLESHEET_CACHING);
152 
153         tfactory = TransformerFactory.newInstance();
154         tfactory.setURIResolver(new FileResolver());
155         setInit(true);
156     }
157 
158     /***
159      * Get a valid and existing filename from a template name. The extension is
160      * removed and replaced with .xsl. If this file does not exist the method
161      * attempts to find default.xsl. If it fails to find default.xsl it returns
162      * null.
163      */
164     protected String getFileName(String templateName) {
165         // First we chop of the existing extension
166         int colon = templateName.lastIndexOf(".");
167         if (colon > 0) {
168             templateName = templateName.substring(0, colon);
169         }
170         FileRetrieverService frs = FileRetrieverService.getInstance();
171         Blog blog = BlogRunDataService.getCurrentRunData().getBlog();
172 
173         // Now we try to find the file ...
174         String f = path + templateName + ".xsl";
175         if (frs.exists(blog, f)) {
176             return f;
177         } else {
178             // ... or the default file
179             if (frs.exists(blog, path + "default.xsl")) {
180                 return path + "default.xsl";
181             } else {
182                 return null;
183             }
184         }
185     }
186 
187     /***
188      * Compile Templates from an input file.
189      */
190     protected Templates compileTemplates(String source)
191             throws Exception {
192         Blog blog = BlogRunDataService.getCurrentRunData().getBlog();
193         InputStream fis = FileRetrieverService.getInstance().getFile(blog,
194                                                                      source)
195             .getFileAsInputStream();
196         Templates template = tfactory.newTemplates(new StreamSource(fis));
197         fis.close();
198         return template;
199     }
200 
201     /***
202      * Retrieves Templates. If caching is switched on the first attempt is to
203      * load the Templates from the cache. If caching is switched of or if the
204      * Stylesheet is not found in the cache a new StyleSheetRoot is compiled
205      * from an input file.
206      * <p>
207      * This method is synchronized on the xsl cache so that a thread does not
208      * attempt to load a StyleSheetRoot from the cache while it is still being
209      * compiled.
210      */
211     protected Templates getTemplates(String xslName)
212             throws Exception {
213         synchronized (cache) {
214             if (caching && cache.containsKey(xslName)) {
215                 return (Templates)cache.get(xslName);
216             }
217 
218             String fn = getFileName(xslName);
219 
220             if (fn == null)
221                 return null;
222 
223             Templates sr = compileTemplates(fn);
224 
225             if (caching) {
226                 cache.put(xslName, sr);
227             }
228 
229             return sr;
230         }
231 
232     }
233 
234     protected void transform(String xslName, Source xmlin, Result xmlout)
235             throws Exception {
236         Templates sr = getTemplates(xslName);
237         Transformer transformer;
238 
239         // If there is no stylesheet we just echo the xml
240         if (sr == null) {
241             transformer = tfactory.newTransformer();
242         } else {
243             transformer = sr.newTransformer();
244         }
245 
246         transformer.transform(xmlin, xmlout);
247     }
248 
249     /***
250      * Execute an xslt
251      */
252     public void transform(String xslName, Reader in, Writer out)
253             throws Exception {
254         Source xmlin = new StreamSource(in);
255         Result xmlout = new StreamResult(out);
256 
257         transform(xslName, xmlin, xmlout);
258     }
259 
260     /***
261      * Execute an xslt
262      */
263     public String transform(String xslName, Reader in)
264             throws Exception {
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, Node in, Writer out)
274             throws Exception {
275         Source xmlin = new DOMSource(in);
276         Result xmlout = new StreamResult(out);
277 
278         transform(xslName, xmlin, xmlout);
279     }
280 
281     /***
282      * Execute an xslt
283      */
284     public String transform(String xslName, Node in)
285             throws Exception {
286         StringWriter sw = new StringWriter();
287         transform(xslName, in, sw);
288         return sw.toString();
289     }
290 }