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.VoidResult;
10  import org.mule.api.MuleEventContext;
11  import org.mule.api.model.EntryPointResolver;
12  import org.mule.api.model.InvocationResult;
13  import org.mule.api.transformer.TransformerException;
14  import org.mule.transport.NullPayload;
15  import org.mule.util.ClassUtils;
16  import org.mule.util.StringMessageUtils;
17  
18  import java.lang.reflect.InvocationTargetException;
19  import java.lang.reflect.Method;
20  
21  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  
26  /**
27   * A Base class for {@link org.mule.api.model.EntryPointResolver}. It provides parameters for
28   * detemining if the payload of the message should be transformed first and whether void methods are
29   * acceptible. It also provides a method cashe for those resolvers that use reflection to discover methods
30   * on the service.
31   */
32  public abstract class AbstractEntryPointResolver implements EntryPointResolver
33  {
34      private static final Log logger = LogFactory.getLog(AbstractEntryPointResolver.class);
35  
36      private boolean acceptVoidMethods = false;
37  
38      private boolean synchronizeCall = false;
39  
40      // @GuardedBy(itself)
41      private final ConcurrentHashMap methodCache = new ConcurrentHashMap(4);
42  
43      public boolean isAcceptVoidMethods()
44      {
45          return acceptVoidMethods;
46      }
47  
48      public void setAcceptVoidMethods(boolean acceptVoidMethods)
49      {
50          this.acceptVoidMethods = acceptVoidMethods;
51      }
52  
53      protected ConcurrentHashMap getMethodCache(Object component)
54      {
55          Class<?> componentClass = component.getClass();
56          ConcurrentHashMap cache = (ConcurrentHashMap) methodCache.get(componentClass);
57          if (cache == null)
58          {
59              methodCache.putIfAbsent(componentClass, new ConcurrentHashMap(4));
60          }
61          return (ConcurrentHashMap) methodCache.get(componentClass);
62      }
63  
64      protected Method getMethodByName(Object component, String methodName, MuleEventContext context)
65      {
66          return (Method) getMethodCache(component).get(methodName);
67      }
68  
69      protected Method addMethodByName(Object component, Method method, MuleEventContext context)
70      {
71          Method previousMethod = (Method) getMethodCache(component).putIfAbsent(method.getName(), method);
72          return (previousMethod != null ? previousMethod : method);
73      }
74  
75      protected Method addMethodByArguments(Object component, Method method, Object[] payload)
76      {
77          Method previousMethod = (Method) getMethodCache(component).putIfAbsent(getCacheKeyForPayload(component, payload), method);
78          return (previousMethod != null ? previousMethod : method);
79      }
80  
81  
82      protected Method getMethodByArguments(Object component, Object[] payload)
83      {
84          Method method = (Method) getMethodCache(component).get(getCacheKeyForPayload(component, payload));
85          return method;
86      }
87  
88      protected String getCacheKeyForPayload(Object component, Object[] payload)
89      {
90          StringBuffer key = new StringBuffer(48);
91          for (int i = 0; i < payload.length; i++)
92          {
93              Object o = payload[i];
94              if (o != null)
95              {
96                  key.append(o.getClass().getName());
97              }
98              else
99              {
100                 key.append("null");
101             }
102         }
103         key.append(".").append(ClassUtils.getClassName(component.getClass()));
104         return key.toString();
105     }
106 
107 
108     protected Object[] getPayloadFromMessage(MuleEventContext context) throws TransformerException
109     {
110         Object temp = context.getMessage().getPayload();
111         if (temp instanceof Object[])
112         {
113             return (Object[]) temp;
114         }
115         else if (temp instanceof NullPayload)
116         {
117             return ClassUtils.NO_ARGS;
118         }
119         else
120         {
121             return new Object[]{temp};
122         }
123     }
124 
125     protected InvocationResult invokeMethod(Object component, Method method, Object[] arguments)
126             throws InvocationTargetException, IllegalAccessException
127     {
128         String methodCall = null;
129 
130         if (logger.isDebugEnabled())
131         {
132             methodCall = component.getClass().getName() + "." + method.getName() + "("
133                     + StringMessageUtils.toString(ClassUtils.getClassTypes(arguments)) + ")";
134             logger.debug("Invoking " + methodCall);
135         }
136 
137         Object result;
138 
139         if(isSynchronizeCall())
140         {
141             synchronized (component)
142             {
143                 result = method.invoke(component, arguments);
144             }
145         }
146         else
147         {
148             result = method.invoke(component, arguments);
149         }
150 
151         if (method.getReturnType().equals(Void.TYPE))
152         {
153             result = VoidResult.getInstance();
154         }
155 
156         if (logger.isDebugEnabled())
157         {
158             logger.debug("Result of call " + methodCall + " is " + (result == null ? "null" : "not null"));
159         }
160 
161         return new InvocationResult(this, result, method);
162     }
163 
164     public boolean isSynchronizeCall()
165     {
166         return synchronizeCall;
167     }
168 
169     public void setSynchronizeCall(boolean synchronizeCall)
170     {
171         this.synchronizeCall = synchronizeCall;
172     }
173 
174     @Override
175     public String toString()
176     {
177         final StringBuffer sb = new StringBuffer();
178         sb.append("AbstractEntryPointResolver");
179         sb.append(", acceptVoidMethods=").append(acceptVoidMethods);
180         sb.append('}');
181         return sb.toString();
182     }
183 }