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 returnType = new SimpleDataType<Object>(newClass);
258 returnType.setMimeType(mimeType);
259 returnType.setEncoding(encoding);
260 }
261
262 public void setMimeType(String mimeType) throws MimeTypeParseException
263 {
264 if (mimeType == null)
265 {
266 this.mimeType = null;
267 }
268 else
269 {
270 MimeType mt = new MimeType(mimeType);
271 this.mimeType = mt.getPrimaryType() + "/" + mt.getSubType();
272 }
273 if (returnType != null)
274 {
275 returnType.setMimeType(mimeType);
276 }
277 }
278
279 public String getMimeType()
280 {
281 return mimeType;
282 }
283
284 public String getEncoding()
285 {
286 return encoding;
287 }
288
289 public void setEncoding(String encoding)
290 {
291 this.encoding = encoding;
292 if (returnType != null)
293 {
294 returnType.setEncoding(encoding);
295 }
296 }
297
298 public boolean isAllowNullReturn()
299 {
300 return allowNullReturn;
301 }
302
303 public void setAllowNullReturn(boolean allowNullReturn)
304 {
305 this.allowNullReturn = allowNullReturn;
306 }
307
308 @Deprecated
309 public boolean isSourceTypeSupported(Class<?> aClass)
310 {
311 return isSourceDataTypeSupported(DataTypeFactory.create(aClass), false);
312 }
313
314 public boolean isSourceDataTypeSupported(DataType<?> dataType)
315 {
316 return isSourceDataTypeSupported(dataType, false);
317 }
318
319
320
321
322
323
324
325
326
327
328 @Deprecated
329 public boolean isSourceTypeSupported(Class<MuleMessage> aClass, boolean exactMatch)
330 {
331 return isSourceDataTypeSupported(new SimpleDataType<MuleMessage>(aClass), exactMatch);
332 }
333
334
335
336
337
338
339
340
341
342 public boolean isSourceDataTypeSupported(DataType<?> dataType, boolean exactMatch)
343 {
344 int numTypes = sourceTypes.size();
345
346 if (numTypes == 0)
347 {
348 return !exactMatch;
349 }
350
351 for (DataType<?> sourceType : sourceTypes)
352 {
353 if (exactMatch)
354 {
355 if (sourceType.equals(dataType))
356 {
357 return true;
358 }
359 }
360 else
361 {
362 if (sourceType.isCompatibleWith(dataType))
363 {
364 return true;
365 }
366 }
367 }
368 return false;
369 }
370
371 public final Object transform(Object src) throws TransformerException
372 {
373 return transform(src, getEncoding(src));
374 }
375
376 public Object transform(Object src, String enc) throws TransformerException
377 {
378 Object payload = src;
379 if (src instanceof MuleMessage)
380 {
381 MuleMessage message = (MuleMessage) src;
382 if ((!isSourceDataTypeSupported(MULE_MESSAGE_DATA_TYPE, true) &&
383 !(this instanceof AbstractMessageTransformer)))
384 {
385 src = ((MuleMessage) src).getPayload();
386 payload = message.getPayload();
387 }
388 }
389
390 DataType<?> sourceType = DataTypeFactory.create(payload.getClass());
391
392
393
394
395
396
397
398
399 if (!isSourceDataTypeSupported(sourceType))
400 {
401 if (ignoreBadInput)
402 {
403 logger.debug("Source type is incompatible with this transformer and property 'ignoreBadInput' is set to true, so the transformer chain will continue.");
404 return payload;
405 }
406 else
407 {
408 Message msg = CoreMessages.transformOnObjectUnsupportedTypeOfEndpoint(getName(),
409 payload.getClass(), endpoint);
410
411 throw new TransformerException(msg, this);
412 }
413 }
414
415 if (logger.isDebugEnabled())
416 {
417 logger.debug(String.format("Applying transformer %s (%s)", getName(), getClass().getName()));
418 logger.debug(String.format("Object before transform: %s", StringMessageUtils.toString(payload)));
419 }
420
421 Object result = doTransform(payload, enc);
422
423 if (result == null)
424 {
425 result = NullPayload.getInstance();
426 }
427
428 if (logger.isDebugEnabled())
429 {
430 logger.debug(String.format("Object after transform: %s", StringMessageUtils.toString(result)));
431 }
432
433 result = checkReturnClass(result);
434 return result;
435 }
436
437 protected String getEncoding(Object src)
438 {
439 String enc = null;
440 if (src instanceof MuleMessage)
441 {
442 enc = ((MuleMessage) src).getEncoding();
443 }
444
445 if (enc == null && endpoint != null)
446 {
447 enc = endpoint.getEncoding();
448 }
449 else if (enc == null)
450 {
451 enc = System.getProperty(MuleProperties.MULE_ENCODING_SYSTEM_PROPERTY);
452 }
453 return enc;
454 }
455
456 protected boolean isConsumed(Class<?> srcCls)
457 {
458 return InputStream.class.isAssignableFrom(srcCls) || StreamSource.class.isAssignableFrom(srcCls);
459 }
460
461 public ImmutableEndpoint getEndpoint()
462 {
463 return endpoint;
464 }
465
466 public void setEndpoint(ImmutableEndpoint endpoint)
467 {
468 this.endpoint = endpoint;
469 }
470
471 protected abstract Object doTransform(Object src, String enc) throws TransformerException;
472
473
474
475
476
477
478
479 public void initialise() throws InitialisationException
480 {
481
482 }
483
484
485
486
487
488 public void dispose()
489 {
490
491 }
492
493 protected String generateTransformerName()
494 {
495 String transformerName = ClassUtils.getSimpleName(this.getClass());
496 int i = transformerName.indexOf("To");
497 if (i > 0 && returnType != null)
498 {
499 String target = ClassUtils.getSimpleName(returnType.getType());
500 if (target.equals("byte[]"))
501 {
502 target = "byteArray";
503 }
504 transformerName = transformerName.substring(0, i + 2) + StringUtils.capitalize(target);
505 }
506 return transformerName;
507 }
508
509 @Deprecated
510 public List<Class<?>> getSourceTypes()
511 {
512
513 List<Class<?>> sourceClasses = new ArrayList<Class<?>>();
514 for (DataType<?> sourceType : sourceTypes)
515 {
516 sourceClasses.add(sourceType.getType());
517 }
518 return Collections.unmodifiableList(sourceClasses);
519 }
520
521 public List<DataType<?>> getSourceDataTypes()
522 {
523 return Collections.unmodifiableList(sourceTypes);
524 }
525
526 public boolean isIgnoreBadInput()
527 {
528 return ignoreBadInput;
529 }
530
531 public void setIgnoreBadInput(boolean ignoreBadInput)
532 {
533 this.ignoreBadInput = ignoreBadInput;
534 }
535
536 @Override
537 public String toString()
538 {
539 StringBuffer sb = new StringBuffer(80);
540 sb.append(ClassUtils.getSimpleName(this.getClass()));
541 sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
542 sb.append(", name='").append(name).append('\'');
543 sb.append(", ignoreBadInput=").append(ignoreBadInput);
544 sb.append(", returnClass=").append(returnType);
545 sb.append(", sourceTypes=").append(sourceTypes);
546 sb.append('}');
547 return sb.toString();
548 }
549
550 public boolean isAcceptNull()
551 {
552 return false;
553 }
554
555 public void setMuleContext(MuleContext context)
556 {
557 this.muleContext = context;
558 try
559 {
560 muleContext.registerListener(this);
561 }
562 catch (NotificationException e)
563 {
564 logger.error("failed to register context listener", e);
565 }
566 }
567
568 public void onNotification(MuleContextNotification notification)
569 {
570 if (notification.getAction() == MuleContextNotification.CONTEXT_DISPOSING)
571 {
572 this.dispose();
573 }
574 }
575 }