View Javadoc

1   /*
2    * $Id: MuleInvoker.java 12304 2008-07-11 20:08:47Z dandiep $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.transport.cxf;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.api.MuleException;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.config.MuleProperties;
17  import org.mule.api.endpoint.InboundEndpoint;
18  import org.mule.api.service.ServiceException;
19  import org.mule.transport.NullPayload;
20  
21  import java.lang.reflect.Method;
22  import java.lang.reflect.Proxy;
23  
24  import org.apache.cxf.frontend.MethodDispatcher;
25  import org.apache.cxf.interceptor.Fault;
26  import org.apache.cxf.message.Exchange;
27  import org.apache.cxf.message.FaultMode;
28  import org.apache.cxf.message.MessageContentsList;
29  import org.apache.cxf.service.Service;
30  import org.apache.cxf.service.invoker.Invoker;
31  import org.apache.cxf.service.model.BindingOperationInfo;
32  
33  /**
34   * Invokes a Mule Service via a CXF binding.
35   */
36  public class MuleInvoker implements Invoker
37  {
38      private final CxfMessageReceiver receiver;
39      private final boolean synchronous;
40      private Class<?> targetClass;
41      
42      public MuleInvoker(CxfMessageReceiver receiver, Class<?> targetClass, boolean synchronous)
43      {
44          this.receiver = receiver;
45          this.targetClass = targetClass;
46          this.synchronous = synchronous;
47      }
48  
49      public Object invoke(Exchange exchange, Object o)
50      {
51          
52          MuleMessage message = null;
53          try
54          {
55              MuleMessage reqMsg = (MuleMessage) exchange.getInMessage().get(CxfConstants.MULE_MESSAGE);
56              CxfMessageAdapter messageAdapter = (CxfMessageAdapter) receiver.getConnector().getMessageAdapter(
57                  reqMsg);
58              messageAdapter.setPayload(exchange.getInMessage());
59  
60              if (!receiver.isProxy())
61              {
62                  BindingOperationInfo bop = exchange.get(BindingOperationInfo.class);
63                  Service svc = exchange.get(Service.class);
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                  messageAdapter.setProperty(MuleProperties.MULE_METHOD_PROPERTY, m);
72              }
73              
74              DefaultMuleMessage muleReq = new DefaultMuleMessage(messageAdapter);
75              String replyTo = (String) exchange.getInMessage().get(MuleProperties.MULE_REPLY_TO_PROPERTY);
76              if (replyTo != null)
77              {
78                  muleReq.setReplyTo(replyTo);
79              }
80              
81              String corId = (String) exchange.getInMessage().get(MuleProperties.MULE_CORRELATION_ID_PROPERTY);
82              if (corId != null)
83              {
84                  muleReq.setCorrelationId(corId);
85              }
86  
87              String corGroupSize = (String) exchange.getInMessage().get(MuleProperties.MULE_CORRELATION_GROUP_SIZE_PROPERTY);
88              if (corGroupSize != null)
89              {
90                  muleReq.setCorrelationGroupSize(Integer.valueOf(corGroupSize));
91              }
92  
93              String corSeq = (String) exchange.getInMessage().get(MuleProperties.MULE_CORRELATION_SEQUENCE_PROPERTY);
94              if (corSeq != null)
95              {
96                  muleReq.setCorrelationSequence(Integer.valueOf(corSeq));
97              }
98              
99              message = receiver.routeMessage(muleReq, synchronous);
100         }
101         catch (MuleException e)
102         {
103             throw new Fault(e);
104         }
105 
106         if (message != null)
107         {
108             if (message.getExceptionPayload() != null)
109             {
110                 Throwable cause = message.getExceptionPayload().getException();
111                 if (cause instanceof ServiceException)
112                 {
113                     cause = cause.getCause();
114                 }
115 
116                 exchange.getInMessage().put(FaultMode.class, FaultMode.UNCHECKED_APPLICATION_FAULT);
117                 if (cause instanceof Fault)
118                 {
119                     throw (Fault) cause;
120                 }
121 
122                 throw new Fault(cause);
123             }
124             else if (message.getPayload() instanceof NullPayload)
125             {
126                 return new MessageContentsList((Object)null);
127             }
128             else
129             {
130                 return new Object[]{message.getPayload()};
131             }
132         }
133         else
134         {
135             return new MessageContentsList((Object)null);
136         }
137     }
138 
139     public InboundEndpoint getEndpoint()
140     {
141         return receiver.getEndpoint();
142     }
143 
144     /**
145      * Returns a Method that has the same declaring class as the class of
146      * targetObject to avoid the IllegalArgumentException when invoking the
147      * method on the target object. The methodToMatch will be returned if the
148      * targetObject doesn't have a similar method.
149      * 
150      * @param methodToMatch The method to be used when finding a matching method
151      *            in targetObject
152      * @param targetObject The object to search in for the method.
153      * @return The methodToMatch if no such method exist in the class of
154      *         targetObject; otherwise, a method from the class of targetObject
155      *         matching the matchToMethod method.
156      */
157     private static Method matchMethod(Method methodToMatch, Class<?> targetClass) {
158         Class<?>[] interfaces = targetClass.getInterfaces();
159         for (int i = 0; i < interfaces.length; i++) {
160             Method m = getMostSpecificMethod(methodToMatch, interfaces[i]);
161             if (!methodToMatch.equals(m)) {
162                 return m;
163             }
164         }
165         return methodToMatch;
166     }
167 
168     /**
169      * Return whether the given object is a J2SE dynamic proxy.
170      * 
171      * @param object the object to check
172      * @see java.lang.reflect.Proxy#isProxyClass
173      */
174     public static boolean isJdkDynamicProxy(Object object) {
175         return object != null && Proxy.isProxyClass(object.getClass());
176     }
177 
178     /**
179      * Given a method, which may come from an interface, and a targetClass used
180      * in the current AOP invocation, find the most specific method if there is
181      * one. E.g. the method may be IFoo.bar() and the target class may be
182      * DefaultFoo. In this case, the method may be DefaultFoo.bar(). This
183      * enables attributes on that method to be found.
184      * 
185      * @param method method to be invoked, which may come from an interface
186      * @param targetClass target class for the curren invocation. May be
187      *            <code>null</code> or may not even implement the method.
188      * @return the more specific method, or the original method if the
189      *         targetClass doesn't specialize it or implement it or is null
190      */
191     public static Method getMostSpecificMethod(Method method, Class<?> targetClass) {
192         if (method != null && targetClass != null) {
193             try {
194                 method = targetClass.getMethod(method.getName(), method.getParameterTypes());
195             } catch (NoSuchMethodException ex) {
196                 // Perhaps the target class doesn't implement this method:
197                 // that's fine, just use the original method
198             }
199         }
200         return method;
201     }
202 }