1
2
3
4
5
6
7
8
9
10
11 package org.mule.transformer;
12
13 import org.mule.api.MuleMessage;
14 import org.mule.api.endpoint.ImmutableEndpoint;
15 import org.mule.api.lifecycle.InitialisationException;
16 import org.mule.api.transformer.Transformer;
17 import org.mule.api.transformer.TransformerException;
18 import org.mule.api.transport.MessageAdapter;
19 import org.mule.config.i18n.CoreMessages;
20 import org.mule.transport.NullPayload;
21 import org.mule.util.ClassUtils;
22 import org.mule.util.FileUtils;
23 import org.mule.util.StringMessageUtils;
24 import org.mule.util.StringUtils;
25
26 import java.io.InputStream;
27 import java.util.Collections;
28 import java.util.List;
29
30 import javax.xml.transform.stream.StreamSource;
31
32 import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37
38
39
40
41
42 public abstract class AbstractTransformer implements Transformer
43 {
44 protected static final int DEFAULT_TRUNCATE_LENGTH = 200;
45
46 protected final Log logger = LogFactory.getLog(getClass());
47
48
49
50
51
52 protected Class returnClass = Object.class;
53
54
55
56
57
58 protected String name = null;
59
60
61 protected ImmutableEndpoint endpoint = null;
62
63
64
65
66
67 protected final List sourceTypes = new CopyOnWriteArrayList();
68
69
70
71
72
73 private boolean ignoreBadInput = false;
74
75
76 public AbstractTransformer()
77 {
78 super();
79 }
80
81 protected Object checkReturnClass(Object object) throws TransformerException
82 {
83 if (returnClass != null)
84 {
85 if (!returnClass.isInstance(object))
86 {
87 throw new TransformerException(
88 CoreMessages.transformUnexpectedType(object.getClass(), returnClass),
89 this);
90 }
91 }
92
93 if (logger.isDebugEnabled())
94 {
95 logger.debug("The transformed object is of expected type. Type is: " +
96 ClassUtils.getSimpleName(object.getClass()));
97 }
98
99 return object;
100 }
101
102 protected void registerSourceType(Class aClass)
103 {
104 if (!sourceTypes.contains(aClass))
105 {
106 sourceTypes.add(aClass);
107
108 if (aClass.equals(Object.class))
109 {
110 logger.debug("java.lang.Object has been added as source type for this transformer, there will be no source type checking performed");
111 }
112 }
113 }
114
115 protected void unregisterSourceType(Class aClass)
116 {
117 sourceTypes.remove(aClass);
118 }
119
120
121 public String getName()
122 {
123 if (name == null)
124 {
125 name = this.generateTransformerName();
126 }
127 return name;
128 }
129
130
131 public void setName(String string)
132 {
133 if (string == null)
134 {
135 string = ClassUtils.getSimpleName(this.getClass());
136 }
137
138 logger.debug("Setting transformer name to: " + string);
139 name = string;
140 }
141
142
143
144
145
146
147 public Class getReturnClass()
148 {
149 return returnClass;
150 }
151
152
153
154
155
156
157 public void setReturnClass(Class newClass)
158 {
159 returnClass = newClass;
160 }
161
162 public boolean isSourceTypeSupported(Class aClass)
163 {
164 return isSourceTypeSupported(aClass, false);
165 }
166
167 public boolean isSourceTypeSupported(Class aClass, boolean exactMatch)
168 {
169 int numTypes = sourceTypes.size();
170
171 if (numTypes == 0)
172 {
173 return !exactMatch;
174 }
175
176 for (int i = 0; i < numTypes; i++)
177 {
178 Class anotherClass = (Class) sourceTypes.get(i);
179 if (exactMatch)
180 {
181 if (anotherClass.equals(aClass))
182 {
183 return true;
184 }
185 }
186 else if (anotherClass.isAssignableFrom(aClass))
187 {
188 return true;
189 }
190 }
191
192 return false;
193 }
194
195
196
197
198
199
200
201 public final Object transform(Object src) throws TransformerException
202 {
203 String encoding = null;
204
205 Object payload = src;
206 MessageAdapter adapter;
207 if (src instanceof MessageAdapter)
208 {
209 encoding = ((MessageAdapter) src).getEncoding();
210 adapter = (MessageAdapter) src;
211 if ((!isSourceTypeSupported(MessageAdapter.class, true)
212 && !isSourceTypeSupported(MuleMessage.class, true)
213 && !(this instanceof AbstractMessageAwareTransformer))
214 )
215 {
216 src = ((MessageAdapter) src).getPayload();
217 payload = adapter.getPayload();
218 }
219 }
220
221 if (encoding == null && endpoint != null)
222 {
223 encoding = endpoint.getEncoding();
224 }
225 else if (encoding == null)
226 {
227 encoding = FileUtils.DEFAULT_ENCODING;
228 }
229
230 Class srcCls = src.getClass();
231 if (!isSourceTypeSupported(srcCls))
232 {
233 if (ignoreBadInput)
234 {
235 logger.debug("Source type is incompatible with this transformer and property 'ignoreBadInput' is set to true, so the transformer chain will continue.");
236 return payload;
237 }
238 else
239 {
240 throw new TransformerException(
241 CoreMessages.transformOnObjectUnsupportedTypeOfEndpoint(this.getName(),
242 payload.getClass(), endpoint), this);
243 }
244 }
245
246 if (logger.isDebugEnabled())
247 {
248 logger.debug("Applying transformer " + getName() + " (" + getClass().getName() + ")");
249 logger.debug("Object before transform: "
250 + StringMessageUtils.truncate(StringMessageUtils.toString(payload), DEFAULT_TRUNCATE_LENGTH, false));
251 }
252
253 Object result;
254 result = doTransform(payload, encoding);
255
256 if (result == null)
257 {
258 result = NullPayload.getInstance();
259 }
260
261 if (logger.isDebugEnabled())
262 {
263 logger.debug("Object after transform: "
264 + StringMessageUtils.truncate(StringMessageUtils.toString(result), DEFAULT_TRUNCATE_LENGTH, false));
265 }
266
267 result = checkReturnClass(result);
268 return result;
269 }
270
271 protected boolean isConsumed(Class srcCls)
272 {
273 return InputStream.class.isAssignableFrom(srcCls) || StreamSource.class.isAssignableFrom(srcCls);
274 }
275
276 public ImmutableEndpoint getEndpoint()
277 {
278 return endpoint;
279 }
280
281
282
283
284
285
286 public void setEndpoint(ImmutableEndpoint endpoint)
287 {
288 this.endpoint = endpoint;
289 }
290
291 protected abstract Object doTransform(Object src, String encoding) throws TransformerException;
292
293
294
295
296
297
298
299 public void initialise() throws InitialisationException
300 {
301
302 }
303
304 protected String generateTransformerName()
305 {
306 String name = ClassUtils.getSimpleName(this.getClass());
307 int i = name.indexOf("To");
308 if (i > 0 && returnClass != null)
309 {
310 String target = ClassUtils.getSimpleName(returnClass);
311 if (target.equals("byte[]"))
312 {
313 target = "byteArray";
314 }
315 name = name.substring(0, i + 2) + StringUtils.capitalize(target);
316 }
317 return name;
318 }
319
320 public List getSourceTypes()
321 {
322 return Collections.unmodifiableList(sourceTypes);
323 }
324
325 public boolean isIgnoreBadInput()
326 {
327 return ignoreBadInput;
328 }
329
330 public void setIgnoreBadInput(boolean ignoreBadInput)
331 {
332 this.ignoreBadInput = ignoreBadInput;
333 }
334
335
336 public String toString()
337 {
338 StringBuffer sb = new StringBuffer(80);
339 sb.append(ClassUtils.getSimpleName(this.getClass()));
340 sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
341 sb.append(", name='").append(name).append('\'');
342 sb.append(", ignoreBadInput=").append(ignoreBadInput);
343 sb.append(", returnClass=").append(returnClass);
344 sb.append(", sourceTypes=").append(sourceTypes);
345 sb.append('}');
346 return sb.toString();
347 }
348
349 public boolean isAcceptNull()
350 {
351 return false;
352 }
353
354 }