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.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
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
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 }