/**
 * Copyright (c) 2008-2012 EBM WebSourcing, 2012-2013 Linagora
 * 
 * This program/library 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 program/library 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 program/library; If not, see <http://www.gnu.org/licenses/>
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.se.jsr181;

import java.io.File;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jbi.JBIException;
import javax.jbi.servicedesc.ServiceEndpoint;

import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.ow2.petals.component.framework.se.AbstractServiceEngine;
import org.ow2.petals.component.framework.su.AbstractServiceUnitManager;
import org.ow2.petals.se.jsr181.axis.Axis2Deployer;
import org.ow2.petals.se.jsr181.model.JaxConfigurationHandler;
import org.w3c.dom.Document;

/**
 * The JSR-181 service engine.
 * 
 * @author Christophe HAMERLING - EBM WebSourcing
 * @author Vincent Zurczak - EBM WebSourcing
 */
public class Jsr181Se extends AbstractServiceEngine {

	/**
	 * The Axis2 configuration context.
	 */
	private ConfigurationContext axisContext;

	/**
	 * The component implementation deployer.
	 */
	private Axis2Deployer deployer;

	/**
	 * This map is used to get the JAX configuration handler associated with an end-point name.
	 * <p>This map is used every time the component receives a message.</p>
	 */
	private final ConcurrentHashMap<String,JaxConfigurationHandler> endpointNameToJaxHandler =
		new ConcurrentHashMap<String,JaxConfigurationHandler> ();



	/**
	 * Creates a new instance of {@link Jsr181Se}.
	 */
	public Jsr181Se() {
		// nothing
	}

	/*
	 * (non-Javadoc)
	 * @see org.ow2.petals.component.framework.AbstractComponent#doInit()
	 */
	@Override
	protected void doInit() throws JBIException {

		// The axis2.xml is required
		final File axis2File = new File(
				this.getContext().getInstallRoot(),
				Jsr181Bootstrap.CONFIGURATION_FILE );

		if( ! axis2File.exists())
			throw new JBIException( "Can not get the Axis2 configuration file from component context" );


		// Get the Axis configuration context
		Logger log = getLogger();
		if( log.isLoggable( Level.FINE ))
			this.getLogger().fine( "Creating the Axis configuration context..." );

		try {
			this.axisContext =
				ConfigurationContextFactory.createConfigurationContextFromFileSystem( axis2File.getAbsolutePath());

			if( log.isLoggable( Level.FINE ))
				this.getLogger().fine( "The Axis configuration context was created." );

		} catch( final AxisFault e ) {

			String msg = "Cannot initialize the JSR181 SE";
			if( log.isLoggable( Level.FINE ))
				this.getLogger().fine( msg );

			throw new JBIException( msg, e );
		}


		// Create the Axis2 deployer
		this.deployer = new Axis2Deployer( this );
	}


	/**
	 * Gets the WSDL definition from the SU.
	 * <p>
	 * At first glance, it seems obvious this component should generate the WSDL on deployment.<br />
	 * The problem is that Petals has redundant declarations: interfaces, services and end-points are
	 * declared in both the WSDL and in the jbi.xml. With JAX-WS, there are also defined in the class.
	 * </p>
	 * <p>
	 * Changing the WSDL means changing the jbi.xml. Same thing if we generate the WSDL at deployment time.
	 * <br />Taking this way implies the component should also generate the jbi.xml.
	 * <br />It means the WSDL and jbi.xml generation should be done in
	 * {@link Jsr181SuManager#doDeploy(String, String, org.ow2.petals.component.framework.jbidescriptor.generated.Jbi)}.
	 * </p>
	 * 
	 * <p>
	 * FIXME: Maybe we should consider that other artifacts (than SU) could be deployed on this component.<br />
	 * SU would have to contain everything.<br />
	 * And WAR could be used to generate a SU on the fly.
	 * </p>
	 * 
	 * (non-Javadoc)
	 * @see org.ow2.petals.component.framework.AbstractComponent
	 * #getServiceDescription(javax.jbi.servicedesc.ServiceEndpoint)
	 */
	@Override
	public Document getServiceDescription( ServiceEndpoint endpoint ) {
		return super.getServiceDescription( endpoint );
	}


	/**
	 * @return the Axis context managed by the component instance
	 */
	public ConfigurationContext getAxisContext() {
		return this.axisContext;
	}


	/**
	 * @return the Axis2 deployer managed by the component instance
	 */
	public Axis2Deployer getAxis2Deployer() {
		return this.deployer;
	}


	/*
	 * (non-Javadoc)
	 * @see org.ow2.petals.component.framework.se.AbstractServiceEngine
	 * #createServiceUnitManager()
	 */
	@Override
	public AbstractServiceUnitManager createServiceUnitManager() {
		return new Jsr181SuManager(this);
	}


	/**
	 * @param endpointName the end-point name
	 * @return the associated JAX configuration handler
	 * @see java.util.concurrent.ConcurrentHashMap#get(java.lang.Object)
	 */
	public JaxConfigurationHandler getJaxConfigurationHandler( String endpointName ) {
		return this.endpointNameToJaxHandler.get( endpointName );
	}


	/**
	 * @param endpointName the end-point name
	 * @param jaxConfigurationHandler the JAX configuration handler to register
	 * @return the JAX configuration handler that was registered for this end-point name
	 * @see java.util.concurrent.ConcurrentHashMap#put(java.lang.Object, java.lang.Object)
	 */
	public JaxConfigurationHandler registerJaxConfigurationHandler(
			String endpointName,
			JaxConfigurationHandler jaxConfigurationHandler ) {

		return this.endpointNameToJaxHandler.put( endpointName, jaxConfigurationHandler );
	}


	/**
	 * @param endpointName the end-point name
	 * @return the JAX configuration handler that was registered for this end-point name
	 * @see java.util.concurrent.ConcurrentHashMap#remove(java.lang.Object)
	 */
	public JaxConfigurationHandler removeJaxConfigurationHandler( String endpointName ) {
		return this.endpointNameToJaxHandler.remove( endpointName );
	}
}
