View Javadoc

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