1
2
3
4
5
6
7
8
9
10
11 package org.mule.processor;
12
13 import org.mule.DefaultMuleEvent;
14 import org.mule.DefaultMuleMessage;
15 import org.mule.api.AnnotatedObject;
16 import org.mule.api.MessagingException;
17 import org.mule.api.MuleContext;
18 import org.mule.api.MuleEvent;
19 import org.mule.api.MuleException;
20 import org.mule.api.MuleMessage;
21 import org.mule.api.context.MuleContextAware;
22 import org.mule.api.expression.ExpressionManager;
23 import org.mule.api.lifecycle.Initialisable;
24 import org.mule.api.lifecycle.InitialisationException;
25 import org.mule.api.processor.MessageProcessor;
26 import org.mule.api.registry.RegistrationException;
27 import org.mule.api.transformer.DataType;
28 import org.mule.api.transformer.Transformer;
29 import org.mule.api.transformer.TransformerException;
30 import org.mule.config.i18n.CoreMessages;
31 import org.mule.transformer.TransformerTemplate;
32 import org.mule.transformer.types.DataTypeFactory;
33 import org.mule.transport.NullPayload;
34 import org.mule.util.ClassUtils;
35 import org.mule.util.TemplateParser;
36 import org.mule.util.TemplateParser.PatternInfo;
37
38 import java.lang.reflect.Method;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Map.Entry;
47 import java.util.concurrent.ConcurrentHashMap;
48
49 import javax.xml.namespace.QName;
50
51 import org.apache.commons.logging.Log;
52 import org.apache.commons.logging.LogFactory;
53
54
55
56
57
58
59
60
61
62
63 public class InvokerMessageProcessor implements MessageProcessor, Initialisable, MuleContextAware, AnnotatedObject
64 {
65 protected final transient Log logger = LogFactory.getLog(getClass());
66
67 protected Object object;
68 protected Class<?> objectType;
69 protected String methodName;
70 protected List<?> arguments = new ArrayList<Object>();
71 protected Class<?>[] argumentTypes;
72 protected String name;
73 protected PatternInfo patternInfo = TemplateParser.createMuleStyleParser().getStyle();
74
75 protected Method method;
76 protected ExpressionManager expressionManager;
77 protected MuleContext muleContext;
78 private final Map<QName, Object> annotations = new ConcurrentHashMap<QName, Object>();
79
80 @Override
81 public void initialise() throws InitialisationException
82 {
83 if (object == null)
84 {
85 lookupObjectInstance();
86 }
87
88 resolveMethodToInvoke();
89
90 expressionManager = muleContext.getExpressionManager();
91 }
92
93 protected void resolveMethodToInvoke() throws InitialisationException
94 {
95 if (argumentTypes != null)
96 {
97 method = ClassUtils.getMethod(object.getClass(), methodName, argumentTypes);
98 if (method == null)
99 {
100 throw new InitialisationException(CoreMessages.methodWithParamsNotFoundOnObject(methodName,
101 argumentTypes, object.getClass()), this);
102 }
103 }
104 else
105 {
106 List<Method> matchingMethods = new ArrayList<Method>();
107 int argSize = arguments != null ? arguments.size() : 0;
108 for (Method methodCandidate : object.getClass().getMethods())
109 {
110 if (methodCandidate.getName().equals(methodName)
111 && methodCandidate.getParameterTypes().length == argSize)
112 matchingMethods.add(methodCandidate);
113 }
114 if (matchingMethods.size() == 1)
115 {
116 method = matchingMethods.get(0);
117 argumentTypes = method.getParameterTypes();
118 }
119 else
120 {
121 throw new InitialisationException(CoreMessages.methodWithNumParamsNotFoundOnObject(
122 methodName, arguments.size(), object), this);
123 }
124 }
125
126 if (logger.isDebugEnabled())
127 {
128 logger.debug(String.format("Initialised %s to use method: '%s'", this, method));
129 }
130 }
131
132 protected void lookupObjectInstance() throws InitialisationException
133 {
134 if (logger.isDebugEnabled())
135 {
136 logger.debug(String.format(
137 "No object instance speciedied. Looking up single instance of type %s in mule registry",
138 objectType));
139 }
140
141 try
142 {
143 object = muleContext.getRegistry().lookupObject(objectType);
144 }
145 catch (RegistrationException e)
146 {
147 throw new InitialisationException(
148 CoreMessages.initialisationFailure(String.format(
149 "Muliple instances of '%s' were found in the registry so you need to configure a specific instance",
150 objectType)), this);
151 }
152 if (object == null)
153 {
154 throw new InitialisationException(CoreMessages.initialisationFailure(String.format(
155 "No instance of '%s' was found in the registry", objectType)), this);
156
157 }
158 }
159
160 @Override
161 public MuleEvent process(MuleEvent event) throws MuleException
162 {
163 MuleEvent resultEvent = event;
164 Object[] args = evaluateArguments(event, arguments);
165
166 if (logger.isDebugEnabled())
167 {
168 logger.debug(String.format("Invoking '%s' of '%s' with arguments: '%s'", method.getName(),
169 object, args));
170 }
171
172 try
173 {
174 Object result = method.invoke(object, args);
175 if (!method.getReturnType().equals(void.class))
176 {
177 resultEvent = createResultEvent(event, result);
178 }
179 }
180 catch (Exception e)
181 {
182 throw new MessagingException(CoreMessages.failedToInvoke(object.toString()), event, e);
183 }
184 return resultEvent;
185 }
186
187 protected Object[] evaluateArguments(MuleEvent event, List<?> argumentTemplates)
188 throws MessagingException
189 {
190 int argSize = argumentTemplates != null ? argumentTemplates.size() : 0;
191 Object[] args = new Object[argSize];
192 MuleMessage message = event.getMessage();
193 try
194 {
195 for (int i = 0; i < args.length; i++)
196 {
197 Object argumentTemplate = argumentTemplates.get(i);
198 if (argumentTemplate != null)
199 {
200 args[i] = transformArgument(evaluateExpressionCandidate(argumentTemplate, message),
201 argumentTypes[i]);
202 }
203 }
204 return args;
205 }
206 catch (TransformerException e)
207 {
208 throw new MessagingException(event, e);
209 }
210 }
211
212 @SuppressWarnings("unchecked")
213 protected Object evaluateExpressionCandidate(Object expressionCandidate, MuleMessage message)
214 throws TransformerException
215 {
216 if (expressionCandidate instanceof Collection<?>)
217 {
218 Collection<Object> collectionTemplate = (Collection<Object>) expressionCandidate;
219 Collection<Object> newCollection = new ArrayList<Object>();
220 for (Object object : collectionTemplate)
221 {
222 newCollection.add(evaluateExpressionCandidate(object, message));
223 }
224 return newCollection;
225 }
226 else if (expressionCandidate instanceof Map<?, ?>)
227 {
228 Map<Object, Object> mapTemplate = (Map<Object, Object>) expressionCandidate;
229 Map<Object, Object> newMap = new HashMap<Object, Object>();
230 for (Entry<Object, Object> entry : mapTemplate.entrySet())
231 {
232 newMap.put(evaluateExpressionCandidate(entry.getKey(), message), evaluateExpressionCandidate(
233 entry.getValue(), message));
234 }
235 return newMap;
236 }
237 else if (expressionCandidate instanceof String[])
238 {
239 String[] stringArrayTemplate = (String[]) expressionCandidate;
240 Object[] newArray = new String[stringArrayTemplate.length];
241 for (int j = 0; j < stringArrayTemplate.length; j++)
242 {
243 newArray[j] = evaluateExpressionCandidate(stringArrayTemplate[j], message);
244 }
245 return newArray;
246 }
247 if (expressionCandidate instanceof String)
248 {
249 Object arg;
250 String expression = (String) expressionCandidate;
251
252
253
254 if (expression.startsWith(patternInfo.getPrefix())
255 && expression.endsWith(patternInfo.getSuffix()))
256 {
257 arg = expressionManager.evaluate(expression, message);
258 }
259 else
260 {
261 arg = expressionManager.parse(expression, message);
262 }
263
264
265 if (arg instanceof MuleMessage)
266 {
267 arg = ((MuleMessage) arg).getPayload();
268 }
269 return arg;
270 }
271 else
272 {
273
274 return expressionCandidate;
275 }
276 }
277
278 private Object transformArgument(Object arg, Class<?> type) throws TransformerException
279 {
280 if (!(type.isAssignableFrom(arg.getClass())))
281 {
282 DataType<?> source = DataTypeFactory.create(arg.getClass());
283 DataType<?> target = DataTypeFactory.create(type);
284
285 Transformer t = muleContext.getRegistry().lookupTransformer(source, target);
286 arg = t.transform(arg);
287 }
288 return arg;
289 }
290
291 public void setObject(Object object)
292 {
293 this.object = object;
294 }
295
296 public void setMethodName(String methodName)
297 {
298 this.methodName = methodName;
299 }
300
301 public void setArgumentExpressionsString(String arguments)
302 {
303 this.arguments = Arrays.asList(arguments.split("\\s*,\\s*"));
304 }
305
306 public void setArguments(List<?> arguments)
307 {
308 this.arguments = arguments;
309 }
310
311 protected MuleEvent createResultEvent(MuleEvent event, Object result) throws MuleException
312 {
313 if (result instanceof MuleMessage)
314 {
315 return new DefaultMuleEvent((MuleMessage) result, event);
316 }
317 else if (result != null)
318 {
319 event.getMessage().applyTransformers(
320 event,
321 Collections.<Transformer> singletonList(new TransformerTemplate(
322 new TransformerTemplate.OverwitePayloadCallback(result))));
323 return event;
324 }
325 else
326 {
327 return new DefaultMuleEvent(new DefaultMuleMessage(NullPayload.getInstance(),
328 event.getMuleContext()), event);
329 }
330 }
331
332 public String getName()
333 {
334 return name;
335 }
336
337 public void setName(String name)
338 {
339 this.name = name;
340 }
341
342 public void setArgumentTypes(Class<?>[] argumentTypes)
343 {
344 this.argumentTypes = argumentTypes;
345 }
346
347 @Override
348 public String toString()
349 {
350 return String.format(
351 "InvokerMessageProcessor [name=%s, object=%s, methodName=%s, argExpressions=%s, argTypes=%s]",
352 name, object, methodName, arguments, argumentTypes);
353 }
354
355 @Override
356 public void setMuleContext(MuleContext context)
357 {
358 this.muleContext = context;
359 }
360
361 public void setObjectType(Class<?> objectType)
362 {
363 this.objectType = objectType;
364 }
365
366 public final Object getAnnotation(QName name)
367 {
368 return annotations.get(name);
369 }
370
371 public final Map<QName, Object> getAnnotations()
372 {
373 return Collections.unmodifiableMap(annotations);
374 }
375
376 public synchronized final void setAnnotations(Map<QName, Object> newAnnotations)
377 {
378 annotations.clear();
379 annotations.putAll(newAnnotations);
380 }
381 }