/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2004 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
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.ws.axis;

import java.lang.reflect.Method;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.ow2.jonas.lib.ejb21.JServiceEndpoint;
import org.ow2.jonas.lib.ejb21.JServiceEndpointHome;
import org.ow2.jonas.lib.util.Log;
import org.ow2.jonas.security.ws.SecurityContextHelper;

import org.apache.axis.AxisFault;
import org.apache.axis.Handler;
import org.apache.axis.MessageContext;
import org.apache.axis.i18n.Messages;
import org.apache.axis.providers.java.RPCProvider;



import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
 * Expose the service-endpoint interface of the Ejb.
 *
 * @author Guillaume Sauthier
 */
public class JOnASEJBProvider extends RPCProvider {

    /**
     * Serial Version UID.
     */
    private static final long serialVersionUID = -3754705462547648319L;

    /**
     * Logger
     */
    private static Logger logger = null;

    /**
     * parameter service-endpoint class name
     */
    public static final String OPTION_SEINTERFACENAME = "serviceEndpointInterfaceName";

    /**
     * parameter service-endpoint JNDI name
     */
    public static final String OPTION_SEJNDINAME = "serviceEndpointJndiName";

    /**
     * cached initial context
     */
    private static InitialContext cachedContext;

    /**
     * Create a new JOnASEJBProvider
     */
    public JOnASEJBProvider() {
        super();
        logger = Log.getLogger("org.ow2.jonas.lib.ejb21.endpoint");
        logger.log(BasicLevel.DEBUG, "");
    }

    /**
     * Override the default implementation
     * Return a object which implements the service.
     * @param msgContext the message context
     * @param seiName The Service Endpoint Interface classname
     * @return an object that implements the service
     * @throws Exception when trying to create a Serviceobject without serviceendpoint name aprameter
     */
    protected Object makeNewServiceObject(MessageContext msgContext, String seiName) throws Exception {
        logger.log(BasicLevel.DEBUG, seiName);
        if (seiName == null) {
            logger.log(BasicLevel.ERROR, "Service Endpoint Interface classname is null");
            // cannot find service-endpoint
            throw new AxisFault(Messages.getMessage("noOption00", OPTION_SEINTERFACENAME, msgContext.getService()
                    .getName()));
        }

        // Get ServiceEndpointHome in JNDI
        String jndiName = getStrOption(OPTION_SEJNDINAME, msgContext.getService());
        if (jndiName == null) {
            logger.log(BasicLevel.ERROR, "Service Endpoint JNDI name is null");
            throw new AxisFault("Missing parameter in service : " + OPTION_SEJNDINAME);
        }
        JServiceEndpointHome sehome = null;
        try {
            InitialContext ic = getCachedContext();
            sehome = (JServiceEndpointHome) ic.lookup(jndiName);
        } catch (NamingException ne) {
            logger.log(BasicLevel.ERROR, "Cannot lookup ServiceEndpointHome");
            throw new AxisFault("Cannot lookup ServiceEndpointHome: " + jndiName);
        }
        // Check that the object implements the SEI
        // TODO

        // Create a new ServiceEndpoint object
        JServiceEndpoint se = sehome.create();

        // Set the MessageContext that can be retrived by the bean
        se.setMessageContext(msgContext);
        return se;
    }

    /**
     * Override the default implementation : create a SecurityContext from username and password
     * @throws Exception if method invokation fail or produce an Exception
     */
    protected Object invokeMethod(MessageContext msgContext, Method method, Object obj, Object[] argValues)
            throws Exception {
        logger.log(BasicLevel.DEBUG, "");
        String username = msgContext.getUsername();
        if (username != null) {
            // Do not forget to initialize the security context
            SecurityContextHelper.getInstance().login(username, msgContext.getPassword());
        }
        return super.invokeMethod(msgContext, method, obj, argValues);
    }

    /**
     * Override the default implementation
     * @return Return the option in the configuration that contains the service
     *         class name. In the EJB case, it is the JNDI name of the bean.
     */
    protected String getServiceClassNameOptionName() {
        logger.log(BasicLevel.DEBUG, "");
        return OPTION_SEINTERFACENAME;
    }

    /**
     * Get a String option by looking first in the service options, and then at
     * the Handler's options. This allows defaults to be specified at the
     * provider level, and then overriden for particular services.
     *
     * @param optionName the option to retrieve
     * @param service Option holder
     *
     * @return String the value of the option or null if not found in either
     *         scope
     */
    private String getStrOption(String optionName, Handler service) {
        String value = null;
        if (service != null) {
            value = (String) service.getOption(optionName);
        }
        if (value == null) {
            value = (String) getOption(optionName);
        }
        return value;
    }

    /**
     * @return Returns the cached InitialContext (or created a new one)
     * @throws javax.naming.NamingException when InitialContext creation fails
     */
    private InitialContext getCachedContext() throws javax.naming.NamingException {
        if (cachedContext == null) {
            cachedContext = new InitialContext();
        }
        return cachedContext;
    }

}