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