View Javadoc

1   /*
2    * $Id: BindingInvocationHandler.java 22392 2011-07-12 16:35:24Z 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  
11  package org.mule.component;
12  
13  import org.mule.DefaultMuleEvent;
14  import org.mule.DefaultMuleMessage;
15  import org.mule.RequestContext;
16  import org.mule.api.MuleContext;
17  import org.mule.api.MuleEvent;
18  import org.mule.api.MuleMessage;
19  import org.mule.api.component.InterfaceBinding;
20  import org.mule.api.config.MuleProperties;
21  import org.mule.config.i18n.CoreMessages;
22  import org.mule.transport.NullPayload;
23  import org.mule.util.StringMessageUtils;
24  
25  import java.lang.reflect.InvocationHandler;
26  import java.lang.reflect.Method;
27  import java.util.Map;
28  import java.util.concurrent.ConcurrentHashMap;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  
33  public class BindingInvocationHandler implements InvocationHandler
34  {
35  
36      public static final String DEFAULT_METHOD_NAME_TOKEN = "default";
37  
38      protected static Log logger = LogFactory.getLog(BindingInvocationHandler.class);
39  
40      protected Map<String, InterfaceBinding> routers = null;
41  
42      protected MuleContext muleContext;
43  
44      public BindingInvocationHandler(InterfaceBinding router)
45      {
46          routers = new ConcurrentHashMap<String, InterfaceBinding>();
47          addRouterForInterface(router);
48      }
49  
50      public void addRouterForInterface(InterfaceBinding router)
51      {
52          if (router.getMethod() == null)
53          {
54              if (routers.size() == 0)
55              {
56                  routers.put(DEFAULT_METHOD_NAME_TOKEN, router);
57              }
58              else
59              {
60                  throw new IllegalArgumentException(CoreMessages.mustSetMethodNamesOnBinding().getMessage());
61              }
62          }
63          else
64          {
65              routers.put(router.getMethod(), router);
66          }
67          muleContext = router.getEndpoint().getConnector().getMuleContext();
68      }
69  
70      @Override
71      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
72      {
73          if (method.getName().equals("toString"))
74          {
75              return toString();
76          }
77  
78          MuleMessage message = createMuleMessage(args);
79  
80          // Some transports such as Axis, RMI and EJB can use the method information
81          message.setInvocationProperty(MuleProperties.MULE_METHOD_PROPERTY, method.getName());
82  
83          InterfaceBinding router = routers.get(method.getName());
84          if (router == null)
85          {
86              router = routers.get(DEFAULT_METHOD_NAME_TOKEN);
87          }
88  
89          if (router == null)
90          {
91              throw new IllegalArgumentException(CoreMessages.cannotFindBindingForMethod(method.getName()).toString());
92          }
93  
94          MuleEvent currentEvent = RequestContext.getEvent();
95          MuleEvent replyEvent = router.process(new DefaultMuleEvent(message,currentEvent));
96  
97          if (replyEvent != null && replyEvent.getMessage()!=null)
98          {
99              MuleMessage reply = replyEvent.getMessage();
100             if (reply.getExceptionPayload() != null)
101             {
102                 throw findDeclaredMethodException(method, reply.getExceptionPayload().getException());
103             }
104             else
105             {
106                 return determineReply(reply, method);
107             }
108         }
109         else
110         {
111             return null;
112         }
113     }
114 
115     private MuleMessage createMuleMessage(Object[] args)
116     {
117         if (args == null)
118         {
119             return new DefaultMuleMessage(NullPayload.getInstance(), muleContext);
120         }
121         else if (args.length == 1)
122         {
123             return new DefaultMuleMessage(args[0], muleContext);
124         }
125         else
126         {
127             return new DefaultMuleMessage(args, muleContext);
128         }
129     }
130 
131     /**
132      * Return the causing exception instead of the general "container" exception (typically
133      * UndeclaredThrowableException) if the cause is known and the type matches one of the
134      * exceptions declared in the given method's "throws" clause.
135      */
136     private Throwable findDeclaredMethodException(Method method, Throwable throwable) throws Throwable
137     {
138         Throwable cause = throwable.getCause();
139         if (cause != null)
140         {
141             // Try to find a matching exception type from the method's "throws" clause, and if so
142             // return that exception.
143             Class<?>[] exceptions = method.getExceptionTypes();
144             for (int i = 0; i < exceptions.length; i++)
145             {
146                 if (cause.getClass().equals(exceptions[i]))
147                 {
148                     return cause;
149                 }
150             }
151         }
152 
153         return throwable;
154     }
155 
156     private Object determineReply(MuleMessage reply, Method bindingMethod)
157     {
158         if (MuleMessage.class.isAssignableFrom(bindingMethod.getReturnType()))
159         {
160             return reply;
161         }
162         else
163         {
164             return reply.getPayload();
165         }
166     }
167 
168     @Override
169     public String toString()
170     {
171         final StringBuffer sb = new StringBuffer();
172         sb.append("BindingInvocation");
173         sb.append("{routers='").append(StringMessageUtils.toString(routers));
174         sb.append('}');
175         return sb.toString();
176     }
177 
178 }