1
20 package org.crosswire.common.xml;
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.URI;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Properties;
28
29 import javax.xml.transform.ErrorListener;
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.TransformerConfigurationException;
35 import javax.xml.transform.TransformerException;
36 import javax.xml.transform.TransformerFactory;
37 import javax.xml.transform.URIResolver;
38 import javax.xml.transform.sax.SAXResult;
39 import javax.xml.transform.sax.SAXSource;
40 import javax.xml.transform.stream.StreamSource;
41
42 import org.crosswire.common.util.IOUtil;
43 import org.crosswire.common.util.NetUtil;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import org.xml.sax.ContentHandler;
47 import org.xml.sax.SAXException;
48
49
56 public class TransformingSAXEventProvider extends Transformer implements SAXEventProvider {
57
63 public TransformingSAXEventProvider(URI xsluri, SAXEventProvider xmlsep) {
64 this.xsluri = xsluri;
65 this.xmlsep = xmlsep;
66 this.outputs = new Properties();
67 this.params = new HashMap<String, Object>();
68 }
69
70
77 private TemplateInfo getTemplateInfo() throws TransformerConfigurationException, IOException {
78 TemplateInfo tinfo = txers.get(xsluri);
80
81 long modtime = -1;
82 if (TransformingSAXEventProvider.developmentMode) {
83 if (tinfo != null) {
84 modtime = NetUtil.getLastModified(xsluri);
85
86 if (modtime > tinfo.getModtime()) {
88 txers.remove(xsluri);
89 tinfo = null;
90 log.debug("updated style, re-caching. xsl={}", xsluri);
91 }
92 }
93 }
94
95 if (tinfo == null) {
96 log.debug("generating templates for {}", xsluri);
97
98 InputStream xslStream = null;
99 try {
100 xslStream = NetUtil.getInputStream(xsluri);
101 if (transfact == null) {
102 transfact = TransformerFactory.newInstance();
103 }
104 Templates templates = transfact.newTemplates(new StreamSource(xslStream));
105
106 if (modtime == -1) {
107 modtime = NetUtil.getLastModified(xsluri);
108 }
109
110 tinfo = new TemplateInfo(templates, modtime);
111
112 txers.put(xsluri, tinfo);
113 } finally {
114 IOUtil.close(xslStream);
115 }
116 }
117
118 return tinfo;
119 }
120
121
124 @Override
125 public void transform(Source xmlSource, Result outputTarget) throws TransformerException {
126 TemplateInfo tinfo;
127 try {
128 tinfo = getTemplateInfo();
129 } catch (IOException e) {
130 throw new TransformerException(e);
131 }
132
133 Transformer transformer = tinfo.getTemplates().newTransformer();
134
135 for (Object obj : outputs.keySet()) {
136 String key = (String) obj;
137 String val = getOutputProperty(key);
138 transformer.setOutputProperty(key, val);
139 }
140
141 for (String key : params.keySet()) {
142 Object val = params.get(key);
143 transformer.setParameter(key, val);
144 }
145
146 if (errors != null) {
147 transformer.setErrorListener(errors);
148 }
149
150 if (resolver != null) {
151 transformer.setURIResolver(resolver);
152 }
153
154 transformer.transform(xmlSource, outputTarget);
155 }
156
157
160 public void provideSAXEvents(ContentHandler handler) throws SAXException {
161 try {
162 Source xmlSource = new SAXSource(new SAXEventProviderXMLReader(xmlsep), new SAXEventProviderInputSource());
163
164 SAXResult outputTarget = new SAXResult(handler);
165
166 transform(xmlSource, outputTarget);
167 } catch (TransformerException ex) {
168 throw new SAXException(ex);
169 }
170 }
171
172
175 @Override
176 public ErrorListener getErrorListener() {
177 return errors;
178 }
179
180
183 @Override
184 public void setErrorListener(ErrorListener errors) throws IllegalArgumentException {
185 this.errors = errors;
186 }
187
188
191 @Override
192 public URIResolver getURIResolver() {
193 return resolver;
194 }
195
196
199 @Override
200 public void setURIResolver(URIResolver resolver) {
201 this.resolver = resolver;
202 }
203
204
207 @Override
208 public Properties getOutputProperties() {
209 return outputs;
210 }
211
212
215 @Override
216 public void setOutputProperties(Properties outputs) throws IllegalArgumentException {
217 this.outputs = outputs;
218 }
219
220
223 @Override
224 public String getOutputProperty(String name) throws IllegalArgumentException {
225 return outputs.getProperty(name);
226 }
227
228
231 @Override
232 public void setOutputProperty(String name, String value) throws IllegalArgumentException {
233 outputs.setProperty(name, value);
234 }
235
236
239 @Override
240 public void clearParameters() {
241 params.clear();
242 }
243
244
247 @Override
248 public Object getParameter(String name) {
249 return params.get(name);
250 }
251
252
255 @Override
256 public void setParameter(String name, Object value) {
257 params.put(name, value);
258 }
259
260
265 public static void setDevelopmentMode(boolean developmentMode) {
266 TransformingSAXEventProvider.developmentMode = developmentMode;
267 }
268
269
274 public static boolean isDevelopmentMode() {
275 return developmentMode;
276 }
277
278
281 private static class TemplateInfo {
282
288 TemplateInfo(Templates templates, long modtime) {
289 this.templates = templates;
290 this.modtime = modtime;
291 }
292
293
298 Templates getTemplates() {
299 return templates;
300 }
301
302
307 long getModtime() {
308 return modtime;
309 }
310
311 private Templates templates;
312 private long modtime;
313 }
314
315
318 private static boolean developmentMode;
319
320
323 private ErrorListener errors;
324
325
328 private URIResolver resolver;
329
330
334 private Properties outputs;
335
336
339 private Map<String, Object> params;
340
341
344 private URI xsluri;
345
346
349 private SAXEventProvider xmlsep;
350
351
354 private TransformerFactory transfact;
355
356
359 private static Map<URI, TemplateInfo> txers = new HashMap<URI, TemplateInfo>();
360
361
364 private static final Logger log = LoggerFactory.getLogger(TransformingSAXEventProvider.class);
365 }
366