1 package net.sourceforge.blogentis.turbine;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
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
174 String f = path + templateName + ".xsl";
175 if (frs.exists(blog, f)) {
176 return f;
177 } else {
178
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
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 }