1 package org.apache.turbine.services.xslt;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
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 }