1
2
3
4
5
6
7 package org.mule.module.xml.transformer;
8
9 import org.mule.api.MuleMessage;
10 import org.mule.api.lifecycle.InitialisationException;
11 import org.mule.api.transformer.Transformer;
12 import org.mule.api.transformer.TransformerException;
13 import org.mule.config.i18n.CoreMessages;
14 import org.mule.module.xml.util.LocalURIResolver;
15 import org.mule.module.xml.util.XMLUtils;
16 import org.mule.util.ClassUtils;
17 import org.mule.util.IOUtils;
18 import org.mule.util.StringUtils;
19
20 import java.io.StringReader;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.Map;
24 import java.util.Map.Entry;
25
26 import javax.xml.transform.ErrorListener;
27 import javax.xml.transform.OutputKeys;
28 import javax.xml.transform.Result;
29 import javax.xml.transform.Source;
30 import javax.xml.transform.TransformerFactory;
31 import javax.xml.transform.TransformerFactoryConfigurationError;
32 import javax.xml.transform.URIResolver;
33 import javax.xml.transform.stream.StreamSource;
34
35 import org.apache.commons.pool.BasePoolableObjectFactory;
36 import org.apache.commons.pool.impl.GenericObjectPool;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 public class XsltTransformer extends AbstractXmlTransformer
89 {
90
91 private static final int MIN_IDLE_TRANSFORMERS = 1;
92
93 private static final int MAX_IDLE_TRANSFORMERS = 32;
94
95 private static final int MAX_ACTIVE_TRANSFORMERS = MAX_IDLE_TRANSFORMERS;
96
97
98 public static final String PREFERRED_TRANSFORMER_FACTORY = "net.sf.saxon.TransformerFactoryImpl";
99
100 protected final GenericObjectPool transformerPool;
101
102
103
104
105 private volatile String xslTransformerFactoryClassName = PREFERRED_TRANSFORMER_FACTORY;
106 private volatile String xslFile;
107 private volatile String xslt;
108 private volatile Map contextProperties;
109
110 private URIResolver uriResolver;
111
112 public XsltTransformer()
113 {
114 super();
115 transformerPool = new GenericObjectPool(new PooledXsltTransformerFactory());
116 transformerPool.setMinIdle(MIN_IDLE_TRANSFORMERS);
117 transformerPool.setMaxIdle(MAX_IDLE_TRANSFORMERS);
118 transformerPool.setMaxActive(MAX_ACTIVE_TRANSFORMERS);
119 uriResolver = new LocalURIResolver();
120 contextProperties = new HashMap();
121 }
122
123 public XsltTransformer(String xslFile)
124 {
125 this();
126 this.setXslFile(xslFile);
127 }
128
129 @Override
130 public void initialise() throws InitialisationException
131 {
132 logger.debug("Initialising transformer: " + this);
133 try
134 {
135
136 if (xslFile != null)
137 {
138 this.xslt = IOUtils.getResourceAsString(xslFile, getClass());
139 }
140 transformerPool.addObject();
141 }
142 catch (Throwable te)
143 {
144 throw new InitialisationException(te, this);
145 }
146 }
147
148
149
150
151
152
153 @Override
154 public Object transformMessage(MuleMessage message, String encoding) throws TransformerException
155 {
156 Object src = message.getPayload();
157 try
158 {
159 Source sourceDoc = XMLUtils.toXmlSource(getXMLInputFactory(), isUseStaxSource(), src);
160 if (sourceDoc == null)
161 {
162 return null;
163 }
164
165 ResultHolder holder = getResultHolder(returnType.getType());
166
167
168 if (holder == null)
169 {
170 holder = getResultHolder(src.getClass());
171 }
172
173
174
175 if (holder == null || DelayedResult.class.equals(returnType.getType()))
176 {
177 return getDelayedResult(message, encoding, sourceDoc);
178 }
179
180 doTransform(message, encoding, sourceDoc, holder.getResult());
181
182 return holder.getResultObject();
183 }
184 catch (Exception e)
185 {
186 throw new TransformerException(this, e);
187 }
188 }
189
190 protected Object getDelayedResult(final MuleMessage message, final String encoding, final Source sourceDoc)
191 {
192 return new DelayedResult()
193 {
194 private String systemId;
195
196 public void write(Result result) throws Exception
197 {
198 doTransform(message, encoding, sourceDoc, result);
199 }
200
201 public String getSystemId()
202 {
203 return systemId;
204 }
205
206 public void setSystemId(String systemId)
207 {
208 this.systemId = systemId;
209 }
210 };
211 }
212
213 protected void doTransform(MuleMessage message, String encoding, Source sourceDoc, Result result)
214 throws Exception
215 {
216 DefaultErrorListener errorListener = new DefaultErrorListener(this);
217 javax.xml.transform.Transformer transformer = null;
218
219 try
220 {
221 transformer = (javax.xml.transform.Transformer) transformerPool.borrowObject();
222
223 transformer.setErrorListener(errorListener);
224 transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
225
226
227 if (contextProperties != null)
228 {
229 for (Iterator i = contextProperties.entrySet().iterator(); i.hasNext();)
230 {
231 Map.Entry parameter = (Entry) i.next();
232 String key = (String) parameter.getKey();
233 transformer.setParameter(key, evaluateTransformParameter(key, parameter.getValue(), message));
234 }
235 }
236
237 transformer.transform(sourceDoc, result);
238
239 if (errorListener.isError())
240 {
241 throw errorListener.getException();
242 }
243 }
244 finally
245 {
246 if (transformer != null)
247 {
248
249
250 transformer.clearParameters();
251
252 transformerPool.returnObject(transformer);
253 }
254 }
255 }
256
257
258
259
260
261
262
263
264 public String getXslTransformerFactory()
265 {
266 return xslTransformerFactoryClassName;
267 }
268
269
270
271
272
273
274 public void setXslTransformerFactory(String xslTransformerFactory)
275 {
276 this.xslTransformerFactoryClassName = xslTransformerFactory;
277 }
278
279
280
281
282 public String getXslFile()
283 {
284 return xslFile;
285 }
286
287
288
289
290 public void setXslFile(String xslFile)
291 {
292 this.xslFile = xslFile;
293 }
294
295 public String getXslt()
296 {
297 return xslt;
298 }
299
300 public void setXslt(String xslt)
301 {
302 this.xslt = xslt;
303 }
304
305 public URIResolver getUriResolver()
306 {
307 return uriResolver;
308 }
309
310 public void setUriResolver(URIResolver uriResolver)
311 {
312 this.uriResolver = uriResolver;
313 }
314
315
316
317
318
319
320
321 protected StreamSource getStreamSource() throws InitialisationException
322 {
323 if (xslt == null)
324 {
325 throw new InitialisationException(CoreMessages.propertiesNotSet("xsl-file or xsl-text"), this);
326 }
327 else
328 {
329 return new StreamSource(new StringReader(xslt));
330 }
331 }
332
333 protected class PooledXsltTransformerFactory extends BasePoolableObjectFactory
334 {
335 @Override
336 public Object makeObject() throws Exception
337 {
338 StreamSource source = XsltTransformer.this.getStreamSource();
339 String factoryClassName = XsltTransformer.this.getXslTransformerFactory();
340 TransformerFactory factory;
341
342 if (PREFERRED_TRANSFORMER_FACTORY.equals(factoryClassName) && !ClassUtils.isClassOnPath(factoryClassName, getClass()))
343 {
344 logger.warn("Preferred Transfomer Factory " + PREFERRED_TRANSFORMER_FACTORY + " not on classpath and no default is set, defaulting to JDK");
345 factoryClassName = null;
346 }
347
348 if (StringUtils.isNotEmpty(factoryClassName))
349 {
350
351 factory = (TransformerFactory) ClassUtils.instanciateClass(factoryClassName,
352 ClassUtils.NO_ARGS, this.getClass());
353 }
354 else
355 {
356
357 try
358 {
359 factory = TransformerFactory.newInstance();
360 }
361 catch (TransformerFactoryConfigurationError e)
362 {
363 System.setProperty("javax.xml.transform.TransformerFactory", XMLUtils.TRANSFORMER_FACTORY_JDK5);
364 factory = TransformerFactory.newInstance();
365 }
366 }
367
368 factory.setURIResolver(getUriResolver());
369 return factory.newTransformer(source);
370 }
371 }
372
373 protected class DefaultErrorListener implements ErrorListener
374 {
375 private TransformerException e = null;
376 private final Transformer trans;
377
378 public DefaultErrorListener(Transformer trans)
379 {
380 this.trans = trans;
381 }
382
383 public TransformerException getException()
384 {
385 return e;
386 }
387
388 public boolean isError()
389 {
390 return e != null;
391 }
392
393 public void error(javax.xml.transform.TransformerException exception)
394 throws javax.xml.transform.TransformerException
395 {
396 e = new TransformerException(trans, exception);
397 }
398
399 public void fatalError(javax.xml.transform.TransformerException exception)
400 throws javax.xml.transform.TransformerException
401 {
402 e = new TransformerException(trans, exception);
403 }
404
405 public void warning(javax.xml.transform.TransformerException exception)
406 throws javax.xml.transform.TransformerException
407 {
408 logger.warn(exception.getMessage());
409 }
410 }
411
412
413
414
415
416 public int getMaxActiveTransformers()
417 {
418 return transformerPool.getMaxActive();
419 }
420
421
422
423
424
425
426
427 public void setMaxActiveTransformers(int maxActiveTransformers)
428 {
429 transformerPool.setMaxActive(maxActiveTransformers);
430 }
431
432
433
434
435
436 public int getMaxIdleTransformers()
437 {
438 return transformerPool.getMaxIdle();
439 }
440
441
442
443
444
445
446 public void setMaxIdleTransformers(int maxIdleTransformers)
447 {
448 transformerPool.setMaxIdle(maxIdleTransformers);
449 }
450
451
452
453
454
455
456
457
458 public Map getContextProperties()
459 {
460 return contextProperties;
461 }
462
463
464
465
466
467
468
469
470 public void setContextProperties(Map contextProperties)
471 {
472 this.contextProperties = contextProperties;
473 }
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488 protected Object evaluateTransformParameter(String name, Object value, MuleMessage message) throws TransformerException
489 {
490 if (value instanceof String)
491 {
492 return muleContext.getExpressionManager().parse(value.toString(), message);
493 }
494
495 return value;
496 }
497 }