/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
 
// $Id: Deployment.java,v 1.4.2.3 2003/11/06 15:36:04 cgjung Exp $

package org.jboss.net.axis;

// axis config and utils
import org.apache.axis.deployment.wsdd.WSDDConstants;
import org.apache.axis.deployment.wsdd.WSDDDeployment;
import org.apache.axis.deployment.wsdd.WSDDNonFatalException;
import org.apache.axis.deployment.wsdd.WSDDProvider;
import org.apache.axis.deployment.wsdd.WSDDService;
import org.apache.axis.deployment.wsdd.WSDDException;
import org.apache.axis.deployment.wsdd.WSDDTypeMapping;
import org.apache.axis.ConfigurationException;
import org.apache.axis.encoding.TypeMappingRegistry;
import org.apache.axis.handlers.soap.SOAPService;

import javax.xml.rpc.encoding.DeserializerFactory;
import org.w3c.dom.Element;

// JAXP
import javax.xml.namespace.QName;

// java utils
import java.util.List;
import java.util.Map;
import java.util.Iterator;
import org.jboss.logging.Logger;

/**
 * Represents a wsdd deployment descriptor/registry with
 * special service-specific classloading features.
 * @author <a href="mailto:Christoph.Jung@infor.de">Christoph G. Jung</a>
 * @since 09.03.2002
 * @version $Revision: 1.4.2.3 $
 */

public class Deployment extends WSDDDeployment {

   //
   // Attributes
   //

   /** for deploymentlogging purposes */
   protected static final Logger log = Logger.getLogger(Deployment.class);

   /**
    * holds a map of service q-names to classloaders
    * this map must be initialised lazily, since accesses are already done
    * in the super-constructor! Newbies!
    */
   protected Map service2ClassLoader;

   /** whether the type mapping has been registered */
   protected boolean tmrCreated = false;
   
   static {
      WSDDProvider.registerProvider(
         WSDDConstants.QNAME_HANDLER_PROVIDER,
         new ServiceClassLoaderAwareWSDDHandlerProvider());
   }
   
   //
   // Constructors
   // 
   
   /**
    * Constructor for Deployment.
    * @param e root element of the deployment document
    * @throws WSDDException
    */
   public Deployment(Element e) throws WSDDException {
      super(e);
      Element[] elements = getChildElements(e, "typeMapping");
      for (int i = 0; i < elements.length; i++) {
         TypeMapping mapping = new TypeMapping(elements[i]);
         deployTypeMapping(mapping);
      }
      // JBOSS only feature.  Here we have the ability to 
      // specify publish URLs to which we wish to register our
      // web services.  Here we processing those publish URLS      
      elements = getChildElements(e, "publish");
      for (int i = 0; i < elements.length; i++) {
         log.debug("processing publish URL");
         // Here we'll call the UDDI4J apis to accomplish this
         // First, figure out what the implications are for SSL
         // enabled comminucation and what provisions already 
         // exist for SSL in jboss..? <pjb 4/24/2002>
      }
   }
   
   //
   // protected helpers
   //
   
   /** lazily initialises the classloader map */
   protected synchronized Map getService2ClassLoader() {
      if (service2ClassLoader == null) {
         service2ClassLoader = new java.util.HashMap();
      }
      return service2ClassLoader;
   }
   
   /** installs the typemappings parameter table inside a deserializer */
   protected void equipTypeMappingWithOptions(TypeMapping typeMapping)
      throws ConfigurationException {
      DeserializerFactory dser =
         (
            (org.apache.axis.encoding.TypeMapping) getTypeMappingRegistry()
               .getTypeMapping(
               typeMapping.getEncodingStyle())).getDeserializer(
            typeMapping.getQName());
      if (dser instanceof ParameterizableDeserializerFactory) {
         // Load up our params
         ((ParameterizableDeserializerFactory) dser).setOptions(
            typeMapping.getParametersTable());
      }
   }

   //
   // Public API
   //

   /* (non-Javadoc)
	* @see org.apache.axis.deployment.wsdd.WSDDDeployment#deployService(org.apache.axis.deployment.wsdd.WSDDService)
    */
   public void deployService(WSDDService service) {
      service.deployToRegistry(this);
      getService2ClassLoader().put(
         service.getQName(),
         Thread.currentThread().getContextClassLoader());
   }

   /* (non-Javadoc)
	* @see org.apache.axis.deployment.wsdd.WSDDDeployment#registerNamespaceForService(java.lang.String, org.apache.axis.deployment.wsdd.WSDDService)
	*/
   public void registerNamespaceForService(String arg0, WSDDService arg1) {
	   super.registerNamespaceForService(arg0, arg1);
	   getService2ClassLoader().put(
		  arg0,
		  Thread.currentThread().getContextClassLoader());		
   }

