package org.jboss.webservice;
import org.dom4j.Document;
import org.dom4j.Element;
import org.jboss.deployment.DeploymentException;
import org.jboss.deployment.DeploymentInfo;
import org.jboss.deployment.MainDeployerMBean;
import org.jboss.deployment.SubDeployer;
import org.jboss.logging.Logger;
import org.jboss.metadata.ApplicationMetaData;
import org.jboss.metadata.BeanMetaData;
import org.jboss.metadata.EjbPortComponentMetaData;
import org.jboss.metadata.WebMetaData;
import org.jboss.mx.util.MBeanProxy;
import org.jboss.mx.util.MBeanProxyCreationException;
import org.jboss.system.ServiceMBeanSupport;
import org.jboss.webservice.metadata.PortComponentMetaData;
import org.jboss.webservice.metadata.WebserviceDescriptionMetaData;
import org.jboss.webservice.metadata.WebservicesFactory;
import org.jboss.webservice.metadata.WebservicesMetaData;
import org.jboss.xml.binding.ObjectModelFactory;
import org.jboss.xml.binding.Unmarshaller;
import javax.management.InstanceNotFoundException;
import javax.management.Notification;
import javax.management.NotificationFilterSupport;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public abstract class ServiceDeployer extends ServiceMBeanSupport
implements ServiceDeployerMBean, NotificationListener
{
private final Logger log = Logger.getLogger(ServiceDeployer.class);
public static final String INIT_PARAM_WEBSERVICE_ID = "WebServiceID";
public static final String INIT_PARAM_SERVICE_ENDPOINT_IMPL = "ServiceEndpointImpl";
public static final String WEBSERVICE_CONTEXT_ROOT = "webservice-context-root";
private AxisServiceMBean axisService;
protected Map webservicesMap = new HashMap();
protected void startService() throws Exception
{
super.startService();
axisService = (AxisServiceMBean)MBeanProxy.get(AxisServiceMBean.class, AxisServiceMBean.OBJECT_NAME, server);
}
public void handleNotification(Notification notification, Object handback)
{
DeploymentInfo di = (DeploymentInfo)notification.getUserData();
String moduleName = di.shortName;
String type = notification.getType();
log.debug("handleNotification: " + type + "," + moduleName);
if (isWebservicesDeployment(di))
{
try
{
if (type.equals(SubDeployer.INIT_NOTIFICATION))
initWebservice(di);
else if (type.equals(SubDeployer.CREATE_NOTIFICATION))
createWebservice(di);
else if (type.equals(SubDeployer.START_NOTIFICATION))
startWebservice(di);
}
catch (Throwable e)
{
handleStartupException(di, e);
}
try
{
if (type.equals(SubDeployer.STOP_NOTIFICATION))
stopWebservice(di);
else if (type.equals(SubDeployer.DESTROY_NOTIFICATION))
destroyWebservice(di);
}
catch (Throwable e)
{
handleShutdownException(moduleName, e);
}
}
}
protected void initWebservice(DeploymentInfo di) throws DeploymentException
{
if (di.metaData instanceof ApplicationMetaData)
{
ApplicationMetaData applMetaData = (ApplicationMetaData)di.metaData;
applMetaData.setWebServiceDeployment(true);
}
if (di.metaData instanceof WebMetaData)
{
WebMetaData webMetaData = (WebMetaData)di.metaData;
webMetaData.setWebServiceDeployment(true);
}
}
protected void createWebservice(DeploymentInfo di) throws DeploymentException
{
URL url = getWebservicesDescriptor(di);
if (url != null)
{
WebservicesMetaData wsMetaData = parseWebservicesXML(di, url);
webservicesMap.put(di.url, wsMetaData);
}
}
protected abstract URL getWebservicesDescriptor(DeploymentInfo di);
private boolean isWebservicesDeployment(DeploymentInfo di)
{
if (getWebservicesDescriptor(di) != null)
return true;
if (di.metaData instanceof ApplicationMetaData)
{
ApplicationMetaData applMetaData = (ApplicationMetaData)di.metaData;
return applMetaData.isWebServiceDeployment();
}
if (di.metaData instanceof WebMetaData)
{
WebMetaData webMetaData = (WebMetaData)di.metaData;
return webMetaData.isWebServiceDeployment();
}
return false;
}
protected void startWebservice(DeploymentInfo di) throws DeploymentException
{
WebservicesMetaData webservices = (WebservicesMetaData)webservicesMap.get(di.url);
if (webservices != null)
{
ServiceLocationResolver locationResolver = new ServiceLocationResolver(di);
WebserviceDescriptionMetaData[] wsdArray = webservices.getWebserviceDescriptions();
for (int i = 0; i < wsdArray.length; i++)
{
WebserviceDescriptionMetaData wsdMetaData = wsdArray[i];
wsdMetaData.updateServiceAddress(locationResolver);
String wsdName = wsdMetaData.getWebserviceDescriptionName();
if (di.metaData instanceof ApplicationMetaData)
{
ApplicationMetaData applMetaData = (ApplicationMetaData)di.metaData;
String wsdlPublishLocation = applMetaData.getWsdlPublishLocationByName(wsdName);
wsdMetaData.setWsdlPublishLocation(wsdlPublishLocation);
}
if (di.metaData instanceof WebMetaData)
{
WebMetaData webMetaData = (WebMetaData)di.metaData;
String wsdlPublishLocation = webMetaData.getWsdlPublishLocationByName(wsdName);
wsdMetaData.setWsdlPublishLocation(wsdlPublishLocation);
}
}
WSDLFilePublisher wsdlfp = new WSDLFilePublisher(di);
wsdlfp.publishWsdlFile(webservices);
deployWebservices(di, webservices);
}
}
protected void stopWebservice(DeploymentInfo di)
{
WebservicesMetaData webservices = (WebservicesMetaData)webservicesMap.get(di.url);
if (webservices != null)
{
undeployWebservices(di, webservices);
WSDLFilePublisher wsdlfp = new WSDLFilePublisher(di);
wsdlfp.unpublishWsdlFile();
}
}
protected void destroyWebservice(DeploymentInfo di)
{
webservicesMap.remove(di.url);
}
protected void handleStartupException(DeploymentInfo di, Throwable th)
{
log.error("Cannot startup webservice for: " + di.shortName, th);
try
{
MainDeployerMBean mainDeployer = (MainDeployerMBean)MBeanProxy.get(MainDeployerMBean.class, MainDeployerMBean.OBJECT_NAME, server);
mainDeployer.undeploy(di);
}
catch (MBeanProxyCreationException e)
{
e.printStackTrace();
}
}
protected void handleShutdownException(String moduleName, Throwable th)
{
log.error("Cannot shutdown webservice for: " + moduleName, th);
}
protected void registerNotificationListener(ObjectName serviceName)
throws InstanceNotFoundException
{
NotificationFilterSupport filter = new NotificationFilterSupport();
filter.enableType(SubDeployer.INIT_NOTIFICATION);
filter.enableType(SubDeployer.CREATE_NOTIFICATION);
filter.enableType(SubDeployer.START_NOTIFICATION);
filter.enableType(SubDeployer.STOP_NOTIFICATION);
filter.enableType(SubDeployer.DESTROY_NOTIFICATION);
server.addNotificationListener(serviceName, this, filter, null);
}
protected void unregisterNotificationListener(ObjectName serviceName)
{
try
{
server.removeNotificationListener(serviceName, this);
}
catch (Exception e)
{
log.error("Cannot remove notification listener: " + e.toString());
}
}
protected WebservicesMetaData parseWebservicesXML(DeploymentInfo di, URL webservicesURL) throws DeploymentException
{
WebservicesMetaData webservices = null;
try
{
InputStream is = webservicesURL.openStream();
try
{
Unmarshaller unmarshaller = new Unmarshaller();
ObjectModelFactory factory = new WebservicesFactory(di.localCl);
webservices = (WebservicesMetaData)unmarshaller.unmarshal(is, factory, null);
}
finally
{
is.close();
}
}
catch (Exception e)
{
throw new DeploymentException("Cannot obtain webservices meta data", e);
}
return webservices;
}
protected void deployWebservices(DeploymentInfo di, WebservicesMetaData webservices)
throws DeploymentException
{
try
{
WebserviceDescriptionMetaData[] wsdArr = webservices.getWebserviceDescriptions();
for (int i = 0; i < wsdArr.length; i++)
{
WebserviceDescriptionMetaData wsd = wsdArr[i];
PortComponentMetaData[] pcArr = wsd.getPortComponents();
for (int j = 0; j < pcArr.length; j++)
{
PortComponentMetaData pcMetaData = pcArr[j];
PortComponentInfo pcInfo = new PortComponentInfo(di, pcMetaData);
axisService.deployService(pcInfo);
}
}
}
catch (Exception e)
{
throw new DeploymentException("Cannot deploy webservice", e);
}
}
protected void undeployWebservices(DeploymentInfo di, WebservicesMetaData webservices)
{
try
{
WebserviceDescriptionMetaData[] wsdarr = webservices.getWebserviceDescriptions();
for (int i = 0; i < wsdarr.length; i++)
{
WebserviceDescriptionMetaData wsDescription = wsdarr[i];
PortComponentMetaData[] pcarr = wsDescription.getPortComponents();
for (int j = 0; j < pcarr.length; j++)
{
PortComponentMetaData pcMetaData = pcarr[j];
PortComponentInfo pcInfo = new PortComponentInfo(di, pcMetaData);
String wsID = pcInfo.getServiceID();
axisService.undeployService(wsID);
}
}
}
catch (Exception ignore)
{
log.warn("Cannot undeploy webservice: " + ignore);
}
}
protected boolean modifyServletConfig(Document doc, String servletName, PortComponentInfo pcInfo) throws DeploymentException
{
Element servletElement = null;
Iterator itServlet = doc.getRootElement().elements("servlet").iterator();
while (itServlet.hasNext() && servletElement == null)
{
Element el = (Element)itServlet.next();
String elName = el.elementTextTrim("servlet-name");
if (servletName.equals(elName))
servletElement = el;
}
if (servletElement == null)
throw new DeploymentException("Cannot find <servlet> with servlet-name: " + servletName);
Element classElement = servletElement.element("servlet-class");
if (classElement == null)
throw new DeploymentException("Cannot find <servlet-class> for servlet-name: " + servletName);
String servletClass = classElement.getTextTrim();
String serviceEndpointServletName = getServiceEndpointServletName();
if (isAlreadyModified(servletElement) == false)
{
classElement.setText(serviceEndpointServletName);
boolean startDetach = false;
ArrayList detachedElements = new ArrayList();
itServlet = servletElement.elements().iterator();
while (itServlet.hasNext())
{
Element el = (Element)itServlet.next();
if (startDetach == true)
{
detachedElements.add(el);
el.detach();
}
if (el.equals(classElement))
startDetach = true;
}
Element paramElement = servletElement.addElement("init-param");
paramElement.addElement("param-name").addText(INIT_PARAM_WEBSERVICE_ID);
paramElement.addElement("param-value").addText(pcInfo.getServiceID());
if (servletClass.equals(serviceEndpointServletName) == false)
{
paramElement = servletElement.addElement("init-param");
paramElement.addElement("param-name").addText(INIT_PARAM_SERVICE_ENDPOINT_IMPL);
paramElement.addElement("param-value").addText(servletClass);
}
PortComponentMetaData pcMetaData = pcInfo.getPortComponentMetaData();
pcMetaData.setServiceEndpointBean(servletClass);
itServlet = detachedElements.iterator();
while (itServlet.hasNext())
{
Element el = (Element)itServlet.next();
servletElement.add(el);
}
return true;
}
else
{
Iterator it = servletElement.elementIterator("init-param");
while (it.hasNext())
{
Element elParam = (Element)it.next();
if (INIT_PARAM_SERVICE_ENDPOINT_IMPL.equals(elParam.elementText("param-name")))
{
String serviceEndpointImpl = elParam.elementText("param-value");
PortComponentMetaData pcMetaData = pcInfo.getPortComponentMetaData();
pcMetaData.setServiceEndpointBean(serviceEndpointImpl);
}
}
return false;
}
}
private boolean isAlreadyModified(Element servletElement)
{
String serviceID = null;
Iterator it = servletElement.elementIterator("init-param");
while (serviceID == null && it.hasNext())
{
Element elParam = (Element)it.next();
if (INIT_PARAM_WEBSERVICE_ID.equals(elParam.elementText("param-name")))
serviceID = elParam.elementText("param-value");
}
return serviceID != null;
}
protected abstract String getServiceEndpointServletName();
public class ServiceLocationResolver
{
private DeploymentInfo di;
public ServiceLocationResolver(DeploymentInfo di)
{
this.di = di;
}
public boolean alwaysResolve()
{
return axisService.isAlwaysModifySOAPAddress();
}
public String getServiceLocation(String schema, PortComponentMetaData pcmd)
{
String ejbLink = pcmd.getEjbLink();
String servletLink = pcmd.getServletLink();
String serviceName = pcmd.getPortComponentName();
String servicePath = null;
if (servletLink != null)
{
WebMetaData metaData = (WebMetaData)di.metaData;
Map servletMappings = metaData.getServletMappings();
String urlPattern = (String)servletMappings.get(servletLink);
if (urlPattern == null)
throw new IllegalStateException("Cannot obtain servlet-mapping for: " + servletLink);
if (urlPattern.startsWith("/") == false)
urlPattern = "/" + urlPattern;
servicePath = metaData.getContextRoot() + urlPattern;
}
else if (ejbLink != null)
{
ApplicationMetaData amd = (ApplicationMetaData)di.metaData;
BeanMetaData bmd = (BeanMetaData)amd.getBeanByEjbName(ejbLink);
if (bmd == null)
throw new IllegalStateException("Cannot find ejb-name: " + ejbLink);
String contextRoot = amd.getWebServiceContextRoot();
if (contextRoot == null)
{
String shortName = di.shortName;
contextRoot = shortName.substring(0, shortName.indexOf('.'));
if (di.parent != null)
{
shortName = di.parent.shortName;
contextRoot = shortName.substring(0, shortName.indexOf('.')) + "/" + contextRoot;
}
contextRoot = "/" + contextRoot;
}
di.context.put(WEBSERVICE_CONTEXT_ROOT, contextRoot);
EjbPortComponentMetaData ejbpcMetaData = bmd.getPortComponent();
if (ejbpcMetaData != null && ejbpcMetaData.getPortComponentURI() != null)
{
servicePath = ejbpcMetaData.getPortComponentURI();
}
else
{
servicePath = contextRoot + "/" + serviceName;
}
}
else
{
throw new IllegalStateException("Cannot find valid <servlet-link> nor <ejb-link> in port component meta data");
}
if (servicePath.endsWith("/*"))
servicePath = servicePath.substring(0, servicePath.indexOf("/*"));
if (schema == null)
schema = "http://";
int port = 0;
String host = null;
String serviceEndpointAddress = null;
try
{
host = axisService.getWebServiceHost();
port = axisService.getWebServicePort();
if ("https://".equals(schema))
port = axisService.getWebServiceSecurePort();
serviceEndpointAddress = new URL(schema + host + ":" + port + servicePath).toExternalForm();
}
catch (Exception e)
{
log.error("Cannot obtain attribute from AxisService, cause: " + e.toString());
}
return serviceEndpointAddress;
}
}
}