View Javadoc

1   /*
2    * $Id: XFireConnector.java 10164 2007-12-28 11:32:14Z marie.rizzo $
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.xfire;
12  
13  import org.mule.MuleManager;
14  import org.mule.impl.MuleDescriptor;
15  import org.mule.impl.endpoint.MuleEndpoint;
16  import org.mule.impl.internal.notifications.ManagerNotification;
17  import org.mule.impl.internal.notifications.ManagerNotificationListener;
18  import org.mule.impl.internal.notifications.NotificationException;
19  import org.mule.impl.model.ModelHelper;
20  import org.mule.providers.AbstractConnector;
21  import org.mule.providers.http.HttpConnector;
22  import org.mule.providers.http.HttpConstants;
23  import org.mule.providers.soap.MethodFixInterceptor;
24  import org.mule.providers.soap.xfire.i18n.XFireMessages;
25  import org.mule.umo.UMOComponent;
26  import org.mule.umo.UMOException;
27  import org.mule.umo.endpoint.UMOEndpoint;
28  import org.mule.umo.endpoint.UMOEndpointURI;
29  import org.mule.umo.lifecycle.InitialisationException;
30  import org.mule.umo.manager.UMOServerNotification;
31  import org.mule.umo.provider.UMOMessageReceiver;
32  import org.mule.util.ClassUtils;
33  import org.mule.util.StringUtils;
34  import org.mule.util.SystemUtils;
35  
36  import java.util.List;
37  import java.util.Map;
38  
39  import org.codehaus.xfire.DefaultXFire;
40  import org.codehaus.xfire.XFire;
41  import org.codehaus.xfire.aegis.AegisBindingProvider;
42  import org.codehaus.xfire.aegis.type.TypeMappingRegistry;
43  import org.codehaus.xfire.annotations.AnnotationServiceFactory;
44  import org.codehaus.xfire.annotations.WebAnnotations;
45  import org.codehaus.xfire.service.Service;
46  import org.codehaus.xfire.service.ServiceFactory;
47  import org.codehaus.xfire.service.binding.BindingProvider;
48  import org.codehaus.xfire.service.binding.ObjectServiceFactory;
49  import org.codehaus.xfire.soap.SoapConstants;
50  import org.codehaus.xfire.wsdl11.builder.WSDLBuilderFactory;
51  
52  /**
53   * Configures Xfire to provide STaX-based Web Servies support to Mule.
54   */
55  public class XFireConnector extends AbstractConnector
56      implements ManagerNotificationListener
57  {
58      public static final String XFIRE_SERVICE_COMPONENT_NAME = "_xfireServiceComponent";
59      public static final String DEFAULT_MULE_NAMESPACE_URI = "http://www.muleumo.org";
60      public static final String XFIRE_PROPERTY = "xfire";
61      public static final String XFIRE_TRANSPORT = "transportClass";
62  
63      public static final String CLASSNAME_ANNOTATIONS = "org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations";
64      private static final String DEFAULT_BINDING_PROVIDER_CLASS = "org.codehaus.xfire.aegis.AegisBindingProvider";
65      private static final String DEFAULT_TYPE_MAPPING_REGISTRY_CLASS = "org.codehaus.xfire.aegis.type.DefaultTypeMappingRegistry";
66  
67      protected MuleDescriptor xfireDescriptor;
68  
69      private XFire xfire;
70  
71      private ServiceFactory serviceFactory;
72  
73      private boolean enableJSR181Annotations = false;
74  
75      private List clientServices = null;
76      private List clientInHandlers = null;
77      private List clientOutHandlers = null;
78      private String clientTransport = null;
79  
80      private String bindingProvider = null;
81      private String typeMappingRegistry = null;
82      private String serviceTransport = null;
83      private List serverInHandlers = null;
84      private List serverOutHandlers = null;
85      
86      private Map extraProperties = null;
87  
88      public XFireConnector()
89      {
90          super();
91          registerProtocols();
92      }
93  
94      protected void registerProtocols()
95      {
96          registerSupportedProtocol("http");
97          registerSupportedProtocol("https");
98          registerSupportedProtocol("jms");
99          registerSupportedProtocol("vm");
100         registerSupportedProtocol("servlet");
101     }
102 
103     public String getProtocol()
104     {
105         return "xfire";
106     }
107 
108     protected void doInitialise() throws InitialisationException
109     {
110 
111         try
112         {
113             MuleManager.getInstance().registerListener(this);
114         }
115         catch (NotificationException e)
116         {
117             throw new InitialisationException(e, this);
118         }
119 
120         if (xfire == null)
121         {
122             xfire = new DefaultXFire();
123         }
124 
125         if (clientServices != null)
126         {
127             ObjectServiceFactory factory = new ObjectServiceFactory();
128             configureBindingProvider(factory);
129 
130             for (int i = 0; i < clientServices.size(); i++)
131             {
132                 try
133                 {
134                     Class clazz = ClassUtils.loadClass(clientServices.get(i).toString(), this.getClass());
135                     Service service = factory.create(clazz);
136                     xfire.getServiceRegistry().register(service);
137                 }
138                 catch (ClassNotFoundException e)
139                 {
140                     throw new InitialisationException(
141                         XFireMessages.couldNotInitAnnotationProcessor(clientServices.get(i)), e, this);
142                 }
143             }
144         }
145 
146         if (serviceFactory == null)
147         {
148             if (enableJSR181Annotations)
149             {
150                 // are we running under Java 5 (at least)?
151                 if (!SystemUtils.isJavaVersionAtLeast(150))
152                 {
153                     throw new InitialisationException(
154                         XFireMessages.annotationsRequireJava5(), this);
155                 }
156                 try
157                 {
158                     WebAnnotations wa = (WebAnnotations)ClassUtils.instanciateClass(
159                         CLASSNAME_ANNOTATIONS, null, this.getClass());
160                     serviceFactory = new AnnotationServiceFactory(wa, xfire.getTransportManager());
161                     configureBindingProvider((ObjectServiceFactory)serviceFactory);
162                 }
163                 catch (Exception ex)
164                 {
165                     throw new InitialisationException(
166                         XFireMessages.couldNotInitAnnotationProcessor(CLASSNAME_ANNOTATIONS), ex, this);
167                 }
168             }
169             else
170             {
171                 serviceFactory = new MuleObjectServiceFactory(xfire.getTransportManager());
172                 configureBindingProvider((ObjectServiceFactory)serviceFactory);
173             }
174         }
175 
176         if (serviceFactory instanceof ObjectServiceFactory)
177         {
178             ObjectServiceFactory osf = (ObjectServiceFactory)serviceFactory;
179             if (osf.getTransportManager() == null)
180             {
181                 osf.setTransportManager(xfire.getTransportManager());
182             }
183 
184         }
185     }
186 
187     protected void configureBindingProvider(ObjectServiceFactory factory) throws InitialisationException
188     {
189         if (StringUtils.isBlank(bindingProvider))
190         {
191             bindingProvider = DEFAULT_BINDING_PROVIDER_CLASS;
192         }
193 
194         if (StringUtils.isBlank(typeMappingRegistry))
195         {
196             typeMappingRegistry = DEFAULT_TYPE_MAPPING_REGISTRY_CLASS;
197         }
198 
199         try
200         {
201             Class clazz = ClassUtils.loadClass(bindingProvider, this.getClass());
202             BindingProvider provider = (BindingProvider)ClassUtils.instanciateClass(clazz, new Object[] {} );
203 
204             // Create the argument of TypeMappingRegistry ONLY if the binding 
205             // provider is aegis and the type mapping registry is not the default
206             if (bindingProvider.equals(DEFAULT_BINDING_PROVIDER_CLASS) && !typeMappingRegistry.equals(DEFAULT_TYPE_MAPPING_REGISTRY_CLASS))
207             {
208                 Class registryClazz = ClassUtils.loadClass(typeMappingRegistry, this.getClass());
209 
210                 // No constructor arguments for the mapping registry
211                 //
212                 // Note that if we had to create the DefaultTypeMappingRegistry here
213                 // we would need to pass in a boolean argument of true to the
214                 // constructor. Currently, it appears that all other registries
215                 // can be created with zero argument constructors
216                 TypeMappingRegistry registry = (TypeMappingRegistry)ClassUtils.instanciateClass(registryClazz, new Object[] { } );
217                 ((AegisBindingProvider)provider).setTypeMappingRegistry(registry);
218             }
219 
220             factory.setBindingProvider(provider);
221 
222             String wsdlBuilderFactoryClass = null;
223 
224             // Special handling for MessageBindingProvider
225             if (bindingProvider.equals("org.codehaus.xfire.service.binding.MessageBindingProvider"))
226             {
227                 factory.setStyle(SoapConstants.STYLE_MESSAGE);
228             }
229 
230             // See MULE-1871
231 //            // Special handling for XmlBeansBindingProvider
232 //            if (bindingProvider.equals("org.codehaus.xfire.service.binding.MessageBindingProvider"))
233 //            {
234 //                factory.setStyle(SoapConstants.STYLE_DOCUMENT);
235 //                wsdlBuilderFactoryClass = "org.codehaus.xfire.xmlbeans.XmlBeansWSDLBuilderFactory";
236 //            }
237 
238             // If required, create the WSDL builder factory (only XML beans needs
239             // this)
240             if (wsdlBuilderFactoryClass != null)
241             {
242                 Class wsdlBuilderFactoryClazz = ClassUtils.loadClass(wsdlBuilderFactoryClass, this.getClass());
243                 WSDLBuilderFactory wsdlBuilderFactory = (WSDLBuilderFactory)ClassUtils.instanciateClass(wsdlBuilderFactoryClazz, new Object[] { } );
244                 factory.setWsdlBuilderFactory(wsdlBuilderFactory);
245             }
246         }
247         catch (Exception ex)
248         {
249             throw new InitialisationException(
250                 XFireMessages.unableToInitBindingProvider(bindingProvider), ex, this);
251         }
252 
253     }
254 
255     protected void doDispose()
256     {
257         // template method
258     }
259 
260     protected void doConnect() throws Exception
261     {
262         // template method
263     }
264 
265     protected void doDisconnect() throws Exception
266     {
267         // template method
268     }
269 
270     protected void doStart() throws UMOException
271     {
272         // template method
273     }
274 
275     protected void doStop() throws UMOException
276     {
277         // template method
278     }
279 
280     public XFire getXfire()
281     {
282         return xfire;
283     }
284 
285     public void setXfire(XFire xfire)
286     {
287         this.xfire = xfire;
288     }
289 
290     protected void registerReceiverWithMuleService(UMOMessageReceiver receiver, UMOEndpointURI ep)
291         throws UMOException
292     {
293         // If this is the first receiver we need to create the Axis service
294         // component
295         // this will be registered with Mule when the Connector starts
296         if (xfireDescriptor == null)
297         {
298             // See if the xfire descriptor has already been added. This allows
299             // developers to override the default configuration, say to increase
300             // the threadpool
301             xfireDescriptor = (MuleDescriptor)MuleManager.getInstance().lookupModel(ModelHelper.SYSTEM_MODEL).getDescriptor(
302                 XFIRE_SERVICE_COMPONENT_NAME + getName());
303             if (xfireDescriptor == null)
304             {
305                 xfireDescriptor = createxfireDescriptor();
306             }
307             else
308             {
309                 // Lets unregister the 'template' instance, configure it and
310                 // then register
311                 // again later
312                 MuleManager.getInstance().lookupModel(ModelHelper.SYSTEM_MODEL).unregisterComponent(xfireDescriptor);
313             }
314             // if the axis server hasn't been set, set it now. The Axis server
315             // may be set externally
316             if (xfireDescriptor.getProperties().get(XFIRE_PROPERTY) == null)
317             {
318                 xfireDescriptor.getProperties().put(XFIRE_PROPERTY, xfire);
319             }
320             if (serviceTransport != null
321                 && xfireDescriptor.getProperties().get(XFIRE_TRANSPORT) == null)
322             {
323                 xfireDescriptor.getProperties().put(XFIRE_TRANSPORT, serviceTransport);
324             }
325             xfireDescriptor.setContainerManaged(false);
326         }
327         String serviceName = receiver.getComponent().getDescriptor().getName();
328 
329         // No determine if the endpointUri requires a new connector to be
330         // registed in the case of http we only need to register the new
331         // endpointUri if the port is different
332         String endpoint = receiver.getEndpointURI().getAddress();
333         String scheme = ep.getScheme().toLowerCase();
334 
335 
336         boolean sync = receiver.getEndpoint().isSynchronous();
337 
338         // If we are using sockets then we need to set the endpoint name appropiately
339         // and if using http/https
340         // we need to default to POST and set the Content-Type
341         if (scheme.equals("http") || scheme.equals("https") || scheme.equals("ssl")
342             || scheme.equals("tcp") || scheme.equals("servlet"))
343         {
344             endpoint += "/" + serviceName;
345             receiver.getEndpoint().getProperties().put(HttpConnector.HTTP_METHOD_PROPERTY, "POST");
346             receiver.getEndpoint().getProperties().put(HttpConstants.HEADER_CONTENT_TYPE,
347                 "text/xml");
348 
349             // Default to using synchronous for socket based protocols unless the
350             // synchronous property has been set explicitly
351             if (!receiver.getEndpoint().isSynchronousSet())
352             {
353                 sync = true;
354             }
355         }
356        
357 
358         UMOEndpoint serviceEndpoint = new MuleEndpoint(endpoint, true);
359         serviceEndpoint.setSynchronous(sync);
360         serviceEndpoint.setName(ep.getScheme() + ":" + serviceName);
361 
362         // Set the transformers on the endpoint too
363         serviceEndpoint.setTransformer(receiver.getEndpoint().getTransformer());
364         receiver.getEndpoint().setTransformer(null);
365 
366         serviceEndpoint.setResponseTransformer(receiver.getEndpoint().getResponseTransformer());
367         receiver.getEndpoint().setResponseTransformer(null);
368 
369         // set the filter on the axis endpoint on the real receiver endpoint
370         serviceEndpoint.setFilter(receiver.getEndpoint().getFilter());
371         // Remove the Axis filter now
372         receiver.getEndpoint().setFilter(null);
373 
374         // set the Security filter on the axis endpoint on the real receiver
375         // endpoint
376         serviceEndpoint.setSecurityFilter(receiver.getEndpoint().getSecurityFilter());
377         // Remove the Axis Receiver Security filter now
378         receiver.getEndpoint().setSecurityFilter(null);
379         xfireDescriptor.getInboundRouter().addEndpoint(serviceEndpoint);
380     }
381 
382     protected MuleDescriptor createxfireDescriptor()
383     {
384         MuleDescriptor xfireDescriptor = (MuleDescriptor)MuleManager.getInstance().lookupModel(ModelHelper.SYSTEM_MODEL)
385             .getDescriptor(XFIRE_SERVICE_COMPONENT_NAME + getName());
386         if (xfireDescriptor == null)
387         {
388             xfireDescriptor = new MuleDescriptor(XFIRE_SERVICE_COMPONENT_NAME + getName());
389             xfireDescriptor.setImplementation(XFireServiceComponent.class.getName());
390         }
391         return xfireDescriptor;
392     }
393 
394     public ServiceFactory getServiceFactory()
395     {
396         return serviceFactory;
397     }
398 
399     public void setServiceFactory(ServiceFactory serviceFactory)
400     {
401         this.serviceFactory = serviceFactory;
402     }
403 
404     /**
405      * The method determines the key used to store the receiver against.
406      *
407      * @param component the component for which the endpoint is being registered
408      * @param endpoint the endpoint being registered for the component
409      * @return the key to store the newly created receiver against. In this case it
410      *         is the component name, which is equivilent to the Axis service name.
411      */
412     protected Object getReceiverKey(UMOComponent component, UMOEndpoint endpoint)
413     {
414         if (endpoint.getEndpointURI().getPort() == -1)
415         {
416             return component.getDescriptor().getName();
417         }
418         else
419         {
420             return endpoint.getEndpointURI().getAddress() + "/"
421                    + component.getDescriptor().getName();
422         }
423     }
424 
425     public boolean isEnableJSR181Annotations()
426     {
427         return enableJSR181Annotations;
428     }
429 
430     public void setEnableJSR181Annotations(boolean enableJSR181Annotations)
431     {
432         this.enableJSR181Annotations = enableJSR181Annotations;
433     }
434 
435     public List getClientServices()
436     {
437         return clientServices;
438     }
439 
440     public void setClientServices(List clientServices)
441     {
442         this.clientServices = clientServices;
443     }
444 
445     public List getClientInHandlers()
446     {
447         return clientInHandlers;
448     }
449 
450     public void setClientInHandlers(List handlers)
451     {
452         clientInHandlers = handlers;
453     }
454 
455     public List getClientOutHandlers()
456     {
457         return clientOutHandlers;
458     }
459 
460     public void setClientOutHandlers(List handlers)
461     {
462         clientOutHandlers = handlers;
463     }
464 
465     public String getClientTransport()
466     {
467         return clientTransport;
468     }
469 
470     public void setClientTransport(String transportClass)
471     {
472         clientTransport = transportClass;
473     }
474 
475     public String getServiceTransport()
476     {
477         return serviceTransport;
478     }
479 
480     public void setServiceTransport(String transportClass)
481     {
482         serviceTransport = transportClass;
483     }
484 
485     public String getBindingProvider()
486     {
487         return bindingProvider;
488     }
489 
490     public void setBindingProvider(String bindingProvider)
491     {
492         this.bindingProvider = bindingProvider;
493     }
494 
495     public String getTypeMappingRegistry()
496     {
497         return typeMappingRegistry;
498     }
499 
500     public void setTypeMappingRegistry(String typeMappingRegistry)
501     {
502         this.typeMappingRegistry = typeMappingRegistry;
503     }
504 
505     public void onNotification(UMOServerNotification event)
506     {
507         if (event.getAction() == ManagerNotification.MANAGER_STARTED_MODELS)
508         {
509             // We need to register the xfire service component once the model
510             // starts because
511             // when the model starts listeners on components are started, thus
512             // all listener
513             // need to be registered for this connector before the xfire service
514             // component is registered. The implication of this is that to add a
515             // new service and a
516             // different http port the model needs to be restarted before the
517             // listener is available
518             if (!MuleManager.getInstance().lookupModel(ModelHelper.SYSTEM_MODEL).isComponentRegistered(
519                 XFIRE_SERVICE_COMPONENT_NAME + getName()))
520             {
521                 try
522                 {
523                     // Descriptor might be null if no inbound endpoints have
524                     // been register for the xfire connector
525                     if (xfireDescriptor == null)
526                     {
527                         xfireDescriptor = createxfireDescriptor();
528                     }
529                     xfireDescriptor.addInterceptor(new MethodFixInterceptor());
530 
531                     if (xfireDescriptor.getProperties().get("xfire") == null)
532                     {
533                         xfireDescriptor.getProperties().put("xfire", xfire);
534                     }
535                     MuleManager.getInstance().lookupModel(ModelHelper.SYSTEM_MODEL).registerComponent(xfireDescriptor);
536                 }
537                 catch (UMOException e)
538                 {
539                     handleException(e);
540                 }
541             }
542         }
543     }
544 
545     public List getServerInHandlers()
546     {
547         return serverInHandlers;
548     }
549 
550     public void setServerInHandlers(List serverInHandlers)
551     {
552         this.serverInHandlers = serverInHandlers;
553     }
554 
555     public List getServerOutHandlers()
556     {
557         return serverOutHandlers;
558     }
559 
560     public void setServerOutHandlers(List serverOutHandlers)
561     {
562         this.serverOutHandlers = serverOutHandlers;
563     }
564 
565     public Map getExtraProperties()
566     {
567         return extraProperties;
568     }
569 
570     public void setExtraProperties(Map extraProperties)
571     {
572     	if (this.extraProperties != null)
573     	{	
574     		this.extraProperties.putAll(extraProperties);
575     	}
576     	else
577     	{
578     		this.extraProperties = extraProperties;	
579     	}
580     }
581 }