View Javadoc

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