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 |