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.module.cxf;
8   
9   import org.mule.api.MuleEvent;
10  import org.mule.api.MuleException;
11  import org.mule.api.MuleMessage;
12  import org.mule.api.config.MuleProperties;
13  import org.mule.api.transport.PropertyScope;
14  import org.mule.component.ComponentException;
15  import org.mule.transport.NullPayload;
16  
17  import java.lang.reflect.Method;
18  import java.lang.reflect.Proxy;
19  import java.util.List;
20  
21  import org.apache.cxf.frontend.MethodDispatcher;
22  import org.apache.cxf.helpers.CastUtils;
23  import org.apache.cxf.interceptor.Fault;
24  import org.apache.cxf.message.Exchange;
25  import org.apache.cxf.message.FaultMode;
26  import org.apache.cxf.message.Message;
27  import org.apache.cxf.message.MessageContentsList;
28  import org.apache.cxf.service.Service;
29  import org.apache.cxf.service.invoker.Invoker;
30  import org.apache.cxf.service.model.BindingOperationInfo;
31  
32  /**
33   * Invokes a Mule Service via a CXF binding.
34   */
35  public class MuleInvoker implements Invoker
36  {
37      private final CxfInboundMessageProcessor cxfMmessageProcessor;
38      private Class<?> targetClass;
39      
40      public MuleInvoker(CxfInboundMessageProcessor cxfMmessageProcessor, Class<?> targetClass)
41      {
42          this.cxfMmessageProcessor = cxfMmessageProcessor;
43          this.targetClass = targetClass;
44      }
45  
46      public Object invoke(Exchange exchange, Object o)
47      {
48          // this is the original request. Keep it to copy all the message properties from it
49          MuleEvent event = (MuleEvent) exchange.get(CxfConstants.MULE_EVENT);
50          MuleEvent responseEvent = null;
51          try
52          {
53              MuleMessage reqMsg = event.getMessage();
54              reqMsg.setPayload(extractPayload(exchange.getInMessage()));
55              
56              BindingOperationInfo bop = exchange.get(BindingOperationInfo.class);
57              Service svc = exchange.get(Service.class);
58              if (!cxfMmessageProcessor.isProxy())
59              {
60                  MethodDispatcher md = (MethodDispatcher) svc.get(MethodDispatcher.class.getName());
61                  Method m = md.getMethod(bop);
62                  if (targetClass != null)
63                  {
64                      m = matchMethod(m, targetClass);
65                  }
66              
67                  reqMsg.setProperty(MuleProperties.MULE_METHOD_PROPERTY, m, PropertyScope.INVOCATION);
68              }
69  
70              if (bop != null)
71              {
72                  reqMsg.setProperty(CxfConstants.INBOUND_OPERATION, bop.getOperationInfo().getName(), PropertyScope.INVOCATION);
73                  reqMsg.setProperty(CxfConstants.INBOUND_SERVICE, svc.getName(), PropertyScope.INVOCATION);
74              }
75              
76              responseEvent = cxfMmessageProcessor.processNext(event);
77          }
78          catch (MuleException e)
79          {
80              exchange.put(CxfConstants.MULE_EVENT, event);
81  
82              Throwable cause = e;
83              if (e instanceof ComponentException) {
84                  cause = e.getCause();
85              }
86              throw new Fault(cause);
87          }
88          catch (RuntimeException e)
89          {
90              exchange.put(CxfConstants.MULE_EVENT, event);
91              throw new Fault(e);
92          }
93  
94          if (!event.getEndpoint().getExchangePattern().hasResponse())
95          {
96              // weird response from AbstractInterceptingMessageProcessor
97              responseEvent = null;
98          }
99          
100         if (responseEvent != null)
101         {
102             exchange.put(CxfConstants.MULE_EVENT, responseEvent);
103             MuleMessage resMessage = responseEvent.getMessage();
104             
105             if (resMessage.getExceptionPayload() != null)
106             {
107                 Throwable cause = resMessage.getExceptionPayload().getException();
108                 if (cause instanceof ComponentException)
109                 {
110                     cause = cause.getCause();
111                 }
112 
113                 exchange.getInMessage().put(FaultMode.class, FaultMode.UNCHECKED_APPLICATION_FAULT);
114                 if (cause instanceof Fault)
115                 {
116                     throw (Fault) cause;
117                 }
118 
119                 throw new Fault(cause);
120             }
121             else if (resMessage.getPayload() instanceof NullPayload)
122             {
123                 return new MessageContentsList((Object)null);
124             }
125             else if (cxfMmessageProcessor.isProxy())
126             {
127                 resMessage.getPayload();
128                 return new Object[] { resMessage };
129             }
130             else
131             {
132                 return new Object[]{resMessage.getPayload()};
133             }
134         }
135         else
136         {
137             exchange.getInMessage().getInterceptorChain().abort();
138             if (exchange.getOutMessage() != null)
139             {
140                 exchange.getOutMessage().getInterceptorChain().abort();
141             }
142             exchange.put(CxfConstants.MULE_EVENT, null);
143             return null;
144         }
145     }
146     
147     protected Object extractPayload(Message cxfMessage)
148     {   
149         List<Object> list = CastUtils.cast(cxfMessage.getContent(List.class));
150         if (list == null)
151         {
152             // Seems Providers get objects stored this way
153             Object object = cxfMessage.getContent(Object.class);
154             if (object != null)
155             {
156                 return object;
157             }
158             else
159             {
160                 return new Object[0];
161             }
162         }
163         
164         if ((list.size() == 1) && (list.get(0) != null))
165         {
166             return list.get(0);
167         }
168         else
169         {
170             return list.toArray();
171         }
172     }
173 
174     /**
175      * Returns a Method that has the same declaring class as the class of
176      * targetObject to avoid the IllegalArgumentException when invoking the
177      * method on the target object. The methodToMatch will be returned if the
178      * targetObject doesn't have a similar method.
179      * 
180      * @param methodToMatch The method to be used when finding a matching method
181      *            in targetObject
182      * @param targetClass The class to search in for the method.
183      * @return The methodToMatch if no such method exist in the class of
184      *         targetObject; otherwise, a method from the class of targetObject
185      *         matching the matchToMethod method.
186      */
187     private static Method matchMethod(Method methodToMatch, Class<?> targetClass) 
188     {
189         Class<?>[] interfaces = targetClass.getInterfaces();
190         for (int i = 0; i < interfaces.length; i++) 
191         {
192             Method m = getMostSpecificMethod(methodToMatch, interfaces[i]);
193             if (!methodToMatch.equals(m)) 
194             {
195                 return m;
196             }
197         }
198         return methodToMatch;
199     }
200 
201     /**
202      * Return whether the given object is a J2SE dynamic proxy.
203      * 
204      * @param object the object to check
205      * @see java.lang.reflect.Proxy#isProxyClass
206      */
207     public static boolean isJdkDynamicProxy(Object object) 
208     {
209         return object != null && Proxy.isProxyClass(object.getClass());
210     }
211 
212     /**
213      * Given a method, which may come from an interface, and a targetClass used
214      * in the current AOP invocation, find the most specific method if there is
215      * one. E.g. the method may be IFoo.bar() and the target class may be
216      * DefaultFoo. In this case, the method may be DefaultFoo.bar(). This
217      * enables attributes on that method to be found.
218      * 
219      * @param method method to be invoked, which may come from an interface
220      * @param targetClass target class for the curren invocation. May be
221      *            <code>null</code> or may not even implement the method.
222      * @return the more specific method, or the original method if the
223      *         targetClass doesn't specialize it or implement it or is null
224      */
225     public static Method getMostSpecificMethod(Method method, Class<?> targetClass) {
226         if (method != null && targetClass != null) {
227             try {
228                 method = targetClass.getMethod(method.getName(), method.getParameterTypes());
229             } catch (NoSuchMethodException ex) {
230                 // Perhaps the target class doesn't implement this method:
231                 // that's fine, just use the original method
232             }
233         }
234         return method;
235     }
236 }