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.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
115 int colon = templateName.lastIndexOf(".");
116 if (colon > 0)
117 {
118 templateName = templateName.substring(0, colon);
119 }
120
121
122 File f = new File(path + templateName + ".xsl");
123 if (f.exists())
124 {
125 return path + templateName + ".xsl";
126 }
127 else
128 {
129
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
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 }