/*
 * Copyright 2010 Red Hat, Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.jboss.soa.dsp.example;

import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.UUID;
import java.util.logging.Level;

import javax.xml.namespace.QName;

import org.jboss.soa.dsp.EndpointMetaData;
import org.jboss.soa.dsp.ServiceEndpointReference;
import org.jboss.soa.dsp.deployer.ServiceDeployer;
import org.jboss.soa.dsp.example.provider.ExampleWebServiceFactory;
import org.jboss.soa.dsp.server.ServerConfig;
import org.jboss.soa.dsp.ws.BaseWebServiceEndpoint;
import org.jboss.soa.dsp.ws.DeploymentBuilder;
import org.jboss.soa.dsp.ws.WSDLParser;
import org.jboss.soa.dsp.ws.WSDLReference;
import org.jboss.soa.dsp.ws.WebServiceProviderGenerator;

public class WSDeployer {

	private static java.util.logging.Logger _log=java.util.logging.Logger.getLogger(WSDeployer.class.getPackage().getName());
	
	private static final String DSP_SERVER_CONFIG_FACTORY = "dsp.server.config.factory";
	private static final String DSP_SERVICE_DEPLOYER = "dsp.service.deployer";

	public WSDeployer() {
	}
	
	/**
	 * Deploy the web service, using the artifacts contained within the supplied the root folder
	 * and based on the WSDL definition located in the supplied WSDL file.
	 * 
	 * @param root The root folder containing the artifacts to be included in the web service
	 * @param wsdlFile The WSDL definition upon which the web service interface will be based
	 * @return The service endpoint reference of the deployed web service
	 */
	public ServiceEndpointReference deploy(java.io.File root, java.io.File wsdlFile) throws Exception {
		ServiceEndpointReference ref=null;
		
		ClassLoader cl=WSDeployer.class.getClassLoader();
		
		javax.wsdl.factory.WSDLFactory factory=javax.wsdl.factory.WSDLFactory.newInstance();
		javax.wsdl.Definition wsdl=factory.newWSDLReader().readWSDL(null, wsdlFile.getAbsolutePath());
		
		WSDLReference wsdlRef=new WSDLReference(wsdl, wsdlFile.toURI());
		
		WebServiceProviderGenerator providerFactory = new WebServiceProviderGenerator();

		javax.wsdl.Service service=(javax.wsdl.Service)wsdl.getServices().values().iterator().next();
		
		_log.fine("SERVICE="+service);
		
		javax.wsdl.Port port=(javax.wsdl.Port)service.getPorts().values().iterator().next();
		
		_log.fine("PORT="+port);
		
		EndpointMetaData metaData=new EndpointMetaData(service.getQName(),
								port.getName(), new QName("http://www.example.org", "ProcessId"),
									UUID.randomUUID().toString());
		
		File warArchive = null;
		try {
			BaseWebServiceEndpoint providerImpl =
		          		providerFactory.createProvider(metaData, wsdlRef, cl,
		          				null, ExampleWebServiceFactory.class);
	
			_log.fine("Provider="+providerImpl);
	
			ServerConfig serverConfig=getServerConfig();
			
			ServiceDeployer deployer=getServiceDeployer();
			
			warArchive = new DeploymentBuilder(serverConfig)
						.setEndpoint(metaData.getEndpointId())
						.setWSDL(wsdlFile, root)
						.setProvider(providerImpl)
						.process(deployer.getBuildProcessor())
						.build();
				
			providerFactory.writeClass(warArchive);
				
			_log.fine("War Archive="+warArchive);
			
			URL serviceUrl = new WSDLParser(wsdlRef.getDefinition()).getServiceLocationURL(metaData.getServiceName(),
									metaData.getPortName());
	
			_log.fine("Service URL="+serviceUrl);
			
			ref = deployer.deploy(metaData, providerImpl.getClass(),
		    		  					serviceUrl, cl, warArchive, getServerConfig());

		} catch (Throwable t) {
			_log.log(Level.SEVERE, "Failed", t);
		}
		
		_log.fine("DEPLOYED endpoint ref="+ref);
		
		return(ref);
	}
	
	public void undeploy(ServiceEndpointReference ref) throws Exception {
		ServiceDeployer deployer=getServiceDeployer();
		
		deployer.undeploy(ref, getServerConfig());
	}
	
	protected ServerConfig getServerConfig() {
		ServerConfig ret=null;
		
		// Get service config factory class from properties file
		ResourceBundle res=ResourceBundle.getBundle("dsp");
		
		if (res != null) {
			String factory=res.getString(DSP_SERVER_CONFIG_FACTORY);
		
			if (factory != null) {
				try {
					Class<?> cls=Class.forName(factory);
					
					org.jboss.soa.dsp.server.ServerConfigFactory scf=
						(org.jboss.soa.dsp.server.ServerConfigFactory)cls.newInstance();
					
					ret = scf.getServerConfig();
					
				} catch(Exception e) {
					_log.log(Level.SEVERE, "Failed to get server config from factory '"+factory+"'", e);
				}
			} else {
				_log.severe("Failed to find server config factory property '"+DSP_SERVER_CONFIG_FACTORY+"'");
			}
		} else {
			_log.severe("Unable to find dsp.properties");
		}

		return(ret);
	}
	
	protected ServiceDeployer getServiceDeployer() {
		ServiceDeployer ret=null;
		
		// Get service config factory class from properties file
		ResourceBundle res=ResourceBundle.getBundle("dsp");
		
		if (res != null) {
			String deployer=res.getString(DSP_SERVICE_DEPLOYER);
		
			if (deployer != null) {
				try {
					Class<?> cls=Class.forName(deployer);
					
					ret = (ServiceDeployer)cls.newInstance();
					
				} catch(Exception e) {
					_log.log(Level.SEVERE, "Failed to get service deployer '"+deployer+"'", e);
				}
			} else {
				_log.severe("Failed to find service deployer property '"+DSP_SERVICE_DEPLOYER+"'");
			}
		} else {
			_log.severe("Unable to find dsp.properties");
		}

		return(ret);
	}
}
