View Javadoc

1   /*
2    * $Id: AxisMessageReceiver.java 7976 2007-08-21 14:26:13Z dirk.olmes $
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.providers.soap.axis;
12  
13  import org.mule.config.i18n.CoreMessages;
14  import org.mule.impl.MuleDescriptor;
15  import org.mule.providers.AbstractMessageReceiver;
16  import org.mule.providers.soap.NamedParameter;
17  import org.mule.providers.soap.ServiceProxy;
18  import org.mule.providers.soap.SoapMethod;
19  import org.mule.providers.soap.axis.extensions.MuleMsgProvider;
20  import org.mule.providers.soap.axis.extensions.MuleRPCProvider;
21  import org.mule.providers.soap.axis.i18n.AxisMessages;
22  import org.mule.umo.UMOComponent;
23  import org.mule.umo.UMOException;
24  import org.mule.umo.endpoint.UMOEndpoint;
25  import org.mule.umo.endpoint.UMOEndpointURI;
26  import org.mule.umo.lifecycle.InitialisationException;
27  import org.mule.umo.provider.UMOConnector;
28  import org.mule.util.StringUtils;
29  
30  import java.util.HashMap;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Map;
34  
35  import javax.xml.rpc.ParameterMode;
36  
37  import org.apache.axis.AxisProperties;
38  import org.apache.axis.constants.Style;
39  import org.apache.axis.constants.Use;
40  import org.apache.axis.description.OperationDesc;
41  import org.apache.axis.description.ParameterDesc;
42  import org.apache.axis.handlers.soap.SOAPService;
43  import org.apache.axis.providers.java.JavaProvider;
44  import org.apache.axis.wsdl.fromJava.Namespaces;
45  
46  /**
47   * <code>AxisMessageReceiver</code> is used to register a component as a service
48   * with a Axis server.
49   */
50  
51  public class AxisMessageReceiver extends AbstractMessageReceiver
52  {
53      protected AxisConnector connector;
54      protected SOAPService service;
55  
56      public AxisMessageReceiver(UMOConnector connector, UMOComponent component, UMOEndpoint endpoint)
57          throws InitialisationException
58      {
59          super(connector, component, endpoint);
60          this.connector = (AxisConnector)connector;
61          try
62          {
63              init();
64          }
65          catch (Exception e)
66          {
67              throw new InitialisationException(e, this);
68          }
69      }
70  
71      protected void init() throws Exception
72      {
73          AxisProperties.setProperty("axis.doAutoTypes", String.valueOf(connector.isDoAutoTypes()));
74          MuleDescriptor descriptor = (MuleDescriptor)component.getDescriptor();
75          String style = (String)descriptor.getProperties().get("style");
76          String use = (String)descriptor.getProperties().get("use");
77          String doc = (String)descriptor.getProperties().get("documentation");
78  
79          UMOEndpointURI uri = endpoint.getEndpointURI();
80          String serviceName = component.getDescriptor().getName();
81  
82          SOAPService existing = this.connector.getAxisServer().getService(serviceName);
83          if (existing != null)
84          {
85              service = existing;
86              logger.debug("Using existing service for " + serviceName);
87          }
88          else
89          {
90              // Check if the style is message. If so, we need to create
91              // a message oriented provider
92              if (style != null && style.equalsIgnoreCase("message"))
93              {
94                  logger.debug("Creating Message Provider");
95                  service = new SOAPService(new MuleMsgProvider(connector));
96                  // } else if (style != null && style.equalsIgnoreCase("document")) {
97                  // logger.debug("Creating Doc Provider");
98                  // service = new SOAPService(new MuleDocLitProvider(connector));
99              }
100             else
101             {
102                 logger.debug("Creating RPC Provider");
103                 service = new SOAPService(new MuleRPCProvider(connector));
104             }
105 
106             service.setEngine(connector.getAxisServer());
107         }
108 
109         String servicePath = uri.getPath();
110         service.setOption(serviceName, this);
111         service.setOption(AxisConnector.SERVICE_PROPERTY_SERVCE_PATH, servicePath);
112         service.setOption(AxisConnector.SERVICE_PROPERTY_COMPONENT_NAME, serviceName);
113 
114         service.setName(serviceName);
115 
116         // Add any custom options from the Descriptor config
117         Map options = (Map)descriptor.getProperties().get("axisOptions");
118 
119         // IF wsdl service name is not set, default to service name
120         if (options == null)
121         {
122             options = new HashMap(2);
123         }
124         if (options.get("wsdlServiceElement") == null)
125         {
126             options.put("wsdlServiceElement", serviceName);
127         }
128 
129         Map.Entry entry;
130         for (Iterator iterator = options.entrySet().iterator(); iterator.hasNext();)
131         {
132             entry = (Map.Entry)iterator.next();
133             service.setOption(entry.getKey().toString(), entry.getValue());
134             logger.debug("Adding Axis option: " + entry);
135         }
136 
137         // set method names
138         Class[] interfaces = ServiceProxy.getInterfacesForComponent(component);
139         if (interfaces.length == 0)
140         {
141             throw new InitialisationException(
142                 AxisMessages.objectMustImplementAnInterface(serviceName), component);
143         }
144         // You must supply a class name if you want to restrict methods
145         // or specify the 'allowedMethods' property in the axisOptions property
146         String methodNames = "*";
147 
148         Map methods = (Map)endpoint.getProperties().get("soapMethods");
149         if (methods == null)
150         {
151             methods = (Map)descriptor.getProperties().get("soapMethods");
152         }
153         if (methods != null)
154         {
155             Iterator i = methods.keySet().iterator();
156             StringBuffer buf = new StringBuffer(64);
157             while (i.hasNext())
158             {
159                 String name = (String)i.next();
160                 Object m = methods.get(name);
161                 SoapMethod method = null;
162                 if (m instanceof List)
163                 {
164                     method = new SoapMethod(name, (List)m);
165                 }
166                 else
167                 {
168                     method = new SoapMethod(name, (String)m);
169                 }
170 
171                 List namedParameters = method.getNamedParameters();
172                 ParameterDesc[] parameters = new ParameterDesc[namedParameters.size()];
173                 for (int j = 0; j < namedParameters.size(); j++)
174                 {
175                     NamedParameter parameter = (NamedParameter)namedParameters.get(j);
176                     byte mode = ParameterDesc.INOUT;
177                     if (parameter.getMode().equals(ParameterMode.IN))
178                     {
179                         mode = ParameterDesc.IN;
180                     }
181                     else if (parameter.getMode().equals(ParameterMode.OUT))
182                     {
183                         mode = ParameterDesc.OUT;
184                     }
185 
186                     parameters[j] = new ParameterDesc(parameter.getName(), mode, parameter.getType());
187                 }
188 
189                 service.getServiceDescription().addOperationDesc(
190                     new OperationDesc(method.getName().getLocalPart(), parameters, method.getReturnType()));
191                 buf.append(method.getName().getLocalPart() + ",");
192             }
193             methodNames = buf.toString();
194             methodNames = methodNames.substring(0, methodNames.length() - 1);
195         }
196         else
197         {
198             String[] methodNamesArray = ServiceProxy.getMethodNames(interfaces);
199             StringBuffer buf = new StringBuffer(64);
200             for (int i = 0; i < methodNamesArray.length; i++)
201             {
202                 buf.append(methodNamesArray[i]).append(",");
203             }
204             methodNames = buf.toString();
205             methodNames = methodNames.substring(0, methodNames.length() - 1);
206         }
207 
208         String className = interfaces[0].getName();
209         // The namespace of the service.
210         // Todo use the service qname in Mule 2.0
211         String namespace = (String)descriptor.getProperties().get("serviceNamespace");
212         if (namespace == null)
213         {
214             namespace = Namespaces.makeNamespace(className);
215         }
216 
217         // WSDL override
218         String wsdlFile = (String)descriptor.getProperties().get("wsdlFile");
219         if (wsdlFile != null)
220         {
221             service.getServiceDescription().setWSDLFile(wsdlFile);
222         }
223         /*
224          * Now we set up the various options for the SOAPService. We set:
225          * RPCProvider.OPTION_WSDL_SERVICEPORT In essense, this is our service name
226          * RPCProvider.OPTION_CLASSNAME This tells the serverProvider (whether it be
227          * an AvalonProvider or just JavaProvider) what class to load via
228          * "makeNewServiceObject". RPCProvider.OPTION_SCOPE How long the object
229          * loaded via "makeNewServiceObject" will persist - either request, session,
230          * or application. We use the default for now.
231          * RPCProvider.OPTION_WSDL_TARGETNAMESPACE A namespace created from the
232          * package name of the service. RPCProvider.OPTION_ALLOWEDMETHODS What
233          * methods the service can execute on our class. We don't set:
234          * RPCProvider.OPTION_WSDL_PORTTYPE RPCProvider.OPTION_WSDL_SERVICEELEMENT
235          */
236         setOptionIfNotset(service, JavaProvider.OPTION_WSDL_SERVICEPORT, serviceName);
237         setOptionIfNotset(service, JavaProvider.OPTION_CLASSNAME, className);
238         setOptionIfNotset(service, JavaProvider.OPTION_SCOPE, "Request");
239         if (StringUtils.isNotBlank(namespace))
240         {
241             setOptionIfNotset(service, JavaProvider.OPTION_WSDL_TARGETNAMESPACE, namespace);
242         }
243 
244         // Set the allowed methods, allow all if there are none specified.
245         if (methodNames == null)
246         {
247             setOptionIfNotset(service, JavaProvider.OPTION_ALLOWEDMETHODS, "*");
248         }
249         else
250         {
251             setOptionIfNotset(service, JavaProvider.OPTION_ALLOWEDMETHODS, methodNames);
252         }
253 
254         // Note that Axis has specific rules to how these two variables are
255         // combined. This is handled for us
256         // Set style: RPC/wrapped/Doc/Message
257 
258         if (style != null)
259         {
260             Style s = Style.getStyle(style);
261             if (s == null)
262             {
263                 throw new InitialisationException(
264                     CoreMessages.valueIsInvalidFor(style, "style"), this);
265             }
266             else
267             {
268                 service.setStyle(s);
269             }
270         }
271         // Set use: Endcoded/Literal
272         if (use != null)
273         {
274             Use u = Use.getUse(use);
275             if (u == null)
276             {
277                 throw new InitialisationException(CoreMessages.valueIsInvalidFor(use, "use"),
278                     this);
279             }
280             else
281             {
282                 service.setUse(u);
283             }
284         }
285 
286         service.getServiceDescription().setDocumentation(doc);
287 
288         // Tell Axis to try and be intelligent about serialization.
289         // TypeMappingRegistryImpl registry = (TypeMappingRegistryImpl)
290         // service.getTypeMappingRegistry();
291         // TypeMappingImpl tm = (TypeMappingImpl) registry.();
292 
293         // Handle complex bean type automatically
294         // registry.setDoAutoTypes( true );
295 
296         // Axis 1.2 fix to handle autotypes properly
297         // AxisProperties.setProperty("axis.doAutoTypes",
298         // String.valueOf(connector.isDoAutoTypes()));
299 
300         // TODO Load any explicitly defined bean types
301         // List types = (List) descriptor.getProperties().get("beanTypes");
302         // connector.registerTypes(registry, types);
303 
304         service.setName(serviceName);
305 
306         // Add initialisation callback for the Axis service
307         descriptor.addInitialisationCallback(new AxisInitialisationCallback(service));
308 
309         if (uri.getScheme().equalsIgnoreCase("servlet"))
310         {
311             connector.addServletService(service);
312             String endpointUrl = uri.getAddress() + "/" + serviceName;
313             endpointUrl = endpointUrl.replaceFirst("servlet:", "http:");
314             service.getServiceDescription().setEndpointURL(endpointUrl);
315         }
316         else
317         {
318             service.getServiceDescription().setEndpointURL(uri.getAddress() + "/" + serviceName);
319         }
320         if (StringUtils.isNotBlank(namespace))
321         {
322             service.getServiceDescription().setDefaultNamespace(namespace);
323         }
324         service.init();
325         service.stop();
326     }
327 
328     protected void doConnect() throws Exception
329     {
330         // Tell the axis configuration about our new service.
331         connector.getServerProvider().deployService(service.getName(), service);
332         connector.registerReceiverWithMuleService(this, endpoint.getEndpointURI());
333     }
334 
335     protected void doDisconnect() throws Exception
336     {
337         try
338         {
339             doStop();
340         }
341         catch (UMOException e)
342         {
343             logger.error(e.getMessage(), e);
344         }
345         // TODO: how do you undeploy an Axis service?
346 
347         // Unregister the mule part of the service
348         connector.unregisterReceiverWithMuleService(this, endpoint.getEndpointURI());
349     }
350 
351     protected void doStart() throws UMOException
352     {
353         if (service != null)
354         {
355             service.start();
356         }
357     }
358 
359     protected void doStop() throws UMOException
360     {
361         if (service != null)
362         {
363             service.stop();
364         }
365     }
366 
367     protected void doDispose()
368     {
369         // nothing to do               
370     }
371 
372     protected void setOptionIfNotset(SOAPService service, String option, Object value)
373     {
374         Object val = service.getOption(option);
375         if (val == null)
376         {
377             service.setOption(option, value);
378         }
379     }
380 
381     public SOAPService getService()
382     {
383         return service;
384     }
385 }