KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > webservice > ServiceDeployer


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7
8 // $Id: ServiceDeployer.java,v 1.18.2.17 2005/06/19 10:07:15 bill Exp $
9
package org.jboss.webservice;
10
11 import java.io.InputStream JavaDoc;
12 import java.net.URL JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.Map JavaDoc;
17 import javax.management.InstanceNotFoundException JavaDoc;
18 import javax.management.Notification JavaDoc;
19 import javax.management.NotificationFilterSupport JavaDoc;
20 import javax.management.NotificationListener JavaDoc;
21 import javax.management.ObjectName JavaDoc;
22 import org.dom4j.Document;
23 import org.dom4j.Element;
24 import org.jboss.deployment.DeploymentException;
25 import org.jboss.deployment.DeploymentInfo;
26 import org.jboss.deployment.MainDeployerMBean;
27 import org.jboss.deployment.SubDeployer;
28 import org.jboss.logging.Logger;
29 import org.jboss.metadata.ApplicationMetaData;
30 import org.jboss.metadata.BeanMetaData;
31 import org.jboss.metadata.EjbPortComponentMetaData;
32 import org.jboss.metadata.WebMetaData;
33 import org.jboss.mx.util.MBeanProxy;
34 import org.jboss.mx.util.MBeanProxyCreationException;
35 import org.jboss.system.ServiceMBeanSupport;
36 import org.jboss.webservice.metadata.PortComponentMetaData;
37 import org.jboss.webservice.metadata.WebserviceDescriptionMetaData;
38 import org.jboss.webservice.metadata.WebservicesFactory;
39 import org.jboss.webservice.metadata.WebservicesMetaData;
40 import org.jboss.xb.binding.ObjectModelFactory;
41 import org.jboss.xb.binding.Unmarshaller;
42 import org.jboss.xb.binding.UnmarshallerFactory;
43
44 /**
45  * A deployer service that manages WS4EE compliant Web-Services within JMX
46  * by translating/delegating to an axis deployer.
47  * <p/>
48  * This service receives deployment notifications from the EJBDeployer and
49  * AbstractWebContainer and deploys the webservices using the {@link AxisService}
50  *
51  * @author Thomas.Diesler@jboss.org
52  * @author Scott.Stark@jboss.org
53  * @version $Revision: 1.18.2.17 $
54  * @jmx.mbean description="Abstract Webservice deployer"
55  * extends="org.jboss.system.ServiceMBean"
56  * @since 15-April-2004
57  */

