View Javadoc

1   /*
2    * $Id: AxisConnector.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.api.MuleContext;
14  import org.mule.api.MuleException;
15  import org.mule.api.construct.FlowConstruct;
16  import org.mule.api.context.notification.MuleContextNotificationListener;
17  import org.mule.api.endpoint.EndpointBuilder;
18  import org.mule.api.endpoint.EndpointURI;
19  import org.mule.api.endpoint.ImmutableEndpoint;
20  import org.mule.api.endpoint.InboundEndpoint;
21  import org.mule.api.lifecycle.InitialisationException;
22  import org.mule.api.processor.MessageProcessor;
23  import org.mule.api.security.EndpointSecurityFilter;
24  import org.mule.api.service.Service;
25  import org.mule.api.source.CompositeMessageSource;
26  import org.mule.api.transport.MessageReceiver;
27  import org.mule.component.DefaultJavaComponent;
28  import org.mule.config.ExceptionHelper;
29  import org.mule.config.i18n.CoreMessages;
30  import org.mule.context.notification.MuleContextNotification;
31  import org.mule.endpoint.AbstractEndpointBuilder;
32  import org.mule.endpoint.EndpointURIEndpointBuilder;
33  import org.mule.model.seda.SedaService;
34  import org.mule.object.SingletonObjectFactory;
35  import org.mule.processor.SecurityFilterMessageProcessor;
36  import org.mule.routing.MessageFilter;
37  import org.mule.service.ServiceCompositeMessageSource;
38  import org.mule.transport.AbstractConnector;
39  import org.mule.transport.service.TransportFactory;
40  import org.mule.transport.servlet.ServletConnector;
41  import org.mule.transport.soap.axis.extensions.MuleConfigProvider;
42  import org.mule.transport.soap.axis.extensions.MuleTransport;
43  import org.mule.transport.soap.axis.extensions.WSDDFileProvider;
44  import org.mule.transport.soap.axis.extensions.WSDDJavaMuleProvider;
45  import org.mule.transport.soap.axis.i18n.AxisMessages;
46  import org.mule.util.ClassUtils;
47  import org.mule.util.CollectionUtils;
48  import org.mule.util.MuleUrlStreamHandlerFactory;
49  
50  import java.util.ArrayList;
51  import java.util.HashMap;
52  import java.util.Iterator;
53  import java.util.List;
54  import java.util.Map;
55  
56  import javax.xml.namespace.QName;
57  
58  import org.apache.axis.client.Call;
59  import org.apache.axis.configuration.SimpleProvider;
60  import org.apache.axis.deployment.wsdd.WSDDConstants;
61  import org.apache.axis.deployment.wsdd.WSDDProvider;
62  import org.apache.axis.encoding.TypeMappingRegistryImpl;
63  import org.apache.axis.encoding.ser.BeanDeserializerFactory;
64  import org.apache.axis.encoding.ser.BeanSerializerFactory;
65  import org.apache.axis.handlers.soap.SOAPService;
66  import org.apache.axis.server.AxisServer;
67  import org.apache.axis.wsdl.fromJava.Namespaces;
68  import org.apache.axis.wsdl.fromJava.Types;
69  
70  /**
71   * <code>AxisConnector</code> is used to maintain one or more Services for Axis
72   * server instance.
73   * <p/>
74   * Some of the Axis specific service initialisation code was adapted from the Ivory
75   * project (http://ivory.codehaus.org). Thanks guys :)
76   */
77  public class AxisConnector extends AbstractConnector implements MuleContextNotificationListener<MuleContextNotification>
78  {
79      /* Register the AxisFault Exception reader if this class gets loaded */
80      static
81      {
82          ExceptionHelper.registerExceptionReader(new AxisFaultExceptionReader());
83      }
84  
85      public static final QName QNAME_MULE_PROVIDER = new QName(WSDDConstants.URI_WSDD_JAVA, "Mule");
86      public static final QName QNAME_MULE_TYPE_MAPPINGS = new QName("http://www.muleumo.org/ws/mappings",
87              "Mule");
88      public static final String DEFAULT_MULE_NAMESPACE_URI = "http://www.muleumo.org";
89  
90      public static final String DEFAULT_MULE_AXIS_SERVER_CONFIG = "mule-axis-server-config.wsdd";
91      public static final String DEFAULT_MULE_AXIS_CLIENT_CONFIG = "mule-axis-client-config.wsdd";
92      public static final String AXIS_SERVICE_COMPONENT_NAME = "_axisServiceComponent";
93      public static final String AXIS_SERVICE_PROPERTY = "_axisService";
94      public static final String AXIS_CLIENT_CONFIG_PROPERTY = "clientConfig";
95  
96      public static final String SERVICE_PROPERTY_COMPONENT_NAME = "componentName";
97      public static final String SERVICE_PROPERTY_SERVCE_PATH = "servicePath";
98  
99      public static final String AXIS = "axis";
100 
101     // used by dispatcher and receiver
102     public static final String SOAP_METHODS = "soapMethods";
103     public static final String STYLE = "style";
104     public static final String USE = "use";
105 
106     private String serverConfig = DEFAULT_MULE_AXIS_SERVER_CONFIG;
107 
108     private AxisServer axis = null;
109     private SimpleProvider serverProvider = null;
110     private String clientConfig = DEFAULT_MULE_AXIS_CLIENT_CONFIG;
111     private SimpleProvider clientProvider = null;
112 
113     private List beanTypes;
114     private Service axisComponent;
115 
116     //this will store the name of the descriptor of the current connector's AxisServiceComponent
117     //private String specificAxisServiceComponentName;
118 
119     /**
120      * These protocols will be set on client invocations. By default Mule uses it's
121      * own transports rather that Axis's. This is only because it gives us more
122      * flexibility inside Mule and simplifies the code
123      */
124     private Map axisTransportProtocols = null;
125 
126     /**
127      * A store of registered servlet services that need to have their endpoints
128      * re-written with the 'real' http url instead of the servlet:// one. This is
129      * only required to ensure wsdl is generated correctly. I would like a clearer
130      * way of doing this so I can remove this workaround
131      */
132     private List servletServices = new ArrayList();
133 
134     private List supportedSchemes = null;
135 
136     private boolean doAutoTypes = true;
137 
138     private boolean treatMapAsNamedParams = true;
139 
140     public AxisConnector(MuleContext context)
141     {
142         super(context);
143         this.registerProtocols();
144     }
145 
146     protected void registerProtocols()
147     {
148         if (supportedSchemes == null)
149         {
150             // Default supported schemes, these can be restricted
151             // through configuration
152             supportedSchemes = new ArrayList();
153             supportedSchemes.add("http");
154             supportedSchemes.add("https");
155             supportedSchemes.add("servlet");
156             supportedSchemes.add("vm");
157             supportedSchemes.add("jms");
158             supportedSchemes.add("xmpp");
159             supportedSchemes.add("ssl");
160             supportedSchemes.add("tcp");
161             supportedSchemes.add("smtp");
162             supportedSchemes.add("smtps");
163             supportedSchemes.add("pop3");
164             supportedSchemes.add("pop3s");
165             supportedSchemes.add("imap");
166             supportedSchemes.add("imaps");
167         }
168 
169         for (Iterator iterator = supportedSchemes.iterator(); iterator.hasNext();)
170         {
171             String s = (String) iterator.next();
172             registerSupportedProtocol(s);
173         }
174     }
175 
176     @Override
177     protected void doInitialise() throws InitialisationException
178     {
179         axisTransportProtocols = new HashMap();
180         //specificAxisServiceComponentName = AXIS_SERVICE_COMPONENT_NAME + "_" + name;
181 
182         axisTransportProtocols = new HashMap();
183         try
184         {
185             for (Iterator iterator = supportedSchemes.iterator(); iterator.hasNext();)
186             {
187                 String s = (String) iterator.next();
188                 axisTransportProtocols.put(s, MuleTransport.getTransportClass(s));
189                 registerSupportedProtocol(s);
190             }
191             muleContext.registerListener(this);
192         }
193         catch (Exception e)
194         {
195             throw new InitialisationException(e, this);
196         }
197         // TODO DO: call registerSupportedProtocol if axisTransportProtocols are set from external?
198 
199         if (clientProvider == null)
200         {
201             clientProvider = createAxisProvider(clientConfig);
202         }
203         else
204         {
205             if (!DEFAULT_MULE_AXIS_CLIENT_CONFIG.equals(clientConfig))
206             {
207                 logger.warn(AxisMessages.clientProviderAndClientConfigConfigured());
208             }
209         }
210 
211         if (axis == null)
212         {
213             if (serverProvider == null)
214             {
215                 serverProvider = this.createAxisProvider(serverConfig);
216             }
217             else
218             {
219                 if (!DEFAULT_MULE_AXIS_SERVER_CONFIG.equals(serverConfig))
220                 {
221                     logger.warn(AxisMessages.serverProviderAndServerConfigConfigured());
222                 }
223             }
224 
225             // Create the AxisServer
226             axis = new AxisServer(serverProvider);
227             // principle of least surprise: doAutoTypes only has effect on our self-configured AxisServer
228             axis.setOption("axis.doAutoTypes", Boolean.valueOf(doAutoTypes));
229         }
230 
231         // Register the Mule service serverProvider
232         WSDDProvider.registerProvider(QNAME_MULE_PROVIDER, new WSDDJavaMuleProvider(this));
233 
234         try
235         {
236             registerTransportTypes();
237         }
238         catch (ClassNotFoundException e)
239         {
240             throw new InitialisationException(
241                     CoreMessages.cannotLoadFromClasspath(e.getMessage()), e, this);
242         }
243 
244         // Register all our UrlStreamHandlers here so they can be resolved. This is necessary
245         // to make Mule work in situations where modification of system properties at runtime
246         // is not reliable, e.g. when running in maven's surefire test executor.
247         MuleUrlStreamHandlerFactory.registerHandler("jms", new org.mule.transport.soap.axis.transport.jms.Handler());
248         MuleUrlStreamHandlerFactory.registerHandler("pop3", new org.mule.transport.soap.axis.transport.pop3.Handler());
249         MuleUrlStreamHandlerFactory.registerHandler("smtp", new org.mule.transport.soap.axis.transport.smtp.Handler());
250         MuleUrlStreamHandlerFactory.registerHandler("vm", new org.mule.transport.soap.axis.transport.vm.Handler());
251 
252         try
253         {
254             registerTypes((TypeMappingRegistryImpl) axis.getTypeMappingRegistry(), beanTypes);
255         }
256         catch (ClassNotFoundException e)
257         {
258             throw new InitialisationException(e, this);
259         }
260     }
261 
262     protected void registerTransportTypes() throws ClassNotFoundException
263     {
264         // Register Transport handlers
265         // By default these will all be handled by Mule, however some companies may
266         // have their own they wish to use
267         for (Iterator iterator = getAxisTransportProtocols().keySet().iterator(); iterator.hasNext();)
268         {
269             String protocol = (String) iterator.next();
270             Object temp = getAxisTransportProtocols().get(protocol);
271             Class clazz;
272             if (temp instanceof String)
273             {
274                 clazz = ClassUtils.loadClass(temp.toString(), getClass());
275             }
276             else
277             {
278                 clazz = (Class) temp;
279             }
280             Call.setTransportForProtocol(protocol, clazz);
281         }
282     }
283 
284     protected SimpleProvider createAxisProvider(String config) throws InitialisationException
285     {
286         // Use our custom file provider that does not require services to be declared
287         // in the WSDD. This only affects the
288         // client side as the client will fallback to the FileProvider when invoking
289         // a service.
290         WSDDFileProvider fileProvider = new WSDDFileProvider(config);
291         fileProvider.setSearchClasspath(true);
292         /*
293          * Wrap the FileProvider with a SimpleProvider so we can programmatically
294          * configure the Axis server (you can only use wsdd descriptors with the
295          * FileProvider)
296          */
297         return new MuleConfigProvider(fileProvider);
298     }
299 
300     public String getProtocol()
301     {
302         return AXIS;
303     }
304 
305     /**
306      * The method determines the key used to store the receiver against.
307      *
308      * @param flowConstruct the component for which the endpoint is being registered
309      * @param endpoint  the endpoint being registered for the component
310      * @return the key to store the newly created receiver against. In this case it
311      *         is the component name, which is equivalent to the Axis service name.
312      */
313     @Override
314     protected Object getReceiverKey(FlowConstruct flowConstruct, InboundEndpoint endpoint)
315     {
316         if (endpoint.getEndpointURI().getPort() == -1)
317         {
318             return flowConstruct.getName();
319         }
320         else
321         {
322             return endpoint.getEndpointURI().getAddress() + "/" + flowConstruct.getName();
323         }
324     }
325 
326     protected void unregisterReceiverWithMuleService(MessageReceiver receiver, EndpointURI ep)
327             throws MuleException
328     {
329         String endpointKey = getCounterEndpointKey(receiver.getEndpointURI());
330 
331         for (Iterator iterator = ((ServiceCompositeMessageSource) axisComponent.getMessageSource()).getEndpoints().iterator(); iterator.hasNext();)
332         {
333             ImmutableEndpoint endpoint = (ImmutableEndpoint) iterator.next();
334             if (endpointKey.startsWith(endpoint.getEndpointURI().getAddress()))
335             {
336                 logger.info("Unregistering Axis endpoint: " + endpointKey + " for service: "
337                         + ((AxisMessageReceiver) receiver).getSoapService().getName());
338             }
339             try
340             {
341                 endpoint.getConnector()
342                         .unregisterListener(receiver.getEndpoint(), axisComponent);
343             }
344             catch (Exception e)
345             {
346                 logger.error("Failed to unregister Axis endpoint: " + endpointKey + " for service: "
347                         + receiver.getFlowConstruct().getName() + ". Error is: "
348                         + e.getMessage(), e);
349             }
350         }
351     }
352 
353     protected void registerReceiverWithMuleService(MessageReceiver receiver, EndpointURI ep)
354             throws MuleException
355     {
356         // If this is the first receiver we need to create the Axis service
357         // component this will be registered with Mule when the Connector starts
358         // See if the axis descriptor has already been added. This allows
359         // developers to override the default configuration, say to increase
360         // the threadpool
361         if (axisComponent == null)
362         {
363             axisComponent = getOrCreateAxisComponent();
364         }
365         else
366         {
367             // Lets unregister the 'template' instance, configure it and
368             // then register again later
369             muleContext.getRegistry().unregisterService(AXIS_SERVICE_PROPERTY + getName());
370         }
371 
372         String serviceName = ((AxisMessageReceiver) receiver).getSoapService().getName();
373         // No determine if the endpointUri requires a new connector to be
374         // registed in the case of http we only need to register the new endpointUri
375         // if the port is different If we're using VM or Jms we just use the resource
376         // info directly without appending a service name
377         String endpoint;
378         String scheme = ep.getScheme().toLowerCase();
379         if (scheme.equals("jms") || scheme.equals("vm") || scheme.equals("servlet"))
380         {
381             endpoint = ep.toString();
382         }
383         else
384         {
385             endpoint = receiver.getEndpointURI().getAddress() + "/" + serviceName;
386         }
387         if (logger.isDebugEnabled())
388         {
389             logger.debug("Modified endpoint with " + scheme + " scheme to " + endpoint);
390         }
391 
392         EndpointBuilder serviceEndpointbuilder = new EndpointURIEndpointBuilder(endpoint, muleContext);
393         serviceEndpointbuilder.setExchangePattern(receiver.getEndpoint().getExchangePattern());
394         serviceEndpointbuilder.setName(ep.getScheme() + ":" + serviceName);
395         // Set the transformers on the endpoint too
396         serviceEndpointbuilder.setTransformers(receiver.getEndpoint().getTransformers().isEmpty() ? null
397                                                                                                   : receiver.getEndpoint().getTransformers());
398         serviceEndpointbuilder.setResponseTransformers(receiver.getEndpoint().getResponseTransformers().isEmpty() ? null
399                                                                                                                  : receiver.getEndpoint().getResponseTransformers());
400         // set the filter on the axis endpoint on the real receiver endpoint
401         serviceEndpointbuilder.addMessageProcessor(new MessageFilter(receiver.getEndpoint().getFilter()));
402         // set the Security filter on the axis endpoint on the real receiver
403         // endpoint
404         EndpointSecurityFilter securityFilter = receiver.getEndpoint().getSecurityFilter();
405         if (securityFilter != null)
406         {
407             serviceEndpointbuilder.addMessageProcessor(new SecurityFilterMessageProcessor(securityFilter));
408         }
409 
410         // TODO Do we really need to modify the existing receiver endpoint? What happens if we don't security,
411         // filters and transformers will get invoked twice?
412         AbstractEndpointBuilder receiverEndpointBuilder = new EndpointURIEndpointBuilder(receiver.getEndpoint());
413         // Remove the Axis filter now
414 
415         List<MessageProcessor> procs = new ArrayList(receiverEndpointBuilder.getMessageProcessors());
416         CollectionUtils.removeType(procs, MessageFilter.class);
417         CollectionUtils.removeType(procs, SecurityFilterMessageProcessor.class);
418         receiverEndpointBuilder.setMessageProcessors(procs);
419 
420         InboundEndpoint serviceEndpoint = muleContext.getRegistry()
421             .lookupEndpointFactory()
422             .getInboundEndpoint(serviceEndpointbuilder);
423 
424         InboundEndpoint receiverEndpoint = muleContext.getRegistry()
425             .lookupEndpointFactory()
426             .getInboundEndpoint(receiverEndpointBuilder);
427 
428         receiver.setEndpoint(receiverEndpoint);
429 
430         
431         ((CompositeMessageSource) axisComponent.getMessageSource()).addSource(serviceEndpoint);
432     }
433 
434     private String getCounterEndpointKey(EndpointURI endpointURI)
435     {
436         StringBuffer endpointKey = new StringBuffer(64);
437 
438         endpointKey.append(endpointURI.getScheme());
439         endpointKey.append("://");
440         endpointKey.append(endpointURI.getHost());
441         if (endpointURI.getPort() > -1)
442         {
443             endpointKey.append(":");
444             endpointKey.append(endpointURI.getPort());
445         }
446         return endpointKey.toString();
447     }
448 
449     // This initialization could be performed in the initialize() method.  Putting it here essentially makes
450     // it a lazy-create/lazy-init
451     // Another option would be to put it in the default-axis-config.xml (MULE-2102) with lazy-init="true" 
452     // but that makes us depend on Spring.
453     // Another consideration is how/when this implicit component gets disposed.
454     protected Service getOrCreateAxisComponent() throws MuleException
455     {
456         Service service = muleContext.getRegistry().lookupService(AXIS_SERVICE_PROPERTY + getName());
457 
458         if (service == null)
459         {
460             // TODO MULE-2228 Simplify this API
461             service = new SedaService(muleContext);
462             service.setName(AXIS_SERVICE_PROPERTY + getName());
463             service.setModel(muleContext.getRegistry().lookupSystemModel());
464 
465             Map props = new HashMap();
466             props.put(AXIS, axis);
467             SingletonObjectFactory of = new SingletonObjectFactory(AxisServiceComponent.class, props);
468             final DefaultJavaComponent component = new DefaultJavaComponent(of);
469             component.setMuleContext(muleContext);
470             service.setComponent(component);
471         }
472         return service;
473     }
474 
475     /**
476      * Template method to perform any work when starting the connectoe
477      *
478      * @throws org.mule.api.MuleException if the method fails
479      */
480     @Override
481     protected void doStart() throws MuleException
482     {
483         axis.start();
484     }
485 
486     /**
487      * Template method to perform any work when stopping the connectoe
488      *
489      * @throws org.mule.api.MuleException if the method fails
490      */
491     @Override
492     protected void doStop() throws MuleException
493     {
494         axis.stop();
495         // Model model = muleContext.getRegistry().lookupModel();
496         // model.unregisterComponent(model.getDescriptor(AXIS_SERVICE_COMPONENT_NAME));
497     }
498 
499     @Override
500     protected void doConnect() throws Exception
501     {
502         // template method
503     }
504 
505     @Override
506     protected void doDisconnect() throws Exception
507     {
508         // template method
509     }
510 
511     @Override
512     protected void doDispose()
513     {
514         // template method
515     }
516 
517     public String getServerConfig()
518     {
519         return serverConfig;
520     }
521 
522     public void setServerConfig(String serverConfig)
523     {
524         this.serverConfig = serverConfig;
525     }
526 
527     public List getBeanTypes()
528     {
529         return beanTypes;
530     }
531 
532     public void setBeanTypes(List beanTypes)
533     {
534         this.beanTypes = beanTypes;
535     }
536 
537     public String getClientConfig()
538     {
539         return clientConfig;
540     }
541 
542     public void setClientConfig(String clientConfig)
543     {
544         this.clientConfig = clientConfig;
545     }
546 
547     public AxisServer getAxis()
548     {
549         return axis;
550     }
551 
552     public void setAxis(AxisServer axisServer)
553     {
554         this.axis = axisServer;
555     }
556 
557     public SimpleProvider getServerProvider()
558     {
559         return serverProvider;
560     }
561 
562     public void setServerProvider(SimpleProvider serverProvider)
563     {
564         this.serverProvider = serverProvider;
565     }
566 
567     public SimpleProvider getClientProvider()
568     {
569         return clientProvider;
570     }
571 
572     public void setClientProvider(SimpleProvider clientProvider)
573     {
574         this.clientProvider = clientProvider;
575     }
576 
577     public Map getAxisTransportProtocols()
578     {
579         return axisTransportProtocols;
580     }
581 
582     public void setAxisTransportProtocols(Map axisTransportProtocols)
583     {
584         this.axisTransportProtocols.putAll(axisTransportProtocols);
585     }
586 
587     void addServletService(SOAPService service)
588     {
589         servletServices.add(service);
590     }
591 
592     public List getSupportedSchemes()
593     {
594         return supportedSchemes;
595     }
596 
597     public void setSupportedSchemes(List supportedSchemes)
598     {
599         this.supportedSchemes = supportedSchemes;
600     }
601 
602     public boolean isDoAutoTypes()
603     {
604         return doAutoTypes;
605     }
606 
607     public void setDoAutoTypes(boolean doAutoTypes)
608     {
609         this.doAutoTypes = doAutoTypes;
610     }
611 
612     void registerTypes(TypeMappingRegistryImpl registry, List types) throws ClassNotFoundException
613     {
614         if (types != null)
615         {
616             Class clazz;
617             for (Iterator iterator = types.iterator(); iterator.hasNext();)
618             {
619                 clazz = ClassUtils.loadClass(iterator.next().toString(), getClass());
620                 String localName = Types.getLocalNameFromFullName(clazz.getName());
621                 QName xmlType = new QName(Namespaces.makeNamespace(clazz.getName()), localName);
622 
623                 registry.getDefaultTypeMapping().register(clazz, xmlType,
624                         new BeanSerializerFactory(clazz, xmlType), new BeanDeserializerFactory(clazz, xmlType));
625             }
626         }
627     }
628 
629     public boolean isTreatMapAsNamedParams()
630     {
631         return treatMapAsNamedParams;
632     }
633 
634     public void setTreatMapAsNamedParams(boolean treatMapAsNamedParams)
635     {
636         this.treatMapAsNamedParams = treatMapAsNamedParams;
637     }
638 
639     public void onNotification(MuleContextNotification notification)
640     {
641         try
642         {
643             if (notification.getAction() == MuleContextNotification.CONTEXT_STARTED)
644             {
645                 // We need to register the Axis service component once the muleContext
646                 // starts because when the model starts listeners on components are started, thus
647                 // all listener need to be registered for this connector before the Axis service
648                 // component is registered.
649                 // The implication of this is that to add a new service and a
650                 // different http port the model needs to be restarted before the listener is available
651                 if (muleContext.getRegistry().lookupService(AXIS_SERVICE_PROPERTY + getName()) == null)
652                 {
653                     // Descriptor might be null if no inbound endpoints have been
654                     // register for the Axis connector
655                     if (axisComponent == null)
656                     {
657                         axisComponent = getOrCreateAxisComponent();
658                     }
659                     muleContext.getRegistry().registerService(axisComponent);
660     
661                     // We have to perform a small hack here to rewrite servlet://
662                     // endpoints with the
663                     // real http:// address
664                     for (Iterator iterator = servletServices.iterator(); iterator.hasNext();)
665                     {
666                         SOAPService service = (SOAPService) iterator.next();
667                         ServletConnector servletConnector = (ServletConnector) new TransportFactory(muleContext).getConnectorByProtocol("servlet");
668                         String url = servletConnector.getServletUrl();
669                         if (url != null)
670                         {
671                             service.getServiceDescription().setEndpointURL(url + "/" + service.getName());
672                         }
673                         else
674                         {
675                             logger.error("The servletUrl property on the ServletConntector has not been set this means that wsdl generation for service '"
676                                     + service.getName() + "' may be incorrect");
677                         }
678                     }
679                     servletServices.clear();
680                 }
681             }
682         }
683         catch (MuleException e)
684         {
685             handleException(e);
686         }
687     }
688 }