   /** deploy the information inside a given target */
   public void deployToRegistry(WSDDDeployment target)
      throws ConfigurationException {
      super.deployToRegistry(target);
      if (target instanceof Deployment) {      	
         ((Deployment) target).getService2ClassLoader().putAll(getService2ClassLoader());
      }
   }

   /**
    * retrieve the classloader that loaded the given service
    */
   public ClassLoader getClassLoader(QName serviceName) {
      return (ClassLoader) getService2ClassLoader().get(serviceName);
   }

   /**
	* retrieve the classloader that loaded the given namespace
	*/
   public ClassLoader getClassLoader(String namespace) {
	  return (ClassLoader) getService2ClassLoader().get(namespace);
   }


   /* (non-Javadoc)
	* @see org.apache.axis.deployment.wsdd.WSDDDeployment#removeNamespaceMapping(java.lang.String)
	*/
   public void removeNamespaceMapping(String arg0) {
	   service2ClassLoader.remove(arg0);
	   super.removeNamespaceMapping(arg0);
   }

   /* (non-Javadoc)
	* @see org.apache.axis.deployment.wsdd.WSDDDeployment#undeployService(javax.xml.namespace.QName)
	*/
   public void undeployService(QName arg0) {
	   service2ClassLoader.remove(arg0);
	   super.undeployService(arg0);
   }

   /** overwrite to equip with options */
   public void deployTypeMapping(WSDDTypeMapping typeMapping)
      throws WSDDException {
      super.deployTypeMapping(typeMapping);
      if (typeMapping instanceof TypeMapping) {
         try {
            equipTypeMappingWithOptions((TypeMapping) typeMapping);
         } catch (ConfigurationException e) {
            throw new WSDDException(
               "Could not equip typemapping with options because of" + e);
         }
      }
   }

   /** overwrite to equip with options */
   public TypeMappingRegistry getTypeMappingRegistry()
      throws ConfigurationException {
      TypeMappingRegistry tmr = super.getTypeMappingRegistry();
      if (!tmrCreated) {
         tmrCreated = true;
         WSDDTypeMapping[] typeMappings = (WSDDTypeMapping[]) getTypeMappings();
         for (int count = 0; count < typeMappings.length; count++) {
            if (typeMappings[count] instanceof TypeMapping) {
               equipTypeMappingWithOptions((TypeMapping) typeMappings[count]);
            }
         }
      }
      return tmr;
   }
   	
   /* overrides the getdeployedservices method in order
    * to address classloading issues when browsing
    * the services list.
    * @see org.apache.axis.EngineConfiguration#getDeployedServices()
    */
   public Iterator getDeployedServices() throws ConfigurationException {
		List serviceDescs = new java.util.ArrayList();
		WSDDService[] services=getServices();
		ClassLoader old=Thread.currentThread().getContextClassLoader();
		try{
			for(int count=0;count<services.length;count++) {
			 	Thread.currentThread().setContextClassLoader(getClassLoader(services[count].getQName()));
			 	try {
				  services[count].makeNewInstance(this);
				  serviceDescs.add(services[count].getServiceDesc());
			 	} catch (WSDDNonFatalException ex) {
				  // If it's non-fatal, just keep on going
				  log.debug("Ingoring non-fatal exception: ", ex);
			 	}
			}
		} finally {
			Thread.currentThread().setContextClassLoader(old);
		}
		return serviceDescs.iterator();
   }

   /* (non-Javadoc)
	* move into the right classloader before obtaining an instance
	* @see org.apache.axis.EngineConfiguration#getServiceByNamespaceURI(java.lang.String)
	*/
   public SOAPService getServiceByNamespaceURI(String arg0)
	   throws ConfigurationException {
		   ClassLoader old=Thread.currentThread().getContextClassLoader();
		   try{
			   Thread.currentThread().setContextClassLoader(getClassLoader(arg0));		
			   return super.getServiceByNamespaceURI(arg0);
		   } finally {
			   Thread.currentThread().setContextClassLoader(old);
		   }
   }

   /* (non-Javadoc)
	* move into the right classloader before obtaining an instance
	* @see org.apache.axis.EngineConfiguration#getService(javax.xml.namespace.QName)
	*/
   public SOAPService getService(QName arg0) throws ConfigurationException {
	   ClassLoader old=Thread.currentThread().getContextClassLoader();
	   try{
		   Thread.currentThread().setContextClassLoader(getClassLoader(arg0));		
		   return super.getService(arg0);
	   } finally {
		   Thread.currentThread().setContextClassLoader(old);
	   }
   }
   
}