58 public abstract class ServiceDeployer extends ServiceMBeanSupport
59         implements ServiceDeployerMBean, NotificationListener JavaDoc
60 {
61    // provide logging
62
private final Logger log = Logger.getLogger(ServiceDeployer.class);
63
64    // The servlet init param in web.xml that is the service ID
65
public static final String JavaDoc INIT_PARAM_WEBSERVICE_ID = "WebServiceID";
66    // The servlet init param in web.xml that is the service endpoint class
67
public static final String JavaDoc INIT_PARAM_SERVICE_ENDPOINT_IMPL = "ServiceEndpointImpl";
68
69    // Proxy to AxisService
70
private AxisServiceMBean axisService;
71
72    /**
73     * Maps the deployment url the the WebservicesMetaData
74     */

75    protected Map JavaDoc webservicesMap = new HashMap JavaDoc();
76
77    /** Get a proxy to AxisService
78     */

79    protected void startService() throws Exception JavaDoc
80    {
81       super.startService();
82       axisService = (AxisServiceMBean)MBeanProxy.get(AxisServiceMBean.class, AxisServiceMBean.OBJECT_NAME, server);
83    }
84
85    /**
86     * Callback method from the broadcaster MBean this listener implementation
87     * is registered to.
88     *
89     * @param notification the notification object
90     * @param handback the handback object given to the broadcaster
91     * upon listener registration
92     */

93    public void handleNotification(Notification JavaDoc notification, Object JavaDoc handback)
94    {
95       DeploymentInfo di = (DeploymentInfo)notification.getUserData();
96
97       String JavaDoc moduleName = di.shortName;
98       String JavaDoc type = notification.getType();
99       log.debug("handleNotification: " + type + "," + moduleName);
100
101       if (isWebservicesDeployment(di))
102       {
103          try
104          {
105             if (type.equals(SubDeployer.INIT_NOTIFICATION))
106                initWebservice(di);
107             else if (type.equals(SubDeployer.CREATE_NOTIFICATION))
108                createWebservice(di);
109             else if (type.equals(SubDeployer.START_NOTIFICATION))
110                startWebservice(di);
111          }
112          catch (Throwable JavaDoc e)
113          {
114             handleStartupException(di, e);
115          }
116
117          try
118          {
119             if (type.equals(SubDeployer.STOP_NOTIFICATION))
120                stopWebservice(di);
121             else if (type.equals(SubDeployer.DESTROY_NOTIFICATION))
122                destroyWebservice(di);
123          }
124          catch (Throwable JavaDoc e)
125          {
126             handleShutdownException(moduleName, e);
127          }
128       }
129    }
130
131    /**
132     * Overwrite to initialize the webservice
133     * Is called when the parent deployer sends the INIT_NOTIFICATION.
134     * <p/>
135     * This implementation does nothing
136     */

137    protected void initWebservice(DeploymentInfo di) throws DeploymentException
138    {
139       if (di.metaData instanceof ApplicationMetaData)
140       {
141          ApplicationMetaData applMetaData = (ApplicationMetaData)di.metaData;
142          applMetaData.setWebServiceDeployment(true);
143       }
144
145       if (di.metaData instanceof WebMetaData)
146       {
147          WebMetaData webMetaData = (WebMetaData)di.metaData;
148          webMetaData.setWebServiceDeployment(true);
149       }
150    }
151
152    /**
153     * Overwrite to create the webservice
154     * Is called when the parent deployer sends the CREATE_NOTIFICATION.
155     * <p/>
156     * This implementation parses webservices.xml and puts it in the local registry.
157     */

158    protected void createWebservice(DeploymentInfo di) throws DeploymentException
159    {
160       URL JavaDoc url = getWebservicesDescriptor(di);
161       if (url != null)
162       {
163          WebservicesMetaData wsMetaData = parseWebservicesXML(di, url);
164          webservicesMap.put(di.url, wsMetaData);
165       }
166    }
167
168    /** Get the resource name of the webservices.xml descriptor. */
169    protected abstract URL JavaDoc getWebservicesDescriptor(DeploymentInfo di);
170
171    /** Return true if this is a web service deployment */
172    private boolean isWebservicesDeployment(DeploymentInfo di)
173    {
174       boolean isWebservicesDeployment = false;
175       if (di.metaData instanceof ApplicationMetaData)
176       {
177          ApplicationMetaData applMetaData = (ApplicationMetaData)di.metaData;
178          isWebservicesDeployment = applMetaData.isWebServiceDeployment() || getWebservicesDescriptor(di) != null;
179       }
180
181       if (di.metaData instanceof WebMetaData)
182       {
183          WebMetaData webMetaData = (WebMetaData)di.metaData;
184          isWebservicesDeployment = webMetaData.isWebServiceDeployment() || getWebservicesDescriptor(di) != null;
185       }
186
187       return isWebservicesDeployment;
188    }
189
190    /**
191     * Overwrite to start the webservice
192     * Is called when the parent deployer sends the START_NOTIFICATION.
193     * <p/>
194     * This implementation deployes the webservices to Axis.
195     */

196    protected void startWebservice(DeploymentInfo di) throws DeploymentException
197    {
198       WebservicesMetaData webservices = (WebservicesMetaData)webservicesMap.get(di.url);
199       if (webservices != null)
200       {
201          // update the service address
202
ServiceLocationResolver locationResolver = new ServiceLocationResolver(di);
203          WebserviceDescriptionMetaData[] wsdArray = webservices.getWebserviceDescriptions();
204          for (int i = 0; i < wsdArray.length; i++)
205          {
206             WebserviceDescriptionMetaData wsdMetaData = wsdArray[i];
207             wsdMetaData.updateServiceAddress(locationResolver);
208             String JavaDoc wsdName = wsdMetaData.getWebserviceDescriptionName();
209
210             // copy the wsdl publish location from jboss.xml
211
if (di.metaData instanceof ApplicationMetaData)
212             {
213                ApplicationMetaData applMetaData = (ApplicationMetaData)di.metaData;
214                String JavaDoc wsdlPublishLocation = applMetaData.getWsdlPublishLocationByName(wsdName);
215                wsdMetaData.setWsdlPublishLocation(wsdlPublishLocation);
216             }
217
218             // copy the wsdl publish location from jboss-web.xml
219
if (di.metaData instanceof WebMetaData)
220             {
221                WebMetaData webMetaData = (WebMetaData)di.metaData;
222                String JavaDoc wsdlPublishLocation = webMetaData.getWsdlPublishLocationByName(wsdName);
223                wsdMetaData.setWsdlPublishLocation(wsdlPublishLocation);
224             }
225          }
226
227          WSDLFilePublisher wsdlfp = new WSDLFilePublisher(di);
228          wsdlfp.publishWsdlFile(webservices);
229          deployWebservices(di, webservices);
230       }
231    }
232
233    /**
234     * Overwrite to stop the webservice
235     * Is called when the parent deployer sends the STOP_NOTIFICATION.
236     * <p/>
237     * This implementation undeployes the webservices to Axis and
238     * removes the webservices.xml from the local registry.
239     */

240    protected void stopWebservice(DeploymentInfo di)
241    {
242       WebservicesMetaData webservices = (WebservicesMetaData)webservicesMap.get(di.url);
243       if (webservices != null)
244       {
245          undeployWebservices(di, webservices);
246          WSDLFilePublisher wsdlfp = new WSDLFilePublisher(di);
247          wsdlfp.unpublishWsdlFile();
248       }
249    }
250
251    /**
252     * Overwrite to destroy the webservice
253     * This method is called when the parent deployer sends the DESTROY_NOTIFICATION.
254     */

255    protected void destroyWebservice(DeploymentInfo di)
256    {
257       webservicesMap.remove(di.url);
258    }
259
260    // PROTECTED *******************************************************************************************************
261

262    /**
263     * Handle all webservice deployment exceptions.
264     * <p/>
265     * You can either simply logs the problem and keep the EJB/WAR module
266     * alive or undeploy properly.
267     */

268    protected void handleStartupException(DeploymentInfo di, Throwable JavaDoc th)
269    {
270       log.error("Cannot startup webservice for: " + di.shortName, th);
271       try
272       {
273          MainDeployerMBean mainDeployer = (MainDeployerMBean)MBeanProxy.get(MainDeployerMBean.class, MainDeployerMBean.OBJECT_NAME, server);
274          mainDeployer.undeploy(di);
275       }
276       catch (MBeanProxyCreationException e)
277       {
278          e.printStackTrace();
279       }
280    }
281
282    /**
283     * Handle all webservice deployment exceptions.
284     * <p/>
285     * You can either simply logs the problem and keep the EJB/WAR module
286     * alive or undeploy properly.
287     */

288    protected void handleShutdownException(String JavaDoc moduleName, Throwable JavaDoc th)
289    {
290       log.error("Cannot shutdown webservice for: " + moduleName, th);
291    }
292
293    /**
294     * Register the notification listener
295     */

296    protected void registerNotificationListener(ObjectName JavaDoc serviceName)
297            throws InstanceNotFoundException JavaDoc
298    {
299       NotificationFilterSupport JavaDoc filter = new NotificationFilterSupport JavaDoc();
300       filter.enableType(SubDeployer.INIT_NOTIFICATION);
301       filter.enableType(SubDeployer.CREATE_NOTIFICATION);
302       filter.enableType(SubDeployer.START_NOTIFICATION);
303       filter.enableType(SubDeployer.STOP_NOTIFICATION);
304       filter.enableType(SubDeployer.DESTROY_NOTIFICATION);
305       server.addNotificationListener(serviceName, this, filter, null);
306    }
307
308    /**
309     * Unregister the notification listener
310     */

311    protected void unregisterNotificationListener(ObjectName JavaDoc serviceName)
312    {
313       try
314       {
315          server.removeNotificationListener(serviceName, this);
316       }
317       catch (Exception JavaDoc e)
318       {
319          log.error("Cannot remove notification listener: " + e.toString());
320       }
321    }
322
323    /**
324     * Unmarshal the webservices.xml
325     */

326    protected WebservicesMetaData parseWebservicesXML(DeploymentInfo di, URL JavaDoc webservicesURL) throws DeploymentException
327    {
328       WebservicesMetaData webservices = null;
329       try
330       {
331          // let the object model factory to create an instance and populate it with data from XML
332
InputStream JavaDoc is = webservicesURL.openStream();
333          try
334          {
335             // setup the XML binding Unmarshaller
336
Unmarshaller unmarshaller = UnmarshallerFactory.newInstance()
337                   .newUnmarshaller();
338             ObjectModelFactory factory = new WebservicesFactory(di.localCl);
339             webservices = (WebservicesMetaData)unmarshaller.unmarshal(is, factory, null);
340          }
341          finally
342          {
343             is.close();
344          }
345       }
346       catch (Exception JavaDoc e)
347       {
348          throw new DeploymentException("Cannot obtain webservices meta data", e);
349       }
350       return webservices;
351    }
352
353    /**
354     * Deploy the webservices using the AxisService MBean
355     */

356    protected void deployWebservices(DeploymentInfo di, WebservicesMetaData webservices)
357            throws DeploymentException
358    {
359       try
360       {
361          WebserviceDescriptionMetaData[] wsdArr = webservices.getWebserviceDescriptions();
362          for (int i = 0; i < wsdArr.length; i++)
363          {
364             WebserviceDescriptionMetaData wsd = wsdArr[i];
365             PortComponentMetaData[] pcArr = wsd.getPortComponents();
366             for (int j = 0; j < pcArr.length; j++)
367             {
368                PortComponentMetaData pcMetaData = pcArr[j];
369                PortComponentInfo pcInfo = new PortComponentInfo(di, pcMetaData);
370                axisService.deployService(pcInfo);
371             }
372          }
373       }
374       catch (Exception JavaDoc e)
375       {
376          throw new DeploymentException("Cannot deploy webservice", e);
377       }
378    }
379
380    /**
381     * Undeploy the webservices using the AxisService MBean
382     */

383    protected void undeployWebservices(DeploymentInfo di, WebservicesMetaData webservices)
384    {
385       try
386       {
387          WebserviceDescriptionMetaData[] wsdarr = webservices.getWebserviceDescriptions();
388          for (int i = 0; i < wsdarr.length; i++)
389          {
390             WebserviceDescriptionMetaData wsDescription = wsdarr[i];
391             PortComponentMetaData[] pcarr = wsDescription.getPortComponents();
392             for (int j = 0; j < pcarr.length; j++)
393             {
394                PortComponentMetaData pcMetaData = pcarr[j];
395                PortComponentInfo pcInfo = new PortComponentInfo(di, pcMetaData);
396                String JavaDoc wsID = pcInfo.getServiceID();
397                axisService.undeployService(wsID);
398             }
399          }
400       }
401       catch (Exception JavaDoc ignore)
402       {
403          log.warn("Cannot undeploy webservice: " + ignore);
404       }
405    }
406
407    /** Modify the servlet-class element
408     */

409    protected boolean modifyServletConfig(Document doc, String JavaDoc servletName, PortComponentInfo pcInfo) throws DeploymentException
410    {
411       Element servletElement = null;
412
413       Iterator JavaDoc itServlet = doc.getRootElement().elements("servlet").iterator();
414       while (itServlet.hasNext() && servletElement == null)
415       {
416          Element el = (Element)itServlet.next();
417          String JavaDoc elName = el.elementTextTrim("servlet-name");
418          if (servletName.equals(elName))
419             servletElement = el;
420       }
421       if (servletElement == null)
422          throw new DeploymentException("Cannot find <servlet> with servlet-name: " + servletName);
423
424       // find the servlet-class
425
Element classElement = servletElement.element("servlet-class");
426       if (classElement == null)
427          throw new DeploymentException("Cannot find <servlet-class> for servlet-name: " + servletName);
428
429       // replace the class name
430
String JavaDoc servletClass = classElement.getTextTrim();
431       String JavaDoc serviceEndpointServletName = getServiceEndpointServletName();
432
433       // Nothing to do if we have an <init-param> with the WebServiceID
434
if (isAlreadyModified(servletElement) == false)
435       {
436          classElement.setText(serviceEndpointServletName);
437
438          // build a list of detached elements that come after <servlet-class>
439
boolean startDetach = false;
440          ArrayList JavaDoc detachedElements = new ArrayList JavaDoc();
441          itServlet = servletElement.elements().iterator();
442          while (itServlet.hasNext())
443          {
444             Element el = (Element)itServlet.next();
445             if (startDetach == true)
446             {
447                detachedElements.add(el);
448                el.detach();
449             }
450             if (el.equals(classElement))
451                startDetach = true;
452          }
453
454          // add additional init params
455
Element paramElement = servletElement.addElement("init-param");
456          paramElement.addElement("param-name").addText(INIT_PARAM_WEBSERVICE_ID);
457          paramElement.addElement("param-value").addText(pcInfo.getServiceID());
458
459          // In case of the generated web.xml for EJB endpoints
460
// we don't have an endpoint implemenation pojo in <servlet-class>
461
if (servletClass.equals(serviceEndpointServletName) == false)
462          {
463             paramElement = servletElement.addElement("init-param");
464             paramElement.addElement("param-name").addText(INIT_PARAM_SERVICE_ENDPOINT_IMPL);
465             paramElement.addElement("param-value").addText(servletClass);
466          }
467
468          PortComponentMetaData pcMetaData = pcInfo.getPortComponentMetaData();
469          pcMetaData.setServiceEndpointBean(servletClass);
470
471          // reattach the elements
472
itServlet = detachedElements.iterator();
473          while (itServlet.hasNext())
474          {
475             Element el = (Element)itServlet.next();
476             servletElement.add(el);
477          }
478
479          return true;
480       }
481       else
482       {
483          Iterator JavaDoc it = servletElement.elementIterator("init-param");
484          while (it.hasNext())
485          {
486             Element elParam = (Element)it.next();
487             if (INIT_PARAM_SERVICE_ENDPOINT_IMPL.equals(elParam.elementText("param-name")))
488             {
489                String JavaDoc serviceEndpointImpl = elParam.elementText("param-value");
490                PortComponentMetaData pcMetaData = pcInfo.getPortComponentMetaData();
491                pcMetaData.setServiceEndpointBean(serviceEndpointImpl);
492             }
493          }
494
495          return false;
496       }
497    }
498
499    // Return true if the web.xml is already modified
500
private boolean isAlreadyModified(Element servletElement)
501    {
502       String JavaDoc serviceID = null;
503
504       Iterator JavaDoc it = servletElement.elementIterator("init-param");
505       while (serviceID == null && it.hasNext())
506       {
507          Element elParam = (Element)it.next();
508          if (INIT_PARAM_WEBSERVICE_ID.equals(elParam.elementText("param-name")))
509             serviceID = elParam.elementText("param-value");
510       }
511
512       return serviceID != null;
513    }
514
515    /**
516     * Override to return the name of the service endpoint servlet
517     */

518    protected abstract String JavaDoc getServiceEndpointServletName();
519
520    /**
521     * This guy resolves the service location, when ask to do so
522     */

523    public class ServiceLocationResolver
524    {
525       private DeploymentInfo di;
526
527       public ServiceLocationResolver(DeploymentInfo di)
528       {
529          this.di = di;
530       }
531
532       public boolean alwaysResolve()
533       {
534          return axisService.isAlwaysModifySOAPAddress();
535       }
536
537       /**
538        * Get the web service address for either an JSE or an EJB endpoint
539        * <p/>
540        * EJB: [schema][host]:[port]/[port-component-uri|deployment name/port-component-name]
541        * JSE: [schema][host]:[port]/[path derived from servlet mapping in web.xml]
542        *
543        * @param schema The url schema, can be 'http://' or 'https://', or null
544        * @param pcmd The port component meta data
545        * @return
546        */

547       public String JavaDoc getServiceLocation(String JavaDoc schema, PortComponentMetaData pcmd)
548       {
549          String JavaDoc ejbLink = pcmd.getEjbLink();
550          String JavaDoc servletLink = pcmd.getServletLink();
551          String JavaDoc serviceName = pcmd.getPortComponentName();
552
553          String JavaDoc servicePath = null;
554
555          // For a web based service endpoint it is derived from the servlet mapping
556
if (servletLink != null)
557          {
558             WebMetaData metaData = (WebMetaData)di.metaData;
559             Map JavaDoc servletMappings = metaData.getServletMappings();
560             String JavaDoc urlPattern = (String JavaDoc)servletMappings.get(servletLink);
561             if (urlPattern == null)
562                throw new IllegalStateException JavaDoc("Cannot obtain servlet-mapping for: " + servletLink);
563
564             if (urlPattern.startsWith("/") == false)
565                urlPattern = "/" + urlPattern;
566
567             servicePath = metaData.getContextRoot() + urlPattern;
568          }
569          else if (ejbLink != null)
570          {
571             ApplicationMetaData amd = (ApplicationMetaData)di.metaData;
572             BeanMetaData bmd = (BeanMetaData)amd.getBeanByEjbName(ejbLink);
573             if (bmd == null)
574                throw new IllegalStateException JavaDoc("Cannot find ejb-name: " + ejbLink);
575
576             // Use the webservice context root if we have one
577
String JavaDoc contextRoot = amd.getWebServiceContextRoot();
578
579             // If not, derive the context root from the deployment short name
580
if (contextRoot == null)
581             {
582                String JavaDoc shortName = di.shortName;
583                contextRoot = shortName.substring(0, shortName.indexOf('.'));
584                contextRoot = "/" + contextRoot;
585                amd.setWebServiceContextRoot(contextRoot);
586             }
587
588             EjbPortComponentMetaData ejbpcMetaData = bmd.getPortComponent();
589             if (ejbpcMetaData != null && ejbpcMetaData.getPortComponentURI() != null)
590             {
591                servicePath = contextRoot + ejbpcMetaData.getPortComponentURI();
592             }
593             else
594             {
595                servicePath = contextRoot + "/" + serviceName;
596             }
597          }
598          else
599          {
600             throw new IllegalStateException JavaDoc("Cannot find valid <servlet-link> nor <ejb-link> in port component meta data");
601          }
602
603          if (servicePath.endsWith("/*"))
604             servicePath = servicePath.substring(0, servicePath.indexOf("/*"));
605
606          if (schema == null)
607             schema = "http://";
608
609          int port = 0;
610          String JavaDoc host = null;
611          String JavaDoc serviceEndpointAddress = null;
612          try
613          {
614             host = axisService.getWebServiceHost();
615             port = axisService.getWebServicePort();
616             if ("https://".equals(schema))
617                port = axisService.getWebServiceSecurePort();
618
619             serviceEndpointAddress = new URL JavaDoc(schema + host + ":" + port + servicePath).toExternalForm();
620          }
621          catch (Exception JavaDoc e)
622          {
623             log.error("Cannot obtain attribute from AxisService, cause: " + e.toString());
624          }
625
626          return serviceEndpointAddress;
627       }
628    }
629 }
630
Popular Tags