View Javadoc

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