View Javadoc

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