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.model.InvocationResult;
11  import org.mule.util.ClassUtils;
12  import org.mule.util.StringMessageUtils;
13  
14  import java.lang.reflect.Method;
15  import java.util.Arrays;
16  import java.util.HashSet;
17  import java.util.List;
18  import java.util.Set;
19  
20  /**
21   * A base class that allows implementing resolvers to define what parameters it is expecting.  Currently
22   * there are two implementations of this {@link org.mule.model.resolvers.NoArgumentsEntryPointResolver}, that
23   * allows methods with no arguments to be invoked and {@link org.mule.model.resolvers.ArrayEntryPointResolver} that
24   * allows for methods that accept an array type to be invoked.
25   * <p/>
26   * Users can set explicit method names on this resolver to control which methods are allowed to be called. Also a set of
27   * 'ignored' methods are available (and the use can add others) to tell the resolver to not resolve to these methods.
28   * The default ones are:
29   * <ul>
30   * <li>{@link #toString()}
31   * <li>{@link #getClass()}
32   * <li>{@link #notify}
33   * <li>{@link #notifyAll}
34   * <li>{@link #hashCode}
35   * <li>{@link #wait}
36   * <li>'is*'
37   * <li>'get*'.
38   * </ul>
39   * <p/> Note that wildcard expressions can be used.
40   */
41  public abstract class AbstractArgumentEntryPointResolver extends ReflectionEntryPointResolver
42  {
43      private Set<String> methods = new HashSet<String>(2);
44  
45      private boolean enableDiscovery = true;
46  
47      public AbstractArgumentEntryPointResolver()
48      {
49          //By default No arg methods without a return type should be supported
50          setAcceptVoidMethods(true);
51          // we don't want to match these methods when looking for a service method
52          //If you add to this list please change the javaDoc above too.
53          setIgnoredMethods(new HashSet<String>(Arrays.asList("toString",
54                  "getClass", "notify", "notifyAll", "wait", "hashCode", "clone", "is*", "get*")));
55      }
56  
57      public Set<String> getMethods()
58      {
59          return methods;
60      }
61  
62      public void setMethods(Set<String> methods)
63      {
64          this.methods = methods;
65      }
66  
67      public void addMethod(String name)
68      {
69          this.methods.add(name);
70      }
71  
72      public boolean removeMethod(String name)
73      {
74          return this.methods.remove(name);
75      }
76  
77  
78      public boolean isEnableDiscovery()
79      {
80          return enableDiscovery;
81      }
82  
83      public void setEnableDiscovery(boolean enableDiscovery)
84      {
85          this.enableDiscovery = enableDiscovery;
86      }
87  
88      @Override
89      public InvocationResult invoke(Object component, MuleEventContext context) throws Exception
90      {
91          Method method = null;
92          Object[] payload = getPayloadFromMessage(context);
93  
94          if (payload == null)
95          {
96              return new InvocationResult(this, InvocationResult.State.NOT_SUPPORTED);
97          }
98  
99          for (String methodName : methods)
100         {
101             method = getMethodByName(component, methodName, context);
102 
103             if (method == null)
104             {
105                 method = ClassUtils.getMethod(component.getClass(), methodName, 
106                     getMethodArgumentTypes(payload));
107             }
108             if (method != null)
109             {
110                 addMethodByName(component, method, context);
111                 break;
112             }
113         }
114         //If the method wasn't explicitly set, lets try and discover it
115         if (method == null)
116         {
117             if (isEnableDiscovery())
118             {
119                 Class<?>[] argTypes = getMethodArgumentTypes(payload);
120                 List<Method> methods = ClassUtils.getSatisfiableMethods(component.getClass(), argTypes,
121                         isAcceptVoidMethods(), false, getIgnoredMethods(), filter);
122 
123                 if (methods.size() > 1)
124                 {
125                     InvocationResult result = new InvocationResult(this, InvocationResult.State.FAILED);
126                     // too many methods match the payload argument
127                     result.setErrorTooManyMatchingMethods(component, argTypes, 
128                         StringMessageUtils.toString(methods));
129                     return result;
130                 }
131                 else if (methods.size() == 1)
132                 {
133                     // found exact match for payload argument
134                     method = this.addMethodByArguments(component, methods.get(0), 
135                         getPayloadFromMessage(context));
136                 }
137                 else
138                 {
139                     InvocationResult result = new InvocationResult(this, InvocationResult.State.FAILED);
140                     // no method for payload argument either - bail out
141                     result.setErrorNoMatchingMethods(component, ClassUtils.NO_ARGS_TYPE);
142                     return result;
143                 }
144             }
145             else
146             {
147                 InvocationResult result = new InvocationResult(this, InvocationResult.State.FAILED);
148                 // no method for the explicit methods either
149                 result.setErrorNoMatchingMethodsCalled(component, StringMessageUtils.toString(methods));
150                 return result;
151             }
152         }
153         return invokeMethod(component, method, getPayloadFromMessage(context));
154     }
155 
156     protected abstract Class<?>[] getMethodArgumentTypes(Object[] payload);
157 
158     @Override
159     public String toString()
160     {
161         final StringBuffer sb = new StringBuffer();
162         sb.append(ClassUtils.getClassName(getClass()));
163         sb.append("{methods=").append(StringMessageUtils.toString(methods));
164         sb.append(", acceptVoidMethods=").append(isAcceptVoidMethods());
165         sb.append('}');
166         return sb.toString();
167     }
168 }