View Javadoc

1   /*
2    * $Id: AxisServiceProxy.java 11373 2008-03-15 05:03:10Z dfeist $
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.soap.axis;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.RequestContext;
15  import org.mule.api.ExceptionPayload;
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.MessageAdapter;
25  import org.mule.config.ExceptionHelper;
26  import org.mule.transport.AbstractMessageReceiver;
27  import org.mule.transport.soap.SoapConstants;
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              MessageAdapter messageAdapter = receiver.getConnector().getMessageAdapter(args);
75              messageAdapter.setProperty(MuleProperties.MULE_METHOD_PROPERTY, method);
76              
77              // add all custom headers, filter out all mule headers (such as
78              // MULE_SESSION) except
79              // for MULE_USER header. Filter out other headers like "soapMethods" and
80              // MuleProperties.MULE_METHOD_PROPERTY and "soapAction"
81              // and also filter out any http related header
82              messageAdapter.addProperties(AxisCleanAndAddProperties.cleanAndAdd(RequestContext.getEventContext()));                        
83                                     
84              MuleMessage message = receiver.routeMessage(new DefaultMuleMessage(messageAdapter), synchronous);
85              
86              if (message != null)
87              {
88                  ExceptionPayload wsException = message.getExceptionPayload();
89  
90                  if (wsException != null)
91                  {
92                      MuleException umoException = ExceptionHelper.getRootMuleException(wsException.getException());
93                      // if the exception has a cause, then throw only the cause
94                      if (umoException.getCause() != null)
95                      {
96                          throw umoException.getCause();
97                      }
98                      else
99                      {
100                         throw umoException;
101                     }
102                 }
103 
104                 return message.getPayload();
105             }
106             else
107             {
108                 return null;
109             }
110         }
111     }
112 
113     /*
114        This is a horrible hack, which is axis-specific (no general classes are affected).  It was
115        added to allow service interface to be configured on endpoints.  The reason it needs to be
116        via a global thread local is that:
117        - the routine getInterfacesForComponent is called from "callback" objects, of which at least
118          one is set in the axis connector.  So the endpoint properties are unavailable when set.
119        - the information passed to the callback is sufficient to identify the component, but not
120          the endpoint, and we would like this configuration to be endpoint specific for two
121          reasons: (i) it is more flexible and (ii) we want to avoid transport specific config
122          on the component (setting it on the connector is way too constraining)
123        - the only other solution (which also uses thread local globals) would be to use the
124          request context, but this is called, amongst other places, from the create() method
125          of the axis message receiver, so no request context is currently in scope.
126        I apologise for this poor code, but after discussing it with rest of the 2.x team we
127        decided that if it worked, it was probably sufficient, since axis 1 support is largely
128        legacy-based.  AC.
129      */
130     public static void setProperties(Map properties)
131     {
132         AxisServiceProxy.properties.set(properties);
133     }
134 
135     public static Class[] getInterfacesForComponent(Service service)
136         throws MuleException, ClassNotFoundException
137     {
138         Class[] interfaces;
139         List ifaces = null;
140 
141         Map localProperties = (Map) properties.get();
142         if (null != localProperties)
143         {
144             ifaces = (List) localProperties.get(SoapConstants.SERVICE_INTERFACES);
145         }
146         if (ifaces == null || ifaces.size() == 0)
147         {
148             final Class implementationClass;
149 
150             if (service.getComponent() instanceof JavaComponent)
151             {
152                 try
153                 {
154                     implementationClass = ((JavaComponent) service.getComponent()).getObjectType();
155                 }
156                 catch (Exception e)
157                 {
158                     throw new ClassNotFoundException("Unable to retrieve class from service factory", e);
159                 }
160             }
161             else
162             {
163                 throw new ClassNotFoundException("Unable to retrieve class from service factory");
164             }
165             
166 
167             // get all implemented interfaces from superclasses as well
168             final List intfList = ClassUtils.getAllInterfaces(implementationClass);
169             interfaces = (Class[])intfList.toArray(new Class[intfList.size()]);
170         }
171         else
172         {
173             interfaces = new Class[ifaces.size()];
174             for (int i = 0; i < ifaces.size(); i++)
175             {
176                 String iface = (String)ifaces.get(i);
177                 interfaces[i] = ClassUtils.loadClass(iface, AxisServiceProxy.class);
178             }
179         }
180 
181         interfaces = removeInterface(interfaces, Callable.class);
182         interfaces = removeInterface(interfaces, Disposable.class);
183         interfaces = removeInterface(interfaces, Initialisable.class);
184         return interfaces;
185     }
186 
187     public static Class[] removeInterface(Class[] interfaces, Class iface)
188     {
189         if (interfaces == null)
190         {
191             return null;
192         }
193         List results = new ArrayList();
194         for (int i = 0; i < interfaces.length; i++)
195         {
196             Class anInterface = interfaces[i];
197             if (!anInterface.equals(iface))
198             {
199                 results.add(anInterface);
200             }
201         }
202         Class[] arResults = new Class[results.size()];
203         if (arResults.length == 0)
204         {
205             return arResults;
206         }
207         else
208         {
209             results.toArray(arResults);
210             return arResults;
211         }
212     }
213 
214     public static Method[] getMethods(Class[] interfaces)
215     {
216         List methodNames = new ArrayList();
217         for (int i = 0; i < interfaces.length; i++)
218         {
219             methodNames.addAll(Arrays.asList(interfaces[i].getMethods()));
220         }
221         Method[] results = new Method[methodNames.size()];
222         return (Method[])methodNames.toArray(results);
223 
224     }
225 
226     public static String[] getMethodNames(Class[] interfaces)
227     {
228         Method[] methods = getMethods(interfaces);
229 
230         String[] results = new String[methods.length];
231         for (int i = 0; i < results.length; i++)
232         {
233             results[i] = methods[i].getName();
234         }
235         return results;
236     }
237 
238 }