/*
 * $RCSfile: ProviderEndPoint.java,v $
 * $Date: 2006/01/26 14:48:59 $
 * $Revision: 1.1.2.2 $
 * $Author: andreys $
 */

/*
 * Copyright (c) 2002-2003 IST-2004-2006-511731 ModelWare - ModelBus.
 * All rights reserved.
 *
 * This software is published under the terms of the ModelBus Software License
 * 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.
 * A copy of ModelBus Software License is provided with this distribution in
 * doc/LICENSE.txt file.
 */

/*
 * ProviderEndPoint.java  
 * 
 * @author Andrey Sadovykh (LIP6)
 * @version $Revision: 1.1.2.2 $ $Date: 2006/01/26 14:48:59 $
 */
package org.eclipse.mddi.modelbus.adapter.infrastructure.transport.server.ws;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.xml.soap.SOAPEnvelope;

import org.apache.log4j.Logger;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.DescriptionUtil;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.server.AbstractServer;
import org.eclipse.mddi.modelbus.adapter.user.AdapterStub;
import org.eclipse.mddi.modelbus.description.concrete.ConcretePackage;
import org.eclipse.mddi.modelbus.description.concrete.Property;
import org.eclipse.mddi.modelbus.description.concrete.Tool;

public class ProviderEndPoint implements EndPoint {

    /**
     * The relative part that belongs to this EndPoint begins with
     * "modeling_services"
     */
    public static final String DEF_REL_PATH = "modeling_services";

    private static Logger logger = Logger.getLogger(ProviderEndPoint.class);

    /**
     * a map that is used for holding the references of the deployed Adapters
     * Each Adapter is associated with a Web Services address (URL). This
     * address allows the Modeling Services provided by the Adapter to be
     * invoked remotely. So, the map contains pairs of addresses and Adapter
     * objects The 'key' element is the address (String URL). The 'value'
     * element is the Adapter object (instance of AdapterStub).
     * 
     */
    Map relativePath2AdapterMap = new HashMap();

    /**
     * Searches for the Adapter that provides a specified Modeling Service on
     * this server.
     * 
     * @param relativePath
     *            a URI identifying a Modeling Service in this server.
     * @return Adapter object
     */
    public AdapterStub getAdapterOfProviderTool(String relativePath) {
        // logger.debug("Searching for the adapter for :"+relativePath);
        // logger.debug("Get adapter list size="
        // +relativePath2AdapterMap.size());
        AdapterStub ad = (AdapterStub) relativePath2AdapterMap
                .get(relativePath);
        // logger.debug("Found adapter :"+ad);
        return ad;
    }

    /**
     * 
     * manage this adapter so that it can receives service invocation.
     * 
     * @param adapter
     * @throws Exception
     * 
     * 
     */
    public void manageAdapter(AdapterStub adapter) throws Exception {

        setUrlProperty(adapter);

        Tool toolDescription = adapter.getToolDescription();
        if (toolDescription == null) {
            logger.warn("Adapter: No tool description found.");
            return;
        }

        EndPointManagerImpl.getInstance().putEndPoint(
                ProviderEndPoint.DEF_REL_PATH, this);
        relativePath2AdapterMap.put(getRelativePath(toolDescription), adapter);
    }

    /**
     * 
     * check the tool description contains the property URL If not, creates this
     * property and it put in tool description <br>
     * 
     * @param adapter
     * 
     * @throws Exception
     */
    private void setUrlProperty(AdapterStub adapter) throws Exception {
        Tool toolDescription = adapter.getToolDescription();

        Property pro = DescriptionUtil
                .getPropertyObject(toolDescription, "URL");
        // if the Property does not exist in tool description
        // Then create it and add to the description
        if (pro == null) {
            pro = ConcretePackage.eINSTANCE.getConcreteFactory()
                    .createProperty();
            toolDescription.getProperty().add(pro);
        }
        int port = ServerManager.getModelBusPort(adapter);

        AbstractServer s = ServerManager.getInstance().getServer(port);

        pro.setName("URL");
        pro.setValue("http://" + ServerManager.getHost() + ":" + port + "/"
                + s.getContext() + "/" + getRelativePath(toolDescription));
        logger.debug("Assigne URL " + pro.getValue());

    }

    public static String getRelativePath(Tool tool) {
        String path;

        path = ProviderEndPoint.DEF_REL_PATH + "/" + tool.getName();

        return path;
    }

    public static String getRelativePath(String toolName) {
        String path;

        path = ProviderEndPoint.DEF_REL_PATH + "/" + toolName;

        return path;
    }
    
    public Collection getAdapters() {
        return relativePath2AdapterMap.values();
    }


    public void removeAdapter(AdapterStub adapter) {
        relativePath2AdapterMap.values().remove(adapter);
    }

    public void execute(String relativePath, SOAPEnvelope req, SOAPEnvelope resp)
            throws javax.xml.soap.SOAPException {
        // String
        // serviceName=AxisEngine.getCurrentMessageContext().getTargetService();
        // String uri="/axis/services/"+serviceName;

        // logger.debug("relativePath: "+relativePath);

        AdapterStub a = getAdapterOfProviderTool(relativePath);

        if (a != null) {
            logger.debug(relativePath + " -> " + a);
            // TODO return SessionReceiver for Session Enabled Providers
            a.getTransportManager().getWsInvocationReceiver()
                    .process(req, resp);
        } else {
            logger.error("No Tool bound to the URI " + relativePath);
            logger.debug("Map has the following entries:");
            for (Iterator it = relativePath2AdapterMap.keySet().iterator(); it
                    .hasNext();) {
                logger.debug(it.next());
            }
            DefaultWsInvocationReceiver.createSoapFault(resp,
                    "No Tool bound to the URI " + relativePath);
        }

    }

}
