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