KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mule > model > DynamicEntryPoint


1 /*
2  * $Id: DynamicEntryPoint.java 4259 2006-12-14 03:12:07Z aperepel $
3  * --------------------------------------------------------------------------------------
4  * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
5  *
6  * The software in this package is published under the terms of the MuleSource MPL
7  * license, a copy of which has been included with this distribution in the
8  * LICENSE.txt file.
9  */

10
11 package org.mule.model;
12
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15 import org.mule.config.MuleProperties;
16 import org.mule.config.i18n.Message;
17 import org.mule.config.i18n.Messages;
18 import org.mule.impl.MuleMessage;
19 import org.mule.impl.RequestContext;
20 import org.mule.providers.NullPayload;
21 import org.mule.umo.UMOEventContext;
22 import org.mule.umo.lifecycle.Callable;
23 import org.mule.umo.model.UMOEntryPoint;
24 import org.mule.util.ClassUtils;
25
26 import java.lang.reflect.InvocationTargetException JavaDoc;
27 import java.lang.reflect.Method JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31
32 /**
33  * <code>DynamicEntryPoint</code> is used to detemine the entry point on a bean
34  * after an event has been received for it. The entrypoint is then discovered using
35  * the event payload type as the argument. An entry point will try and be matched for
36  * different argument types so it's possible to have multiple entry points on a
37  * single component.
38  */

