| Deployment.java |
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
// $Id: Deployment.java,v 1.16.2.3 2005/03/02 14:19:53 tdiesler Exp $
package org.jboss.net.axis;
// axis config and utils
import org.jboss.axis.ConfigurationException;
import org.jboss.axis.MessageContext;
import org.jboss.axis.deployment.wsdd.WSDDConstants;
import org.jboss.axis.deployment.wsdd.WSDDDeployment;
import org.jboss.axis.deployment.wsdd.WSDDException;
import org.jboss.axis.deployment.wsdd.WSDDProvider;
import org.jboss.axis.deployment.wsdd.WSDDService;
import org.jboss.axis.deployment.wsdd.WSDDTypeMapping;
import org.jboss.axis.encoding.TypeMappingRegistry;
import org.jboss.axis.handlers.soap.SOAPService;
import org.jboss.logging.Logger;
import org.w3c.dom.Element;
import javax.xml.namespace.QName;
import javax.xml.rpc.encoding.DeserializerFactory;
import java.util.Iterator;
import java.util.List;
/**
* <p/>
* This subclass represents a wsdd deployment
* with scoped typemappings and service-specific
* classloading features. It may also serve as a place to
* statically register some other jboss-specific
* implementation classes in the axis package.
* </p>
* <p/>
* WSDDDeployment is used by Axis in two respects: Two parse a
* deployment descriptor and to host the accumulated
* configuration data. We use that circumstance to build up
* an additional deployment scope in jboss.net - services are
* registered in the central registry/engine but still pertain
* their relation (especially wrt typemapping delegation) to their
* original deployment. We do that by annotating the scope deployments
* in the service options.
* </p>
* <p/>
* This design is IMHO more clever and needs less
* overhead than the original approach of mapping services to
* classloaders. Furthermore, it allows us to introduce some JSR109
* related deployment concepts without global effect.
* </p>
*
* @author <a href="mailto:Christoph.Jung@infor.de">Christoph G. Jung</a>
* @version $Revision: 1.16.2.3 $
* @since 09.03.2002
*/
public class Deployment extends WSDDDeployment
{
private static Logger log = Logger.getLogger(Deployment.class);
//
// Attributes
//
/**
* holds the classloader related to this deployment
* which is the thread context classloader at creation time
*/
protected ClassLoader deploymentLoader;
/**
* these are our local typemappings
*/
protected List typeMappings = new java.util.ArrayList();
/**
* whether our registry has already been built
*/
protected boolean tmrCreated;
/**
* this handler provider will be injected into Axis to load
* implementations from the right classloaders
*/
static
{
WSDDProvider.registerProvider(WSDDConstants.QNAME_HANDLER_PROVIDER,
new ServiceClassLoaderAwareWSDDHandlerProvider());
}
//
// Constructors
//
/**
* Constructor for Deployment. Is used with server-config.wsdd
* in order to build the engine configuration. Is used with
* actual deployment documents to build scoped deployments.
* After calling the super constructor, we rebuild the typemappings
* with our typemapping implementation that may contain additional
* typemapping options. Unfortunately, you will have to do an
* enclosing Thread.currentThread().setContextClassLoader(loader)
* because of the f**cked constructor functionality of the super class.
* Its a 1st grade Java rule, guys! So rather use the static factory method.
*/
protected Deployment(Element e, ClassLoader loader) throws WSDDException
{
super(e);
this.deploymentLoader = loader;
// if axis did use more factories, we did not have to do this
Element[] elements = getChildElements(e, "typeMapping");
for (int i = 0; i < elements.length; i++)
{
TypeMapping mapping = new TypeMapping(elements[i]);
deployTypeMapping(mapping);
}
}
/**
* the safe "constructor"
*/
public static Deployment makeSafeDeployment(Element e, ClassLoader loader) throws WSDDException
{
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(loader);
try
{
return new Deployment(e, loader);
}
finally
{
Thread.currentThread().setContextClassLoader(old);
}
}
//
// protected helpers
//
/**
* return the deployment loader of this deployment
*/
protected ClassLoader getDeploymentLoader()
{
return deploymentLoader;
}
/**
* return the scoped deployment for this service
*/
protected static Deployment getDeployment(WSDDService service)
{
return (
(Deployment)service.getParametersTable().get(Constants.SERVICE_DEPLOYMENT_PARAMETER));
}
//
// Public API
//
/* (non-Javadoc)
* this is called whenever a service is parsed. This means that
* we will mark it to belong to us (and our classloader). Furthermore,
* upon existance of a dedicated paramter flag, we will shift the
* jaxrpc handler chain of the service into a separate property such
* that the provider class instead of the SoapService can control
* when it will be called.
* @see org.jboss.axis.deployment.wsdd.WSDDDeployment#deployService(org.jboss.axis.deployment.wsdd.WSDDService)
*/
public void deployService(WSDDService service)
{
// registers deployment instance in service
// note that besides this entry, there will be only strings
// in the hashtable so maybe axis will hickup at some places
// when it does not expect a real instance value
service.getParametersTable().put(Constants.SERVICE_DEPLOYMENT_PARAMETER,
this);
// do the handler chain shifting only once for parsing
if (service.getHandlerInfoChain() != null && "true".equals(service.getParameter(Constants.USE_PROVIDER_HANDLER_CHAIN)))
{
service.getParametersTable().put(Constants.PROVIDER_HANDLER_CHAIN, service.getHandlerInfoChain());
service.setParameter(Constants.USE_PROVIDER_HANDLER_CHAIN, "false");
service.setHandlerInfoChain(null);
}
super.deployService(service);
}
/**
* overwrite to equip with options
*/
public void deployTypeMapping(WSDDTypeMapping typeMapping)
throws WSDDException
{
// we only register our own stuff ;-)
if (typeMapping instanceof TypeMapping)
{
if (tmrCreated)
{
try
{
installTypeMappingWithOptions((TypeMapping)typeMapping);
}
catch (ConfigurationException e)
{
throw new WSDDException("Could not install type mapping with options." + e);
}
}
else
{
typeMappings.add(typeMapping);
}
}
}
/*
* overrides the getdeployedservices method in order
* to prebuild the service instances (and hence
* address classloading issues when browsing
* the services list during a "get")
* implicitely requires a current message context
* for which the serviceservlet must cater.
* @see org.jboss.axis.EngineConfiguration#getDeployedServices()
*/
public Iterator getDeployedServices() throws ConfigurationException
{
List serviceDescs = new java.util.ArrayList();
WSDDService[] services = getServices();
for (int count = 0; count < services.length; count++)
{
try
{
serviceDescs.add(getService(services[count].getQName()).
getServiceDescription());
}
catch (ConfigurationException ex)
{
// If it's non-fatal, just keep on going
log.debug("Ingoring non-fatal exception: ", ex);
}
}
return serviceDescs.iterator();
}
/**
* hides the "old" uncoped way of constructing services and their
* tmrs and wraps it into a classloader aware shell
*
* @param serviceName
* @return
* @throws ConfigurationException
*/
private SOAPService getServiceInternal(QName serviceName)
throws ConfigurationException
{
// This hack sets the deployment loader as the TCL
// If this is not done the org.jboss.test.jbossnet.admindevel.ExampleTestCase fails on redeployment
// The reason is that the HelloObj[] class gets loaded from a stale classloader
ClassLoader deploymentLoader = getDeploymentLoader();
Thread.currentThread().setContextClassLoader(deploymentLoader);
MessageContext currentContext = MessageContext.getCurrentContext();
if (currentContext != null)
currentContext.setClassLoader(deploymentLoader);
return super.getService(serviceName);
}
/* overrides the getService method in order
* to address scoping issues when setting service
* affinity. requires a current message context
* for which the serviceservlet must cater.
* @see org.jboss.axis.EngineConfiguration#getService(javax.xml.namespace.QName)
*/
public SOAPService getService(QName serviceName) throws ConfigurationException
{
// we lookup the service meta-data
WSDDService wsddService = getWSDDService(serviceName);
if (wsddService != null)
{
// if its is there, we delegate to the scope deployment
// to do the real work
return getDeployment(wsddService).getServiceInternal(serviceName);
}
return null;
}
/* (non-Javadoc)
* the only place were ive seen accesses to that ugly function was in
* the client code when parsing replies to a non-configured service in order
* to get operationdescs. Seems like this will not break anything ...
* @see org.jboss.axis.EngineConfiguration#getServiceByNamespaceURI(java.lang.String)
*/
public SOAPService getServiceByNamespaceURI(String arg0)
throws ConfigurationException
{
return null;
}
/* (non-Javadoc)
* when we deploy to a registry, we only want our services to be seen,
* but do not want our typemappings there
* @see org.jboss.axis.deployment.wsdd.WSDDDeployment#deployToRegistry(org.jboss.axis.deployment.wsdd.WSDDDeployment)
*/
public void deployToRegistry(WSDDDeployment arg0)
throws ConfigurationException
{
// do the usual deployment stuff (remember that super.typeMappings
// will still be empty at this point).
super.deployToRegistry(arg0);
// pretend the same engine
configureEngine(arg0.getEngine());
// we delegate to the registries type mapping registry (and get
// our local typemappings installed here before)
getTypeMappingRegistry().delegate(arg0.getTypeMappingRegistry());
}
/* (non-Javadoc)
* @see org.jboss.axis.EngineConfiguration#getTypeMappingRegistry()
*/
public TypeMappingRegistry getTypeMappingRegistry()
throws ConfigurationException
{
// if we need to create the tmr for the first time
if (!tmrCreated)
{
tmrCreated = true;
// we need to get all our typemappings known by our superclass
// because we want to hide them from the global registry
for (Iterator allTms = typeMappings.iterator(); allTms.hasNext();)
{
TypeMapping nextMapping = (TypeMapping)allTms.next();
installTypeMappingWithOptions(nextMapping);
}
tmrCreated = true;
}
// do the super call in each case
return super.getTypeMappingRegistry();
}
/**
* this helper serves to install typemappings with additional options
*/
protected void installTypeMappingWithOptions(TypeMapping nextMapping) throws ConfigurationException
{
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(getDeploymentLoader());
try
{
// first make sure that the mapping is installed correctly
super.deployTypeMapping(nextMapping);
// then access the factories in order to put the info there
org.jboss.axis.encoding.TypeMapping axisMapping =
(org.jboss.axis.encoding.TypeMapping)getTypeMappingRegistry()
.getTypeMapping(nextMapping.getEncodingStyle());
DeserializerFactory dser =
axisMapping.getDeserializer(nextMapping.getQName());
if (dser instanceof ParameterizableDeserializerFactory)
{
// Load up our params
((ParameterizableDeserializerFactory)dser).setOptions(((TypeMapping)nextMapping).getParametersTable());
}
}
finally
{
Thread.currentThread().setContextClassLoader(oldLoader);
}
}
}| Deployment.java |