/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@ow2.org
 *
 * This 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 any later version.
 *
 * This 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial Developer : Delplanque Xavier & Sauthier Guillaume
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.deployment.ws;

import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.xml.namespace.QName;

import org.ow2.jonas.deployment.common.DeploymentDescException;
import org.ow2.jonas.deployment.common.HandlerDesc;
import org.ow2.jonas.deployment.common.xml.Handler;
import org.ow2.jonas.deployment.ws.xml.JonasPortComponent;
import org.ow2.jonas.deployment.ws.xml.PortComponent;
import org.ow2.jonas.lib.util.I18n;






/**
 * This class provides methodes to manipulate portComponent's attributes.
 *
 * @author Guillaume Sauthier
 * @author Xavier Delplanque
 */

public abstract class PortComponentDesc {

    /**
     * Internationalization
     */
    private static I18n i18n = I18n.getInstance(PortComponentDesc.class);

    /**
     * The name of the Port (must be unique)
     */
    private String name;

    /**
     * The interface of the endpoint/port
     */
    private Class sei;

    /**
     * the sib link, can be ejb or servlet link
     */
    private String sibLink;

    /**
     * The classname of bean implementing the service
     */
    private String sib;

    /**
     * The list of Handlers the Port will run
     */
    private List handlers = new Vector();

    /**
     * The QName of the WSDL port
     */
    private QName portQName;

    /**
     * The URL where to access the port-component (null before resolving)
     */
    private URL endpoint = null;

    /**
     * parent container service
     */
    private ServiceDesc parent = null;

    /**
     * User specified endpoint URI
     */
    private String endpointURI = null;

    /**
     * url-pattern computed from endpoint-uri
     */
    private String mapping = null;

    /**
     * service name computed from endpoint-uri
     */
    private String serviceName = null;

    /**
     * Creates a new PortComponentDesc object.
     *
     * @param jarCL the module (ejbjar or war) classloader.
     * @param pc webservices port-component element
     * @param jpc webservices jonas-port-component element
     * @param parent ServiceDesc containing the PortComponent
     *
     * @throws WSDeploymentDescException When construction fails.
     */
    protected PortComponentDesc(ClassLoader jarCL,
                                PortComponent pc,
                                JonasPortComponent jpc,
                                ServiceDesc parent)
        throws WSDeploymentDescException {

        this.parent = parent;

        // set name
        name = pc.getPortComponentName();
        if ("".equals(name)) { //$NON-NLS-1$
            String err = getI18n().getMessage("PortComponentDesc.noPCName"); //$NON-NLS-1$
            throw new WSDeploymentDescException(err);
        }

        // set sei
        String seiClassName = pc.getServiceEndpointInterface();
        if ("".equals(seiClassName)) { //$NON-NLS-1$
            String err = getI18n().getMessage("PortComponentDesc.noInterfaceName"); //$NON-NLS-1$
            throw new WSDeploymentDescException(err);
        }

        try {
            sei = jarCL.loadClass(seiClassName);
        } catch (ClassNotFoundException e) {
            String err = getI18n().getMessage("PortComponentDesc.loadError", seiClassName); //$NON-NLS-1$
            throw new WSDeploymentDescException(err, e);
        }

        // set and init handlers
        List hl = pc.getHandlerList();
        Handler h = null;

        for (int i = 0; i < hl.size(); i++) {
            // for each reference, build and add a HandlerDesc Object
            if (hl.get(i) != null) {
                // get the standard dd handler
                h = (Handler) hl.get(i);
                // build and add a new handler
                try {
                    handlers.add(new HandlerDesc(jarCL, h));
                } catch (DeploymentDescException dde) {
                    throw new WSDeploymentDescException(dde);
                }
            }
        }

        // set portQName
        portQName = pc.getWsdlPort().getQName();

        // we have jonas specific infos
        if (jpc != null) {
            // endpoint URI
            endpointURI = jpc.getEndpointURI();
            if (endpointURI != null) {

                // uri doesn't start with '/'
                if (!endpointURI.startsWith("/")) {
                    // create service-name
                    serviceName = endpointURI;
                    endpointURI += "/" + endpointURI;
                } else {
                    // remove the first / for the service name
                    serviceName = endpointURI.substring(1);
                }

                // serviceName shouldn't be empty
                if ("".equals(serviceName)) {
                    String err = getI18n().getMessage("PortComponentDesc.invalidEndpointURI", this.name); //$NON-NLS-1$
                    throw new WSDeploymentDescException(err);
                }

            }
        } else {
            // TODO Check this
            serviceName = portQName.getLocalPart();
        }


    }

