View Javadoc

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