View Javadoc

1   /*
2    * $Id: MethodHeaderPropertyEntryPointResolver.java 19191 2010-08-25 21:05:23Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.api.transport.PropertyScope;
17  import org.mule.config.i18n.CoreMessages;
18  import org.mule.util.ClassUtils;
19  
20  import java.lang.reflect.Method;
21  
22  import org.apache.commons.lang.BooleanUtils;
23  
24  /**
25   * This resolver will look for a {@link org.mule.api.config.MuleProperties#MULE_METHOD_PROPERTY} 
26   * property on the incoming event to determine which method to invoke Users can customise the name 
27   * of the property used to look up the method name on the event
28   */
29  public class MethodHeaderPropertyEntryPointResolver extends AbstractEntryPointResolver
30  {
31  
32      private String methodProperty = MuleProperties.MULE_METHOD_PROPERTY;
33  
34      public String getMethodProperty()
35      {
36          return methodProperty;
37      }
38  
39      public void setMethodProperty(String methodProperty)
40      {
41          this.methodProperty = methodProperty;
42      }
43  
44      public InvocationResult invoke(Object component, MuleEventContext context) throws Exception
45      {
46          // Transports such as SOAP need to ignore the method property
47          boolean ignoreMethod = BooleanUtils.toBoolean(context.getMessage().<Boolean>getInboundProperty(MuleProperties.MULE_IGNORE_METHOD_PROPERTY));
48  
49          if (ignoreMethod)
50          {
51              //TODO: Removed once we have property scoping
52              InvocationResult result = new InvocationResult(this, InvocationResult.State.NOT_SUPPORTED);
53              result.setErrorMessage("Property: " + MuleProperties.MULE_IGNORE_METHOD_PROPERTY + " was set so skipping this resolver");
54              return result;
55          }
56  
57          // MULE-4874: this is needed in order to execute the transformers before determining the methodProp
58          Object[] payload = getPayloadFromMessage(context);
59  
60          //TODO MULE-4953 I don't think the VM transport if managing invocation properties correctly, or maybe it is and this
61          //is valid
62          //Here I have to remove the 'method' property rather than just read it
63          Object methodProp = context.getMessage().removeProperty(getMethodProperty(), PropertyScope.INVOCATION);
64          if (methodProp == null)
65          {
66              methodProp = context.getMessage().getInboundProperty(getMethodProperty());
67          }
68          if (methodProp == null)
69          {
70              InvocationResult result = new InvocationResult(this, InvocationResult.State.FAILED);
71              // no method for the explicit method header
72              result.setErrorMessage(CoreMessages.propertyIsNotSetOnEvent(getMethodProperty()).toString());
73              return result;
74          }
75  
76          Method method;
77          String methodName;
78          if (methodProp instanceof Method)
79          {
80              method = (Method) methodProp;
81              methodName = method.getName();
82          }
83          else
84          {
85              methodName = methodProp.toString();
86              method = getMethodByName(methodName, context);
87          }
88  
89          if (method != null && method.getParameterTypes().length == 0)
90          {
91              return invokeMethod(component, method, ClassUtils.NO_ARGS_TYPE);
92          }
93  
94          if (method == null)
95          {
96              Class<?>[] classTypes = ClassUtils.getClassTypes(payload);
97  
98              method = ClassUtils.getMethod(component.getClass(), methodName, classTypes);
99              
100             if (method == null)
101             {
102                 InvocationResult result = new InvocationResult(this, InvocationResult.State.FAILED);
103                 result.setErrorNoMatchingMethods(component, classTypes);
104                 return result;
105             }
106 
107         }
108 
109         validateMethod(component, method);
110         addMethodByName(method, context);
111 
112         return invokeMethod(component, method, payload);
113     }
114 
115     /**
116      * This method can be used to validate that the method exists and is allowed to
117      * be executed.
118      *
119      * @param component the service component being invoked
120      * @param method the method to invoke on the component
121      * @throws NoSuchMethodException if the method does not exist on the component
122      */
123     protected void validateMethod(Object component, Method method) throws NoSuchMethodException
124     {
125         boolean fallback = component instanceof Callable;
126 
127         if (method != null)
128         {
129             // This will throw NoSuchMethodException if it doesn't exist
130             try
131             {
132                 component.getClass().getMethod(method.getName(), method.getParameterTypes());
133             }
134             catch (NoSuchMethodException e)
135             {
136                 if (!fallback)
137                 {
138                     throw e;
139                 }
140             }
141         }
142         else
143         {
144             if (!fallback)
145             {
146                 throw new NoSuchMethodException(
147                         CoreMessages.methodWithParamsNotFoundOnObject("null", "unknown",
148                                 component.getClass()).toString());
149             }
150         }
151     }
152 
153     @Override
154     public String toString()
155     {
156         final StringBuffer sb = new StringBuffer();
157         sb.append("MethodHeaderPropertyEntryPointResolver");
158         sb.append("{methodHeader=").append(methodProperty);
159         sb.append(", acceptVoidMethods=").append(isAcceptVoidMethods());
160         sb.append('}');
161         return sb.toString();
162     }
163 
164 }