View Javadoc

1   /*
2    * $Id: MuleInvoker.java 22728 2011-08-24 15:51:41Z pablo.kraan $
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.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  
86              Throwable cause = e;
87              if (e instanceof ComponentException) {
88                  cause = e.getCause();
89              }
90              throw new Fault(cause);
91          }
92          catch (RuntimeException e)
93          {
94              exchange.put(CxfConstants.MULE_EVENT, event);
95              throw new Fault(e);
96          }
97  
98          if (!event.getExchangePattern().hasResponse())
99          {
100             // weird response from AbstractInterceptingMessageProcessor
101             responseEvent = null;
102         }
103         
104         if (responseEvent != null)
105         {
106             exchange.put(CxfConstants.MULE_EVENT, responseEvent);
107             MuleMessage resMessage = responseEvent.getMessage();
108             
109             if (resMessage.getExceptionPayload() != null)
110             {
111                 Throwable cause = resMessage.getExceptionPayload().getException();
112                 if (cause instanceof ComponentException)
113                 {
114                     cause = cause.getCause();
115                 }
116 
117                 exchange.getInMessage().put(FaultMode.class, FaultMode.UNCHECKED_APPLICATION_FAULT);
118                 if (cause instanceof Fault)
119                 {
120                     throw (Fault) cause;
121                 }
122 
123                 throw new Fault(cause);
124             }
125             else if (resMessage.getPayload() instanceof NullPayload)
126             {
127                 return new MessageContentsList((Object)null);
128             }
129             else if (cxfMmessageProcessor.isProxy())
130             {
131                 resMessage.getPayload();
132                 return new Object[] { resMessage };
133             }
134             else
135             {
136                 return new Object[]{resMessage.getPayload()};
137             }
138         }
139         else
140         {
141             exchange.getInMessage().getInterceptorChain().abort();
142             if (exchange.getOutMessage() != null)
143             {
144                 exchange.getOutMessage().getInterceptorChain().abort();
145             }
146             exchange.put(CxfConstants.MULE_EVENT, null);
147             return null;
148         }
149     }
150     
151     protected Object extractPayload(Message cxfMessage)
152     {   
153         List<Object> list = CastUtils.cast(cxfMessage.getContent(List.class));
154         if (list == null)
155         {
156             // Seems Providers get objects stored this way
157             Object object = cxfMessage.getContent(Object.class);
158             if (object != null)
159             {
160                 return object;
161             }
162             else
163             {
164                 return new Object[0];
165             }
166         }
167         
168         if ((list.size() == 1) && (list.get(0) != null))
169         {
170             return list.get(0);
171         }
172         else
173         {
174             return list.toArray();
175         }
176     }
177 
178     /**
179      * Returns a Method that has the same declaring class as the class of
180      * targetObject to avoid the IllegalArgumentException when invoking the
181      * method on the target object. The methodToMatch will be returned if the
182      * targetObject doesn't have a similar method.
183      * 
184      * @param methodToMatch The method to be used when finding a matching method
185      *            in targetObject
186      * @param targetClass The class to search in for the method.
187      * @return The methodToMatch if no such method exist in the class of
188      *         targetObject; otherwise, a method from the class of targetObject
189      *         matching the matchToMethod method.
190      */
191     private static Method matchMethod(Method methodToMatch, Class<?> targetClass) 
192     {
193         Class<?>[] interfaces = targetClass.getInterfaces();
194         for (int i = 0; i < interfaces.length; i++) 
195         {
196             Method m = getMostSpecificMethod(methodToMatch, interfaces[i]);
197             if (!methodToMatch.equals(m)) 
198             {
199                 return m;
200             }
201         }
202         return methodToMatch;
203     }
204 
205     /**
206      * Return whether the given object is a J2SE dynamic proxy.
207      * 
208      * @param object the object to check
209      * @see java.lang.reflect.Proxy#isProxyClass
210      */
211     public static boolean isJdkDynamicProxy(Object object) 
212     {
213         return object != null && Proxy.isProxyClass(object.getClass());
214     }
215 
216     /**
217      * Given a method, which may come from an interface, and a targetClass used
218      * in the current AOP invocation, find the most specific method if there is
219      * one. E.g. the method may be IFoo.bar() and the target class may be
220      * DefaultFoo. In this case, the method may be DefaultFoo.bar(). This
221      * enables attributes on that method to be found.
222      * 
223      * @param method method to be invoked, which may come from an interface
224      * @param targetClass target class for the curren invocation. May be
225      *            <code>null</code> or may not even implement the method.
226      * @return the more specific method, or the original method if the
227      *         targetClass doesn't specialize it or implement it or is null
228      */
229     public static Method getMostSpecificMethod(Method method, Class<?> targetClass) {
230         if (method != null && targetClass != null) {
231             try {
232                 method = targetClass.getMethod(method.getName(), method.getParameterTypes());
233             } catch (NoSuchMethodException ex) {
234                 // Perhaps the target class doesn't implement this method:
235                 // that's fine, just use the original method
236             }
237         }
238         return method;
239     }
240 }