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