    /**
     * Return the parent ServiceDesc of the PortComponent.
     *
     * @return the parent ServiceDesc of the PortComponent.
     */
    public ServiceDesc getServiceDesc() {
        return parent;
    }

    /**
     * Return the name of the PortComponent.
     *
     * @return the name of the PortComponent.
     */
    public String getName() {
        return name;
    }

    /**
     * Return the Service Endpoint Interface name.
     *
     * @return the Service Endpoint Interface name.
     */
    public Class getServiceEndpointInterface() {
        return sei;
    }

    /**
     * Return the implementation bean. It's the bean classname
     * which do the real work.
     *
     * @return the implementation bean classname.
     */
    public String getSIBClassname() {
        return sib;
    }

    /**
     * Set the sib class name.
     *
     * @param sibClassName the sib class name.
     *
     * @deprecated sib class set with the setSessionStatelessDesc
     *             or setWebDesc methods.
     */
    protected void setSIBClassname(String sibClassName) {
        this.sib = sibClassName;
    }

    /**
     * Return the WSDL's Port QName, the PortComponent is asssociated with.
     *
     * @return the port's QName
     */
    public QName getQName() {
        return portQName;
    }

    /**
     * Return the list of Handlers the PortComponent is associated with.
     *
     * @return the list of Handlers the PortComponent is associated with.
     */
    public List getHandlers() {
        return handlers;
    }

    /**
     * Return the service-impl-bean value. the sib can be an ejb or a servlet.
     *
     * @return the sib name.
     */
    public String getSibLink() {
        return sibLink;
    }

    /**
     * Return true if the Service Impl Bean is an EJB.
     *
     * @return true if the Service Impl Bean is an EJB.
     */
    public abstract boolean hasBeanImpl();

    /**
     * Return true if the Service Impl Bean is a JaxRpc component.
     *
     * @return true if the Service Impl Bean is a JaxRpc component.
     */
    public abstract boolean hasJaxRpcImpl();

    /**
     * Return the URL where the port-component can be accessed.
     *
     * @return the URL where the port-component can be accessed.
     */
    public URL getEndpointURL() {
        return endpoint;
    }

    /**
     * Set the Endpoint URL of the port-component.
     *
     * @param url the resolved endpoint URL.
     */
    public void setEndpointURL(URL url) {
        endpoint = url;
    }

    /**
     * @return Returns the mapping.
     */
    public String getMapping() {
        return mapping;
    }

    /**
     * @return Returns the serviceName.
     */
    public String getServiceName() {
        return serviceName;
    }

    /**
     * Setter method for J2EE component linking.
     * @param desc the descriptor of the component implementing the endpoint.
     * @throws WSDeploymentDescException when desc is an unknown type.
     */
    public abstract void setDesc(Object desc) throws WSDeploymentDescException;

    /**
     * @return Returns a String representation of the PortComponent
     */
    public String toString() {

        StringBuffer sb = new StringBuffer();

        sb.append("\n" + getClass().getName()); //$NON-NLS-1$
        sb.append("\ngetName()=" + getName()); //$NON-NLS-1$
        sb.append("\ngetServiceEndpointInterface()=" + getServiceEndpointInterface()); //$NON-NLS-1$
        sb.append("\ngetSibLink()=" + getSibLink()); //$NON-NLS-1$
        sb.append("\ngetSIBClassname()=" + getSIBClassname()); //$NON-NLS-1$
        sb.append("\ngetQName()=" + getQName()); //$NON-NLS-1$

        for (Iterator i = getHandlers().iterator(); i.hasNext();) {
            sb.append("\ngetHandlers()=" + ((Handler) i.next()).toString()); //$NON-NLS-1$
        }

        return sb.toString();

    }

    /**
     * @return Returns the sib.
     */
    public String getSib() {
        return sib;
    }

    /**
     * @param sib The sib to set.
     */
    public void setSib(String sib) {
        this.sib = sib;
    }

    /**
     * @param sibLink The sibLink to set.
     */
    public void setSibLink(String sibLink) {
        this.sibLink = sibLink;
    }

    /**
     * @return Returns the i18n.
     */
    public static I18n getI18n() {
        return i18n;
    }

    /**
     * @return Returns the endpointURI.
     */
    public String getEndpointURI() {
        return endpointURI;
    }
}
