1
2
3
4
5
6
7
8
9
10
11 package org.mule.transformer;
12
13 import org.mule.api.MuleContext;
14 import org.mule.api.MuleEvent;
15 import org.mule.api.MuleException;
16 import org.mule.api.MuleMessage;
17 import org.mule.api.config.MuleProperties;
18 import org.mule.api.context.notification.MuleContextNotificationListener;
19 import org.mule.api.endpoint.ImmutableEndpoint;
20 import org.mule.api.lifecycle.InitialisationException;
21 import org.mule.api.transformer.DataType;
22 import org.mule.api.transformer.Transformer;
23 import org.mule.api.transformer.TransformerException;
24 import org.mule.api.transformer.TransformerMessagingException;
25 import org.mule.config.i18n.CoreMessages;
26 import org.mule.config.i18n.Message;
27 import org.mule.context.notification.MuleContextNotification;
28 import org.mule.context.notification.NotificationException;
29 import org.mule.transformer.types.DataTypeFactory;
30 import org.mule.transformer.types.SimpleDataType;
31 import org.mule.transport.NullPayload;
32 import org.mule.util.ClassUtils;
33 import org.mule.util.StringMessageUtils;
34 import org.mule.util.StringUtils;
35
36 import java.io.InputStream;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.List;
40
41 import javax.activation.MimeType;
42 import javax.activation.MimeTypeParseException;
43 import javax.xml.transform.stream.StreamSource;
44
45 import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
46
47 import org.apache.commons.logging.Log;
48 import org.apache.commons.logging.LogFactory;
49
50
51
52
53
54
55 public abstract class AbstractTransformer implements Transformer, MuleContextNotificationListener<MuleContextNotification>
56 {
57 public static final DataType<MuleMessage> MULE_MESSAGE_DATA_TYPE = new SimpleDataType<MuleMessage>(MuleMessage.class);
58
59 protected MuleContext muleContext;
60
61 protected final Log logger = LogFactory.getLog(getClass());
62
63
64
65
66
67 protected DataType<?> returnType = new SimpleDataType<Object>(Object.class);
68
69
70
71
72
73 protected String name = null;
74
75
76
77
78 protected ImmutableEndpoint endpoint = null;
79
80
81
82
83
84 @SuppressWarnings("unchecked")
85 protected final List<DataType<?>> sourceTypes = new CopyOnWriteArrayList
86
87
88
89
90
91 private boolean ignoreBadInput = false;
92
93
94
95
96 private boolean allowNullReturn = false;
97
98
99
100
101 protected String mimeType;
102 protected String encoding;
103
104
105
106
107 public AbstractTransformer()
108 {
109 super();
110 }
111
112 public MuleEvent process(MuleEvent event) throws MuleException
113 {
114 if (event != null && event.getMessage() != null)
115 {
116 try
117 {
118 event.getMessage().applyTransformers(event, this);
119 }
120 catch (TransformerException e)
121 {
122 throw new TransformerMessagingException(e.getI18nMessage(), event, this, e);
123 }
124 }
125 return event;
126 }
127
128 protected Object checkReturnClass(Object object) throws TransformerException
129 {
130
131 if(object==null || object instanceof NullPayload && isAllowNullReturn())
132 {
133 return object;
134 }
135
136 if (returnType != null)
137 {
138 DataType<?> dt = DataTypeFactory.create(object.getClass());
139 if (!returnType.isCompatibleWith(dt))
140 {
141 throw new TransformerException(
142 CoreMessages.transformUnexpectedType(dt, returnType),
143 this);
144 }
145 }
146
147 if (logger.isDebugEnabled())
148 {
149 logger.debug("The transformed object is of expected type. Type is: " +
150 ClassUtils.getSimpleName(object.getClass()));
151 }
152
153 return object;
154 }
155
156
157
158
159
160
161
162
163 @Deprecated
164 protected void registerSourceType(Class<?> aClass)
165 {
166 registerSourceType(new SimpleDataType<Object>(aClass));
167 }
168
169
170
171
172
173
174
175 @Deprecated
176 protected void unregisterSourceType(Class<?> aClass)
177 {
178 unregisterSourceType(new SimpleDataType<Object>(aClass));
179 }
180
181
182
183
184
185
186
187 protected void registerSourceType(DataType<?> dataType)
188 {
189 if (!sourceTypes.contains(dataType))
190 {
191 sourceTypes.add(dataType);
192
193 if (dataType.getType().equals(Object.class))
194 {
195 logger.debug("java.lang.Object has been added as source type for this transformer, there will be no source type checking performed");
196 }
197 }
198 }
199
200
201
202
203
204
205 protected void unregisterSourceType(DataType<?> dataType)
206 {
207 sourceTypes.remove(dataType);
208 }
209
210
211
212
213 public String getName()
214 {
215 if (name == null)
216 {
217 name = this.generateTransformerName();
218 }
219 return name;
220 }
221
222
223
224
225 public void setName(String string)
226 {
227 if (string == null)
228 {
229 string = ClassUtils.getSimpleName(this.getClass());
230 }
231
232 logger.debug("Setting transformer name to: " + string);
233 name = string;
234 }
235
236 @Deprecated
237 public Class<?> getReturnClass()
238 {
239 return returnType.getType();
240 }
241
242 public void setReturnDataType(DataType<?> type)
243 {
244 this.returnType = type.cloneDataType();
245 this.encoding = type.getEncoding();
246 this.mimeType = type.getMimeType();
247 }
248
249 public DataType<?> getReturnDataType()
250 {
251 return returnType;
252 }
253
254 @Deprecated
255 public void setReturnClass(Class<?> newClass)
256 {
257 DataType<?> tempReturnType = new SimpleDataType<Object>(newClass);
258 tempReturnType.setMimeType(mimeType);
259 tempReturnType.setEncoding(encoding);
260 setReturnDataType(tempReturnType);
261 }
262
263 public void setMimeType(String mimeType) throws MimeTypeParseException
264 {
265 if (mimeType == null)
266 {
267 this.mimeType = null;
268 }
269 else
270 {
271 MimeType mt = new MimeType(mimeType);
272 this.mimeType = mt.getPrimaryType() + "/" + mt.getSubType();
273 }
274 if (returnType != null)
275 {
276 returnType.setMimeType(mimeType);
277 }
278 }
279
280 public String getMimeType()
281 {
282 return mimeType;
283 }
284
285 public String getEncoding()
286 {
287 return encoding;
288 }
289
290 public void setEncoding(String encoding)
291 {
292 this.encoding = encoding;
293 if (returnType != null)
294 {
295 returnType.setEncoding(encoding);
296 }
297 }
298
299 public boolean isAllowNullReturn()
300 {
301 return allowNullReturn;
302 }
303
304 public void setAllowNullReturn(boolean allowNullReturn)
305 {
306 this.allowNullReturn = allowNullReturn;
307 }
308
309 @Deprecated
310 public boolean isSourceTypeSupported(Class<?> aClass)
311 {
312 return isSourceDataTypeSupported(DataTypeFactory.create(aClass), false);
313 }
314
315 public boolean isSourceDataTypeSupported(DataType<?> dataType)
316 {
317 return isSourceDataTypeSupported(dataType, false);
318 }
319
320
321
322
323
324
325
326
327
328
329 @Deprecated
330 public boolean isSourceTypeSupported(Class<MuleMessage> aClass, boolean exactMatch)
331 {
332 return isSourceDataTypeSupported(new SimpleDataType<MuleMessage>(aClass), exactMatch);
333 }
334
335
336
337
338
339
340
341
342
343 public boolean isSourceDataTypeSupported(DataType<?> dataType, boolean exactMatch)
344 {
345 int numTypes = sourceTypes.size();
346
347 if (numTypes == 0)
348 {
349 return !exactMatch;
350 }
351
352 for (DataType<?> sourceType : sourceTypes)
353 {
354 if (exactMatch)
355 {
356 if (sourceType.equals(dataType))
357 {
358 return true;
359 }
360 }
361 else
362 {
363 if (sourceType.isCompatibleWith(dataType))
364 {
365 return true;
366 }
367 }
368 }
369 return false;
370 }
371
372 public final Object transform(Object src) throws TransformerException
373 {
374 return transform(src, getEncoding(src));
375 }
376
377 public Object transform(Object src, String enc) throws TransformerException
378 {
379 Object payload = src;
380 if (src instanceof MuleMessage)
381 {
382 MuleMessage message = (MuleMessage) src;
383 if ((!isSourceDataTypeSupported(MULE_MESSAGE_DATA_TYPE, true) &&
384 !(this instanceof AbstractMessageTransformer)))
385 {
386 src = ((MuleMessage) src).getPayload();
387 payload = message.getPayload();
388 }
389 }
390
391 DataType<?> sourceType = DataTypeFactory.create(payload.getClass());
392
393
394
395
396
397
398
399
400 if (!isSourceDataTypeSupported(sourceType))
401 {
402 if (ignoreBadInput)
403 {
404 logger.debug("Source type is incompatible with this transformer and property 'ignoreBadInput' is set to true, so the transformer chain will continue.");
405 return payload;
406 }
407 else
408 {
409 Message msg = CoreMessages.transformOnObjectUnsupportedTypeOfEndpoint(getName(),
410 payload.getClass(), endpoint);
411
412 throw new TransformerException(msg, this);
413 }
414 }
415
416 if (logger.isDebugEnabled())
417 {
418 logger.debug(String.format("Applying transformer %s (%s)", getName(), getClass().getName()));
419 logger.debug(String.format("Object before transform: %s", StringMessageUtils.toString(payload)));
420 }
421
422 Object result = doTransform(payload, enc);
423
424 if (result == null)
425 {
426 result = NullPayload.getInstance();
427 }
428
429 if (logger.isDebugEnabled())
430 {
431 logger.debug(String.format("Object after transform: %s", StringMessageUtils.toString(result)));
432 }
433
434 result = checkReturnClass(result);
435 return result;
436 }
437
438 protected String getEncoding(Object src)
439 {
440 String enc = null;
441 if (src instanceof MuleMessage)
442 {
443 enc = ((MuleMessage) src).getEncoding();
444 }
445
446 if (enc == null && endpoint != null)
447 {
448 enc = endpoint.getEncoding();
449 }
450 else if (enc == null)
451 {
452 enc = System.getProperty(MuleProperties.MULE_ENCODING_SYSTEM_PROPERTY);
453 }
454 return enc;
455 }
456
457 protected boolean isConsumed(Class<?> srcCls)
458 {
459 return InputStream.class.isAssignableFrom(srcCls) || StreamSource.class.isAssignableFrom(srcCls);
460 }
461
462 public ImmutableEndpoint getEndpoint()
463 {
464 return endpoint;
465 }
466
467 public void setEndpoint(ImmutableEndpoint endpoint)
468 {
469 this.endpoint = endpoint;
470 }
471
472 protected abstract Object doTransform(Object src, String enc) throws TransformerException;
473
474
475
476
477
478
479
480 public void initialise() throws InitialisationException
481 {
482
483 }
484
485
486
487
488
489 public void dispose()
490 {
491
492 }
493
494 protected String generateTransformerName()
495 {
496 String transformerName = ClassUtils.getSimpleName(this.getClass());
497 int i = transformerName.indexOf("To");
498 if (i > 0 && returnType != null)
499 {
500 String target = ClassUtils.getSimpleName(returnType.getType());
501 if (target.equals("byte[]"))
502 {
503 target = "byteArray";
504 }
505 transformerName = transformerName.substring(0, i + 2) + StringUtils.capitalize(target);
506 }
507 return transformerName;
508 }
509
510 @Deprecated
511 public List<Class<?>> getSourceTypes()
512 {
513
514 List<Class<?>> sourceClasses = new ArrayList<Class<?>>();
515 for (DataType<?> sourceType : sourceTypes)
516 {
517 sourceClasses.add(sourceType.getType());
518 }
519 return Collections.unmodifiableList(sourceClasses);
520 }
521
522 public List<DataType<?>> getSourceDataTypes()
523 {
524 return Collections.unmodifiableList(sourceTypes);
525 }
526
527 public boolean isIgnoreBadInput()
528 {
529 return ignoreBadInput;
530 }
531
532 public void setIgnoreBadInput(boolean ignoreBadInput)
533 {
534 this.ignoreBadInput = ignoreBadInput;
535 }
536
537 @Override
538 public String toString()
539 {
540 StringBuffer sb = new StringBuffer(80);
541 sb.append(ClassUtils.getSimpleName(this.getClass()));
542 sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
543 sb.append(", name='").append(name).append('\'');
544 sb.append(", ignoreBadInput=").append(ignoreBadInput);
545 sb.append(", returnClass=").append(returnType);
546 sb.append(", sourceTypes=").append(sourceTypes);
547 sb.append('}');
548 return sb.toString();
549 }
550
551 public boolean isAcceptNull()
552 {
553 return false;
554 }
555
556 public void setMuleContext(MuleContext context)
557 {
558 this.muleContext = context;
559 try
560 {
561 muleContext.registerListener(this);
562 }
563 catch (NotificationException e)
564 {
565 logger.error("failed to register context listener", e);
566 }
567 }
568
569 public void onNotification(MuleContextNotification notification)
570 {
571 if (notification.getAction() == MuleContextNotification.CONTEXT_DISPOSING)
572 {
573 this.dispose();
574 }
575 }
576 }