View Javadoc

1   /*
2    * $Id: MethodHeaderPropertyEntryPointResolver.java 10489 2008-01-23 17:53:38Z dfeist $
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 CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  package org.mule.model.resolvers;
11  
12  import org.mule.api.MuleEventContext;
13  import org.mule.api.config.MuleProperties;
14  import org.mule.api.lifecycle.Callable;
15  import org.mule.api.model.InvocationResult;
16  import org.mule.config.i18n.CoreMessages;
17  import org.mule.util.ClassUtils;
18  
19  import java.lang.reflect.Method;
20  
21  import org.apache.commons.lang.BooleanUtils;
22  
23  /**
24   * This resolver will look for a 'method' property on the incoming event to determine which method to invoke
25   * Users can customise the name of the property used to look up the method name on the event
26   */
27  public class MethodHeaderPropertyEntryPointResolver extends AbstractEntryPointResolver
28  {
29  
30      private String methodProperty = MuleProperties.MULE_METHOD_PROPERTY;
31  
32      public String getMethodProperty()
33      {
34          return methodProperty;
35      }
36  
37      public void setMethodProperty(String methodProperty)
38      {
39          this.methodProperty = methodProperty;
40      }
41  
42      public InvocationResult invoke(Object component, MuleEventContext context) throws Exception
43      {
44          //TODO: RM* This is a hack that can be fixed by introducing property scoping on the message
45          // Transports such as SOAP need to ignore the method property
46          boolean ignoreMethod = BooleanUtils.toBoolean((Boolean) context.getMessage().removeProperty(
47                  MuleProperties.MULE_IGNORE_METHOD_PROPERTY));
48  
49          if (ignoreMethod)
50          {
51              //TODO: Removed once we have property scoping
52              InvocationResult result = new InvocationResult(InvocationResult.STATE_INVOKE_NOT_SUPPORTED);
53              result.setErrorMessage("Property: " + MuleProperties.MULE_IGNORE_METHOD_PROPERTY + " was set so skipping this resolver: " + this);
54              return result;
55          }
56  
57          //TODO: with scoped properties we wouldn't need to remove the property here
58          Object methodProp = context.getMessage().removeProperty(getMethodProperty());
59          if (methodProp == null)
60          {
61              InvocationResult result = new InvocationResult(InvocationResult.STATE_INVOKED_FAILED);
62              // no method for the explicit method header
63              result.setErrorMessage(CoreMessages.propertyIsNotSetOnEvent(getMethodProperty()).toString());
64              return result;
65          }
66  
67          Method method;
68          String methodName;
69          if (methodProp instanceof Method)
70          {
71              method = (Method) methodProp;
72              methodName = method.getName();
73          }
74          else
75          {
76              methodName = methodProp.toString();
77              method = getMethodByName(methodName, context);
78          }
79  
80          if (method != null && method.getParameterTypes().length == 0)
81          {
82              return invokeMethod(component, method, ClassUtils.NO_ARGS_TYPE);
83          }
84  
85          Object[] payload = getPayloadFromMessage(context);
86  
87          if (method == null)
88          {
89              Class[] classTypes = ClassUtils.getClassTypes(payload);
90              try
91              {
92                  method = component.getClass().getMethod(methodName, classTypes);
93              }
94              catch (NoSuchMethodException e)
95              {
96                  InvocationResult result = new InvocationResult(InvocationResult.STATE_INVOKED_FAILED);
97                  result.setErrorNoMatchingMethods(component, classTypes, this);
98                  return result;
99  
100             }
101         }
102 
103         validateMethod(component, method);
104         addMethodByName(method, context);
105 
106         return invokeMethod(component, method, payload);
107 
108     }
109 
110     /**
111      * This method can be used to validate that the method exists and is allowed to
112      * be executed.
113      */
114     protected void validateMethod(Object component, Method method)
115             throws NoSuchMethodException
116     {
117         boolean fallback = component instanceof Callable;
118 
119         if (method != null)
120         {
121             // This will throw NoSuchMethodException if it doesn't exist
122             try
123             {
124                 component.getClass().getMethod(method.getName(), method.getParameterTypes());
125             }
126             catch (NoSuchMethodException e)
127             {
128                 if (!fallback)
129                 {
130                     throw e;
131                 }
132             }
133         }
134         else
135         {
136             if (!fallback)
137             {
138                 throw new NoSuchMethodException(
139                         CoreMessages.methodWithParamsNotFoundOnObject("null", "unknown",
140                                 component.getClass()).toString());
141             }
142         }
143     }
144 
145     public String toString()
146     {
147         final StringBuffer sb = new StringBuffer();
148         sb.append("MethodHeaderPropertyEntryPointResolver");
149         sb.append("{methodHeader=").append(methodProperty);
150         sb.append("transformFirst=").append(isTransformFirst());
151         sb.append(", acceptVoidMethods=").append(isAcceptVoidMethods());
152         sb.append('}');
153         return sb.toString();
154     }
155 
156 }