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