39
40 public class DynamicEntryPoint implements UMOEntryPoint
41 {
42     /**
43      * logger used by this class
44      */

45     protected static final Log logger = LogFactory.getLog(DynamicEntryPoint.class);
46
47     private Map JavaDoc entryPoints = new HashMap JavaDoc();
48     private Method JavaDoc currentMethod;
49
50     // we don't want to match these methods when looking for a service method to
51
// invoke
52
protected String JavaDoc[] ignoreMethods = new String JavaDoc[]{"equals", "getInvocationHandler"};
53
54     public Class JavaDoc[] getParameterTypes()
55     {
56         if (currentMethod == null)
57         {
58             return null;
59         }
60         return currentMethod.getParameterTypes();
61     }
62
63     public synchronized Object JavaDoc invoke(Object JavaDoc component, UMOEventContext context) throws Exception JavaDoc
64     {
65         Object JavaDoc payload = null;
66         Method JavaDoc method = null;
67
68         // Transports such as Soap need he method property to be ignorred
69
Boolean JavaDoc ignoreMethod = (Boolean JavaDoc)context.getMessage().removeProperty(
70             MuleProperties.MULE_IGNORE_METHOD_PROPERTY);
71         boolean ignore = (ignoreMethod == null ? false : ignoreMethod.booleanValue());
72
73         if (!ignore)
74         {
75             // Check for method override and remove it from the event
76
Object JavaDoc methodOverride = context.getMessage().removeProperty(MuleProperties.MULE_METHOD_PROPERTY);
77             if (methodOverride instanceof Method JavaDoc)
78             {
79                 method = (Method JavaDoc)methodOverride;
80             }
81             else if (methodOverride != null)
82             {
83                 payload = context.getTransformedMessage();
84                 // Get the method that matches the method name with the current
85
// argument types
86
method = ClassUtils.getMethod(methodOverride.toString(), ClassUtils.getClassTypes(payload),
87                     component.getClass());
88                 validateMethod(component, method, methodOverride.toString());
89             }
90         }
91
92         if (method == null)
93         {
94             if (component instanceof Callable)
95             {
96                 method = Callable.class.getMethods()[0];
97                 payload = context;
98             }
99             if (method == null)
100             {
101                 method = getMethod(component, context);
102                 if (method == null)
103                 {
104                     payload = context.getTransformedMessage();
105                     method = getMethod(component, payload);
106                     if (method != null)
107                     {
108                         RequestContext.rewriteEvent(new MuleMessage(payload, context.getMessage()));
109                     }
110                 }
111                 else
112                 {
113                     payload = context;
114                 }
115             }
116         }
117         if (method != null)
118         {
119             validateMethod(component, method, method.getName());
120
121             currentMethod = method;
122             if (payload == null)
123             {
124                 payload = context.getTransformedMessage();
125                 RequestContext.rewriteEvent(new MuleMessage(payload, context.getMessage()));
126             }
127             return invokeCurrent(component, payload);
128         }
129
130         // Are any methods on the component accepting an context?
131
List JavaDoc methods = ClassUtils.getSatisfiableMethods(component.getClass(),
132             ClassUtils.getClassTypes(context), true, false, ignoreMethods);
133         if (methods.size() > 1)
134         {
135             TooManySatisfiableMethodsException tmsmex = new TooManySatisfiableMethodsException(
136                 component.getClass());
137             throw new InvocationTargetException JavaDoc(tmsmex, "There must be only one method accepting "
138                                                         + context.getClass().getName() + " in component "
139                                                         + component.getClass().getName());
140         }
141         else if (methods.size() == 1)
142         {
143             if (logger.isDebugEnabled())
144             {
145                 logger.debug("Dynamic Entrypoint using method: " + component.getClass().getName() + "."
146                              + ((Method JavaDoc)methods.get(0)).getName() + "(" + context.getClass().getName() + ")");
147             }
148             addMethod(component, (Method JavaDoc)methods.get(0), context.getClass());
149             return invokeCurrent(component, context);
150         }
151         else
152         {
153             methods = ClassUtils.getSatisfiableMethods(component.getClass(),
154                 ClassUtils.getClassTypes(payload), true, true, ignoreMethods);
155             if (methods.size() > 1)
156             {
157                 throw new TooManySatisfiableMethodsException(component.getClass());
158             }
159             if (methods.size() == 1)
160             {
161                 if (logger.isDebugEnabled())
162                 {
163                     logger.debug("Dynamic Entrypoint using method: " + component.getClass().getName() + "."
164                                  + ((Method JavaDoc)methods.get(0)).getName() + "(" + payload.getClass().getName()
165                                  + ")");
166                 }
167                 addMethod(component, (Method JavaDoc)methods.get(0), payload.getClass());
168                 return invokeCurrent(component, payload);
169             }
170             else
171             {
172                 throw new NoSatisfiableMethodsException(component.getClass(),
173                     ClassUtils.getClassTypes(payload));
174             }
175         }
176     }
177
178     /**
179      * This method can be used to validate that the method exists and is allowed to
180      * be executed.
181      *
182      * @param component
183      * @param method
184      * @param methodName
185      * @throws Exception
186      */

187     protected void validateMethod(Object JavaDoc component, Method JavaDoc method, String JavaDoc methodName) throws Exception JavaDoc
188     {
189         boolean fallback = component instanceof Callable;
190         if (method == null && !fallback)
191         {
192             throw new NoSuchMethodException JavaDoc(new Message(Messages.METHOD_X_WITH_PARAMS_X_NOT_FOUND_ON_X,
193                 methodName, "unknown", component.getClass().getName()).toString());
194         }
195         // This will throw NoSuchMethodException if it doesn't exist
196
try
197         {
198             component.getClass().getMethod(method.getName(), method.getParameterTypes());
199         }
200         catch (Exception JavaDoc e)
201         {
202             if (!fallback) throw e;
203         }
204     }
205
206     protected Method JavaDoc getMethod(Object JavaDoc component, Object JavaDoc arg)
207     {
208         return (Method JavaDoc)entryPoints.get(component.getClass().getName() + ":" + arg.getClass().getName());
209     }
210
211     protected void addMethod(Object JavaDoc component, Method JavaDoc method, Class JavaDoc arg)
212     {
213         entryPoints.put(component.getClass().getName() + ":" + arg.getName(), method);
214         currentMethod = method;
215     }
216
217     /**
218      * Will invoke the entry point method on the given component
219      *
220      * @param component the component to invoke
221      * @param arg the argument to pass to the method invocation
222      * @return An object (if any) returned by the invocation
223      * @throws InvocationTargetException
224      * @throws IllegalAccessException
225      */

226     private Object JavaDoc invokeCurrent(Object JavaDoc component, Object JavaDoc arg)
227         throws InvocationTargetException JavaDoc, IllegalAccessException JavaDoc
228     {
229         String JavaDoc methodCall = null;
230         if (logger.isDebugEnabled())
231         {
232             methodCall = component.getClass().getName() + "." + currentMethod.getName() + "("
233                          + arg.getClass().getName() + ")";
234             logger.debug("Invoking " + methodCall);
235         }
236
237         Object JavaDoc[] args;
238         if (arg.getClass().isArray())
239         {
240             if (Object JavaDoc[].class.isAssignableFrom(arg.getClass()))
241             {
242                 args = (Object JavaDoc[])arg;
243             }
244             else
245             {
246                 args = new Object JavaDoc[]{arg};
247             }
248         }
249         else if (arg instanceof NullPayload)
250         {
251             args = null;
252         }
253         else
254         {
255             args = new Object JavaDoc[]{arg};
256         }
257         Object JavaDoc result = currentMethod.invoke(component, args);
258         if (logger.isDebugEnabled())
259         {
260             logger.debug("Result of call " + methodCall + " is " + (result == null ? "null" : "not null"));
261         }
262         return result;
263     }
264
265     public boolean isVoid()
266     {
267         if (currentMethod == null)
268         {
269             return false;
270         }
271         return currentMethod.getReturnType().getName().equals("void");
272     }
273
274     public String JavaDoc getMethodName()
275     {
276         if (currentMethod == null)
277         {
278             return null;
279         }
280         return currentMethod.getName();
281     }
282 }
283
Popular Tags