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