/*
* JBoss, Home of Professional Open Source Copyright 2009, Red Hat Middleware
* LLC, and individual contributors by the @authors tag. See the copyright.txt
* in the distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this software; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
* site: http://www.fsf.org.
*/
package org.jboss.soa.esb.listeners.deployers.mc;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.log4j.Logger;
import org.jboss.deployers.spi.DeploymentException;
import org.jboss.deployers.spi.deployer.DeploymentStages;
import org.jboss.deployers.vfs.spi.deployer.AbstractSimpleVFSRealDeployer;
import org.jboss.deployers.vfs.spi.structure.VFSDeploymentUnit;
import org.jboss.internal.soa.esb.listeners.war.Filter;
import org.jboss.internal.soa.esb.listeners.war.SecurityConstraints;
import org.jboss.internal.soa.esb.listeners.war.Servlet;
import org.jboss.internal.soa.esb.listeners.war.WebModel;
import org.jboss.internal.soa.esb.publish.ContractReferencePublisher;
import org.jboss.internal.soa.esb.publish.DefaultContractReferencePublisher;
import org.jboss.internal.soa.esb.util.JBossDeployerUtil;
import org.jboss.internal.soa.esb.webservice.ESBResponseFilter;
import org.jboss.internal.soa.esb.webservice.ESBServiceContractReferencePublisher;
import org.jboss.internal.soa.esb.webservice.ESBServiceEndpointInfo;
import org.jboss.internal.soa.esb.webservice.JAXWSProviderClassGenerator;
import org.jboss.internal.soa.esb.webservice.WebServicePublishException;
import org.jboss.metadata.common.jboss.WebserviceDescriptionMetaData;
import org.jboss.metadata.common.jboss.WebserviceDescriptionsMetaData;
import org.jboss.metadata.javaee.spec.ParamValueMetaData;
import org.jboss.metadata.javaee.spec.SecurityRoleMetaData;
import org.jboss.metadata.javaee.spec.SecurityRolesMetaData;
import org.jboss.metadata.web.jboss.JBossServletMetaData;
import org.jboss.metadata.web.jboss.JBossServletsMetaData;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import org.jboss.metadata.web.spec.AuthConstraintMetaData;
import org.jboss.metadata.web.spec.FilterMappingMetaData;
import org.jboss.metadata.web.spec.FilterMetaData;
import org.jboss.metadata.web.spec.FiltersMetaData;
import org.jboss.metadata.web.spec.LoginConfigMetaData;
import org.jboss.metadata.web.spec.SecurityConstraintMetaData;
import org.jboss.metadata.web.spec.ServletMappingMetaData;
import org.jboss.metadata.web.spec.TransportGuaranteeType;
import org.jboss.metadata.web.spec.UserDataConstraintMetaData;
import org.jboss.metadata.web.spec.WebResourceCollectionMetaData;
import org.jboss.metadata.web.spec.WebResourceCollectionsMetaData;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.Service;
import org.jboss.soa.esb.helpers.KeyValuePair;
import org.jboss.soa.esb.listeners.config.ModelUtil;
import org.jboss.soa.esb.listeners.config.ServiceContract;
import org.jboss.soa.esb.listeners.config.WebserviceInfo;
import org.jboss.soa.esb.listeners.deployers.mc.util.VfsUtil;
import org.jboss.virtual.MemoryFileFactory;
import org.jboss.virtual.VirtualFile;
/**
* EsbWebServiceDeployer is responsible for deploying the web service that will
* expose the underlying ESB service as a web service.
* <p/>
*
* @author <a href="mailto:dbevenius@jboss.com">Daniel Bevenius</a>
*
*/
public class EsbWebServiceDeployer extends AbstractSimpleVFSRealDeployer<EsbMetaData>
{
/** Logger */
private Logger log = Logger.getLogger(EsbWebServiceDeployer.class);
/**
* Key used for attaching a VirtualFile representing a ref to
* a dynamically created root virtual file system.
*/
static final String DYNAMIC_CL_DIR_KEY = "WS-DYNAMIC-CL-DIR";
/**
* Key used for attaching a URL representing a ref to
* a dynamically created root virtual file system.
*/
static final String DYNAMIC_CL_URL_KEY = "WS-DYNAMIC-CL-URL";
/**
* Key used for attaching a VirtualFile representing a ref to
* a dynamically created WEB-INF/classes virtual file system.
*/
static final String DYNAMIC_WEBINF_CL_DIR_KEY = "WS-WEBINF-DYNAMIC-CL-DIR";
/**
* Key used for attaching a URL representing a ref to
* a dynamically created WEB-INF/classes virtual file system.
*/
static final String DYNAMIC_WEBINF_CL_URL_KEY = "WS-WEBINF-DYNAMIC-CL-URL";
/**
* Sole constructor that performas the following steps:
* <lu>
* <li>Sets the output of this deployer to be {@link EsbMetaData}.</li>
* <li>Sets this deployers deployment stage to {@link DeploymentStages#POST_PARSE}./li>
* <li>Specifies that this deployer produces JBossWebMetaData and EsbMetaData./li>
* </lu>
*/
public EsbWebServiceDeployer()
{
super(EsbMetaData.class);
// Set the deployment stage to after parse.
setStage(DeploymentStages.POST_PARSE);
// Tell the MicroContainer that we are producing JBossWebMetaData.
setOutput(JBossWebMetaData.class);
// Tell the MicroContainer that we are producing EsbMetaData.
setOutput(EsbMetaData.class);
}
@Override
public void deploy(final VFSDeploymentUnit unit, final EsbMetaData esbMetaData) throws DeploymentException
{
boolean webMetaDataCreated = false;
final JBossWebMetaData webMetaData = new JBossWebMetaData();
final JBossServletsMetaData servlets = new JBossServletsMetaData();
final List<ServletMappingMetaData> servletMappings = new ArrayList<ServletMappingMetaData>();
final FiltersMetaData filters = new FiltersMetaData();
final List<FilterMappingMetaData> filterMappings = new ArrayList<FilterMappingMetaData>();
final List<ContractReferencePublisher> publishers = new ArrayList<ContractReferencePublisher>() ;
final List<SecurityConstraintMetaData> securityConstraintsMDs = new ArrayList<SecurityConstraintMetaData>();
final WebserviceDescriptionsMetaData descriptions = new WebserviceDescriptionsMetaData();
final List<WebserviceInfo> webServices = esbMetaData.getModel().getWebserviceServices();
if (hasWebServices(webServices))
{
webMetaDataCreated = true;
log.debug("Deploying webservices for : " + esbMetaData.getDeploymentName());
try
{
// Create an in-memory file system.
final URL inMemRootUrl = VfsUtil.createInMemUrl(esbMetaData.getDeploymentName());
final VirtualFile inMemRootDir = VfsUtil.createInMemoryFs(inMemRootUrl);
// Attach the in-memory classpath URL and virtual file to this deployment unit so we can remove then upon undeploy.
//attachToDeploymentUnit(unit, inMemRootUrl, inMemRootDir);
unit.addAttachment(DYNAMIC_CL_DIR_KEY, inMemRootDir);
unit.addAttachment(DYNAMIC_CL_URL_KEY, inMemRootUrl);
// Add the in-memory classpath to this deployment unit.
unit.addClassPath(inMemRootDir);
// Create WEB-INF/classes relative to the in-memory vfs root.
final URL classesUrl = VfsUtil.createInMemUrl(inMemRootUrl, "WEB-INF/classes");
final VirtualFile classesDir = MemoryFileFactory.createDirectory(classesUrl);
unit.addAttachment(DYNAMIC_WEBINF_CL_DIR_KEY, classesDir);
unit.addAttachment(DYNAMIC_WEBINF_CL_URL_KEY, classesUrl);
// Add the in-memory classes dir to this deployment unit.
unit.addClassPath(classesDir);
final JAXWSProviderClassGenerator generator = new JAXWSProviderClassGenerator();
for (WebserviceInfo wsInfo : webServices)
{
final ESBServiceEndpointInfo serviceInfo = new ESBServiceEndpointInfo(wsInfo);
final String handlers = JBossDeployerUtil.getHandlers(serviceInfo);
final boolean includeHandlers = handlers != null;
if (includeHandlers)
{
unit.appendMetaDataLocation(classesDir);
final String wsHandlerName = serviceInfo.getPackageName().replace('.', '/') + "/esb-jaxws-handlers.xml";
VfsUtil.addFile(classesUrl, wsHandlerName, handlers.getBytes());
}
if (serviceInfo.isOneWay())
{
FilterMetaData filter = createFilter(serviceInfo);
filters.add(filter);
filterMappings.add(createFilterMapping(serviceInfo, filter));
}
final Service service = wsInfo.getService();
// Generate the servlet class bytes
final byte[] servletClass = generator.generate(service.getCategory(), service.getName(), serviceInfo, includeHandlers);
final String servletClassName = serviceInfo.getClassName().replace('.', '/') + ".class";
final URL servletClassUrl = VfsUtil.createInMemUrl(classesUrl, servletClassName);
// Add the servlet to the virtual file system.
VfsUtil.addFile(classesUrl, servletClassName, servletClass);
log.debug("Generated ServletImpl '" + servletClassUrl + "'");
servlets.add(createServlets(serviceInfo, generator, includeHandlers));
servletMappings.add(createServletMapping(serviceInfo));
final WebserviceDescriptionMetaData description = new WebserviceDescriptionMetaData();
description.setName(esbMetaData.getDeploymentName());
description.setWebserviceDescriptionName(esbMetaData.getDeploymentName());
description.setWsdlPublishLocation(serviceInfo.getWSDLFileName());
descriptions.add(description);
final ContractReferencePublisher publisher = new ESBServiceContractReferencePublisher(service, wsInfo.getDescription(), serviceInfo.getServletName());
publishers.add(publisher);
}
}
catch (final Exception e)
{
throw new DeploymentException("Failed to create webservice artifact", e);
}
}
WebModel webModel = new WebModel(esbMetaData.getArchiveName());
try {
// Set the global security domain and global security method.
// These setting are shared for all http-providers and EBWSs
// in a jboss-esb.xml file.
webModel.setAuthDomain(esbMetaData.getModel().getAuthDomain());
webModel.setAuthMethod(esbMetaData.getModel().getAuthMethod());
ModelUtil.updateWebModel(ModelUtil.getListenerGroups(esbMetaData.getModel()), webModel);
} catch (ConfigurationException e) {
throw new DeploymentException("Failed to capture web metadata from ESB configuration.", e);
}
// Handle the ServiceContracts
List<ServiceContract> modelServiceContracts = esbMetaData.getModel().getServiceContracts();
if (modelServiceContracts != null && modelServiceContracts.size() > 0) {
List<ServiceContract> actionableServiceContracts = new ArrayList<ServiceContract>();
for (Servlet servlet : webModel.getServlets()) {
Service service = servlet.getService();
String endpointAddress = servlet.getEndpointAddress();
if (service != null && endpointAddress != null) {
for (ServiceContract serviceContract : modelServiceContracts) {
if (service.equals(serviceContract.getService())) {
actionableServiceContracts.add(serviceContract);
publishers.add(
new DefaultContractReferencePublisher(
service, serviceContract.getDescription(), endpointAddress ) );
break; // first ServiceContract matching a Servlet wins!
}
}
}
}
esbMetaData.setServiceContracts(actionableServiceContracts);
}
// Add the filters...
for(Filter filter : webModel.getFilters()) {
webMetaDataCreated = true;
filters.add(createFilter(filter));
filterMappings.add(createFilterMapping(filter));
}
// Add the Servlets...
for(Servlet servlet : webModel.getServlets()) {
webMetaDataCreated = true;
servlets.add(createServlet(servlet));
servletMappings.add(createServletMapping(servlet));
SecurityConstraints securityConstraints = servlet.getSecurityConstraints();
if(securityConstraints != null) {
SecurityConstraintMetaData securityConstraintMD = new SecurityConstraintMetaData();
securityConstraintsMDs.add(securityConstraintMD);
securityConstraintMD.setDisplayName("Constraints for servlet '" + servlet.getName() + "'.");
// Add the resource details...
WebResourceCollectionsMetaData resources = new WebResourceCollectionsMetaData();
WebResourceCollectionMetaData resource = new WebResourceCollectionMetaData();
resources.add(resource);
securityConstraintMD.setResourceCollections(resources);
resource.setHttpMethods(new ArrayList(securityConstraints.getProtectedMethods()));
resource.setUrlPatterns(servlet.getUrlMappings());
// Add the Auth Constraint...
if(!securityConstraints.getAllowedRoles().isEmpty()) {
AuthConstraintMetaData constraint = new AuthConstraintMetaData();
constraint.setRoleNames(new ArrayList(securityConstraints.getAllowedRoles()));
securityConstraintMD.setAuthConstraint(constraint);
}
// Add the User Constraint...
if(securityConstraints.getTransportGuarantee() != null) {
UserDataConstraintMetaData constraint = new UserDataConstraintMetaData();
constraint.setTransportGuarantee(TransportGuaranteeType.valueOf(securityConstraints.getTransportGuarantee()));
securityConstraintMD.setUserDataConstraint(constraint);
}
}
}
if(webModel.getAuthMethod() != null) {
LoginConfigMetaData loginConfig = new LoginConfigMetaData();
loginConfig.setAuthMethod(webModel.getAuthMethod());
loginConfig.setRealmName("Authentication Realm for '" + esbMetaData.getArchiveName() + "'");
webMetaData.setLoginConfig(loginConfig);
}
if(webModel.getAuthDomain() != null) {
webMetaData.setSecurityDomain(webModel.getAuthDomain());
}
if(!webModel.getSecurityRoles().isEmpty()) {
SecurityRolesMetaData secRolesMetaData = new SecurityRolesMetaData();
webMetaData.setSecurityRoles(secRolesMetaData);
for(String role : webModel.getSecurityRoles()) {
SecurityRoleMetaData secRoleMetaData = new SecurityRoleMetaData();
secRoleMetaData.setRoleName(role);
secRolesMetaData.add(secRoleMetaData);
}
}
if(webMetaDataCreated) {
webMetaData.setContextRoot(esbMetaData.getDeploymentName());
webMetaData.setServlets(servlets);
webMetaData.setServletMappings(servletMappings);
webMetaData.setFilters(filters);
webMetaData.setFilterMappings(filterMappings);
webMetaData.setWebserviceDescriptions(descriptions);
webMetaData.setSecurityContraints(securityConstraintsMDs);
esbMetaData.setPublishers(publishers);
unit.addAttachment(JBossWebMetaData.class, webMetaData);
}
}
@Override
public void undeploy(final VFSDeploymentUnit unit, final EsbMetaData esbMetaData)
{
try
{
removeVirtualFile(unit, DYNAMIC_CL_DIR_KEY);
removeVirtualFile(unit, DYNAMIC_WEBINF_CL_DIR_KEY);
}
finally
{
try
{
removeFromClassPath(unit, DYNAMIC_WEBINF_CL_URL_KEY);
removeFromClassPath(unit, DYNAMIC_CL_URL_KEY);
}
catch (final Exception e)
{
log.warn("Error deleting dynamic class root for " + unit.getName(), e);
}
}
}
private void removeVirtualFile(final VFSDeploymentUnit unit, final String attachmenKey)
{
final VirtualFile file = unit.removeAttachment(attachmenKey, VirtualFile.class);
if (file != null)
{
unit.removeClassPath(file);
}
}
private void removeFromClassPath(final VFSDeploymentUnit unit, final String attachmentKey)
{
final URL url = unit.removeAttachment(attachmentKey, URL.class);
if (url != null)
{
MemoryFileFactory.delete(url);
}
}
private boolean hasWebServices(final List<WebserviceInfo> endpointServices)
{
return endpointServices != null && endpointServices.size() > 0;
}
private ServletMappingMetaData createServletMapping(final ESBServiceEndpointInfo serviceInfo)
{
final ServletMappingMetaData mapping = new ServletMappingMetaData();
mapping.setServletName(serviceInfo.getServletName());
mapping.setUrlPatterns(Arrays.asList(new String[] { "/ebws" + serviceInfo.getServletPath()}));
return mapping;
}
private JBossServletMetaData createServlets(final ESBServiceEndpointInfo serviceInfo, final JAXWSProviderClassGenerator generator, final boolean includeHandlers) throws WebServicePublishException
{
final JBossServletMetaData servlet = new JBossServletMetaData();
servlet.setServletName(serviceInfo.getServletName());
servlet.setServletClass(serviceInfo.getClassName());
servlet.setLoadOnStartup(1);
return servlet;
}
private FilterMetaData createFilter(final ESBServiceEndpointInfo serviceInfo)
{
// Filter
final FilterMetaData filter = new FilterMetaData();
filter.setFilterName(serviceInfo.getServletName() + "_Filter");
filter.setFilterClass(ESBResponseFilter.class.getName());
// Set up the initparam 'OneWay'
final ParamValueMetaData oneWayInitParam = new ParamValueMetaData();
oneWayInitParam.setParamName("OneWay");
oneWayInitParam.setParamValue("true");
filter.setInitParam(Arrays.asList(new ParamValueMetaData[] {oneWayInitParam}));
return filter;
}
private FilterMappingMetaData createFilterMapping(ESBServiceEndpointInfo serviceInfo, FilterMetaData filter) {
FilterMappingMetaData mapping = new FilterMappingMetaData();
mapping.setFilterName(filter.getFilterName());
mapping.setServletNames(Arrays.asList(new String[] {serviceInfo.getServletName()}));
return mapping;
}
private JBossServletMetaData createServlet(Servlet servlet) {
JBossServletMetaData servletMD = new JBossServletMetaData();
servletMD.setServletName(servlet.getName());
servletMD.setServletClass(servlet.getRuntimeClass());
servletMD.setLoadOnStartup(1);
List<ParamValueMetaData> initParamsMetaData = createParamsMetaData(servlet.getParams());
if(initParamsMetaData != null) {
servletMD.setInitParam(initParamsMetaData);
}
return servletMD;
}
private ServletMappingMetaData createServletMapping(Servlet servlet) {
final ServletMappingMetaData mapping = new ServletMappingMetaData();
mapping.setServletName(servlet.getName());
mapping.setUrlPatterns(servlet.getUrlMappings());
return mapping;
}
private FilterMetaData createFilter(final Filter filter)
{
FilterMetaData filterMetaData = new FilterMetaData();
filterMetaData.setFilterName(filter.getName());
filterMetaData.setFilterClass(filter.getRuntimeClass());
List<ParamValueMetaData> initParamsMetaData = createParamsMetaData(filter.getParams());
if(initParamsMetaData != null) {
filterMetaData.setInitParam(initParamsMetaData);
}
return filterMetaData;
}
private List<ParamValueMetaData> createParamsMetaData(List<KeyValuePair> initParams) {
List<ParamValueMetaData> initParamsMetaData = null;
if(!initParams.isEmpty()) {
initParamsMetaData = new ArrayList<ParamValueMetaData>();
for(KeyValuePair initParam : initParams) {
ParamValueMetaData initParamMetaData = new ParamValueMetaData();
initParamMetaData.setParamName(initParam.getKey());
initParamMetaData.setParamValue(initParam.getValue());
initParamsMetaData.add(initParamMetaData);
}
}
return initParamsMetaData;
}
private FilterMappingMetaData createFilterMapping(Filter filter) {
FilterMappingMetaData mapping = new FilterMappingMetaData();
mapping.setFilterName(filter.getName());
mapping.setServletNames(Arrays.asList(new String[] {filter.getTargetServlet().getName()}));
return mapping;
}
}
|