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