View Javadoc

1   /*
2    * $Id: AxisServiceProxy.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.transport.soap.axis;
12  
13  import org.mule.RequestContext;
14  import org.mule.api.ExceptionPayload;
15  import org.mule.api.MuleEvent;
16  import org.mule.api.MuleException;
17  import org.mule.api.MuleMessage;
18  import org.mule.api.component.JavaComponent;
19  import org.mule.api.config.MuleProperties;
20  import org.mule.api.lifecycle.Callable;
21  import org.mule.api.lifecycle.Disposable;
22  import org.mule.api.lifecycle.Initialisable;
23  import org.mule.api.service.Service;
24  import org.mule.api.transport.PropertyScope;
25  import org.mule.config.ExceptionHelper;
26  import org.mule.module.cxf.SoapConstants;
27  import org.mule.transport.AbstractMessageReceiver;
28  import org.mule.transport.soap.axis.extras.AxisCleanAndAddProperties;
29  import org.mule.util.ClassUtils;
30  
31  import java.lang.reflect.InvocationHandler;
32  import java.lang.reflect.Method;
33  import java.lang.reflect.Proxy;
34  import java.util.ArrayList;
35  import java.util.Arrays;
36  import java.util.List;
37  import java.util.Map;
38  
39  /**
40   * <code>ServiceProxy</code> is a proxy that wraps a soap endpointUri to look like
41   * a Web service. Also provides helper methods for building and describing web
42   * service interfaces in Mule.
43   */
44  
45  public class AxisServiceProxy
46  {
47  
48      private static ThreadLocal properties = new ThreadLocal();
49  
50      public static Object createProxy(AbstractMessageReceiver receiver, boolean synchronous, Class[] classes)
51      {
52          final ClassLoader cl = Thread.currentThread().getContextClassLoader();
53          return Proxy.newProxyInstance(cl, classes, createServiceHandler(receiver, synchronous));
54      }
55  
56      public static InvocationHandler createServiceHandler(AbstractMessageReceiver receiver, boolean synchronous)
57      {
58          return new AxisServiceHandler(receiver, synchronous);
59      }
60  
61      private static class AxisServiceHandler implements InvocationHandler
62      {
63          private AbstractMessageReceiver receiver;
64          private boolean synchronous = true;
65  
66          public AxisServiceHandler(AbstractMessageReceiver receiver, boolean synchronous)
67          {
68              this.receiver = receiver;
69              this.synchronous = synchronous;
70          }
71  
72          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
73          {
74              MuleMessage messageToRoute = receiver.createMuleMessage(args,
75                  receiver.getEndpoint().getEncoding());
76              messageToRoute.setProperty(MuleProperties.MULE_METHOD_PROPERTY, method, PropertyScope.INVOCATION);
77              
78              // add all custom headers, filter out all mule headers (such as
79              // MULE_SESSION) except
80              // for MULE_USER header. Filter out other headers like "soapMethods" and
81              // MuleProperties.MULE_METHOD_PROPERTY and "soapAction"
82              // and also filter out any http related header
83              messageToRoute.addProperties(AxisCleanAndAddProperties.cleanAndAdd(RequestContext.getEventContext()));
84  
85              MuleEvent event = receiver.routeMessage(messageToRoute);
86              MuleMessage message = event == null ? null : event.getMessage();
87  
88              if (message != null)
89              {
90                  ExceptionPayload wsException = message.getExceptionPayload();
91  
92                  if (wsException != null)
93                  {
94                      MuleException exception = ExceptionHelper.getRootMuleException(wsException.getException());
95                      // if the exception has a cause, then throw only the cause
96                      if (exception.getCause() != null)
97                      {
98                          throw exception.getCause();
99                      }
100                     else
101                     {
102                         throw exception;
103                     }
104                 }
105 
106                 return message.getPayload();
107             }
108             else
109             {
110                 return null;
111             }
112         }
113     }
114 
115     /*
116        This is a horrible hack, which is axis-specific (no general classes are affected).  It was
117        added to allow service interface to be configured on endpoints.  The reason it needs to be
118        via a global thread local is that:
119        - the routine getInterfacesForComponent is called from "callback" objects, of which at least
120          one is set in the axis connector.  So the endpoint properties are unavailable when set.
121        - the information passed to the callback is sufficient to identify the component, but not
122          the endpoint, and we would like this configuration to be endpoint specific for two
123          reasons: (i) it is more flexible and (ii) we want to avoid transport specific config
124          on the component (setting it on the connector is way too constraining)
125        - the only other solution (which also uses thread local globals) would be to use the
126          request context, but this is called, amongst other places, from the create() method
127          of the axis message receiver, so no request context is currently in scope.
128        I apologise for this poor code, but after discussing it with rest of the 2.x team we
129        decided that if it worked, it was probably sufficient, since axis 1 support is largely
130        legacy-based.  AC.
131      */
132     public static void setProperties(Map properties)
133     {
134         AxisServiceProxy.properties.set(properties);
135     }
136 
137     public static Class[] getInterfacesForComponent(Service service)
138         throws MuleException, ClassNotFoundException
139     {
140         Class[] interfaces;
141         List ifaces = null;
142 
143         Map localProperties = (Map) properties.get();
144         if (null != localProperties)
145         {
146             ifaces = (List) localProperties.get(SoapConstants.SERVICE_INTERFACES);
147         }
148         if (ifaces == null || ifaces.size() == 0)
149         {
150             final Class implementationClass;
151 
152             if (service.getComponent() instanceof JavaComponent)
153             {
154                 try
155                 {
156                     implementationClass = ((JavaComponent) service.getComponent()).getObjectType();
157                 }
158                 catch (Exception e)
159                 {
160                     throw new ClassNotFoundException("Unable to retrieve class from service factory", e);
161                 }
162             }
163             else
164             {
165                 throw new ClassNotFoundException("Unable to retrieve class from service factory");
166             }
167             
168 
169             // get all implemented interfaces from superclasses as well
170             final List intfList = ClassUtils.getAllInterfaces(implementationClass);
171             interfaces = (Class[])intfList.toArray(new Class[intfList.size()]);
172         }
173         else
174         {
175             interfaces = new Class[ifaces.size()];
176             for (int i = 0; i < ifaces.size(); i++)
177             {
178                 String iface = (String)ifaces.get(i);
179                 interfaces[i] = ClassUtils.loadClass(iface, AxisServiceProxy.class);
180             }
181         }
182 
183         interfaces = removeInterface(interfaces, Callable.class);
184         interfaces = removeInterface(interfaces, Disposable.class);
185         interfaces = removeInterface(interfaces, Initialisable.class);
186         return interfaces;
187     }
188 
189     public static Class[] removeInterface(Class[] interfaces, Class iface)
190     {
191         if (interfaces == null)
192         {
193             return null;
194         }
195         List results = new ArrayList();
196         for (int i = 0; i < interfaces.length; i++)
197         {
198             Class anInterface = interfaces[i];
199             if (!anInterface.equals(iface))
200             {
201                 results.add(anInterface);
202             }
203         }
204         Class[] arResults = new Class[results.size()];
205         if (arResults.length == 0)
206         {
207             return arResults;
208         }
209         else
210         {
211             results.toArray(arResults);
212             return arResults;
213         }
214     }
215 
216     public static Method[] getMethods(Class[] interfaces)
217     {
218         List methodNames = new ArrayList();
219         for (int i = 0; i < interfaces.length; i++)
220         {
221             methodNames.addAll(Arrays.asList(interfaces[i].getMethods()));
222         }
223         Method[] results = new Method[methodNames.size()];
224         return (Method[])methodNames.toArray(results);
225 
226     }
227 
228     public static String[] getMethodNames(Class[] interfaces)
229     {
230         Method[] methods = getMethods(interfaces);
231 
232         String[] results = new String[methods.length];
233         for (int i = 0; i < results.length; i++)
234         {
235             results[i] = methods[i].getName();
236         }
237         return results;
238     }
239 
240 }