1
21 package org.crosswire.common.xml;
22
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.net.URI;
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.Properties;
29
30 import javax.xml.transform.ErrorListener;
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.TransformerConfigurationException;
36 import javax.xml.transform.TransformerException;
37 import javax.xml.transform.TransformerFactory;
38 import javax.xml.transform.URIResolver;
39 import javax.xml.transform.sax.SAXResult;
40 import javax.xml.transform.sax.SAXSource;
41 import javax.xml.transform.stream.StreamSource;
42
43 import org.crosswire.common.util.IOUtil;
44 import org.crosswire.common.util.NetUtil;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.xml.sax.ContentHandler;
48 import org.xml.sax.SAXException;
49
50
58 public class TransformingSAXEventProvider extends Transformer implements SAXEventProvider {
59
62 public TransformingSAXEventProvider(URI xsluri, SAXEventProvider xmlsep) {
63 this.xsluri = xsluri;
64 this.xmlsep = xmlsep;
65 this.outputs = new Properties();
66 this.params = new HashMap<String, Object>();
67 }
68
69
74 private TemplateInfo getTemplateInfo() throws TransformerConfigurationException, IOException {
75 TemplateInfo tinfo = txers.get(xsluri);
77
78 long modtime = -1;
79 if (TransformingSAXEventProvider.developmentMode) {
80 if (tinfo != null) {
81 modtime = NetUtil.getLastModified(xsluri);
82
83 if (modtime > tinfo.getModtime()) {
85 txers.remove(xsluri);
86 tinfo = null;
87 log.debug("updated style, re-caching. xsl={}", xsluri);
88 }
89 }
90 }
91
92 if (tinfo == null) {
93 log.debug("generating templates for {}", xsluri);
94
95 InputStream xslStream = null;
96 try {
97 xslStream = NetUtil.getInputStream(xsluri);
98 if (transfact == null) {
99 transfact = TransformerFactory.newInstance();
100 }
101 Templates templates = transfact.newTemplates(new StreamSource(xslStream));
102
103 if (modtime == -1) {
104 modtime = NetUtil.getLastModified(xsluri);
105 }
106
107 tinfo = new TemplateInfo(templates, modtime);
108
109 txers.put(xsluri, tinfo);
110 } finally {
111 IOUtil.close(xslStream);
112 }
113 }
114
115 return tinfo;
116 }
117
118
125 @Override
126 public void transform(Source xmlSource, Result outputTarget) throws TransformerException {
127 TemplateInfo tinfo;
128 try {
129 tinfo = getTemplateInfo();
130 } catch (IOException e) {
131 throw new TransformerException(e);
132 }
133
134 Transformer transformer = tinfo.getTemplates().newTransformer();
135
136 for (Object obj : outputs.keySet()) {
137 String key = (String) obj;
138 String val = getOutputProperty(key);
139 transformer.setOutputProperty(key, val);
140 }
141
142 for (String key : params.keySet()) {
143 Object val = params.get(key);
144 transformer.setParameter(key, val);
145 }
146
147 if (errors != null) {
148 transformer.setErrorListener(errors);
149 }
150
151 if (resolver != null) {
152 transformer.setURIResolver(resolver);
153 }
154
155 transformer.transform(xmlSource, outputTarget);
156 }
157
158
165 public void provideSAXEvents(ContentHandler handler) throws SAXException {
166 try {
167 Source xmlSource = new SAXSource(new SAXEventProviderXMLReader(xmlsep), new SAXEventProviderInputSource());
168
169 SAXResult outputTarget = new SAXResult(handler);
170
171 transform(xmlSource, outputTarget);
172 } catch (TransformerException ex) {
173 throw new SAXException(ex);
174 }
175 }
176
177
180 @Override
181 public ErrorListener getErrorListener() {
182 return errors;
183 }
184
185
188 @Override
189 public void setErrorListener(ErrorListener errors) throws IllegalArgumentException {
190 this.errors = errors;
191 }
192
193
196 @Override
197 public URIResolver getURIResolver() {
198 return resolver;
199 }
200
201
204 @Override
205 public void setURIResolver(URIResolver resolver) {
206 this.resolver = resolver;
207 }
208
209
212 @Override
213 public Properties getOutputProperties() {
214 return outputs;
215 }
216
217
220 @Override
221 public void setOutputProperties(Properties outputs) throws IllegalArgumentException {
222 this.outputs = outputs;
223 }
224
225
228 @Override
229 public String getOutputProperty(String name) throws IllegalArgumentException {
230 return outputs.getProperty(name);
231 }
232
233
236 @Override
237 public void setOutputProperty(String name, String value) throws IllegalArgumentException {
238 outputs.setProperty(name, value);
239 }
240
241
244 @Override
245 public void clearParameters() {
246 params.clear();
247 }
248
249
252 @Override
253 public Object getParameter(String name) {
254 return params.get(name);
255 }
256
257
260 @Override
261 public void setParameter(String name, Object value) {
262 params.put(name, value);
263 }
264
265
268 public static void setDevelopmentMode(boolean developmentMode) {
269 TransformingSAXEventProvider.developmentMode = developmentMode;
270 }
271
272
276 public static boolean isDevelopmentMode() {
277 return developmentMode;
278 }
279
280
283 private static class TemplateInfo {
284
287 public TemplateInfo(Templates templates, long modtime) {
288 this.templates = templates;
289 this.modtime = modtime;
290 }
291
292
295 Templates getTemplates() {
296 return templates;
297 }
298
299
302 long getModtime() {
303 return modtime;
304 }
305
306 private Templates templates;
307 private long modtime;
308 }
309
310
313 private static boolean developmentMode;
314
315
318 private ErrorListener errors;
319
320
323 private URIResolver resolver;
324
325
329 private Properties outputs;
330
331
334 private Map<String, Object> params;
335
336
339 private URI xsluri;
340
341
344 private SAXEventProvider xmlsep;
345
346
349 private TransformerFactory transfact;
350
351
354 private static Map<URI, TemplateInfo> txers = new HashMap<URI, TemplateInfo>();
355
356
359 private static final Logger log = LoggerFactory.getLogger(TransformingSAXEventProvider.class);
360 }
361