/**
 * 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
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.lib.ejb21;

import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;

import javax.ejb.EJBException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;

import org.ow2.jonas.deployment.ejb.MethodDesc;
import org.ow2.jonas.deployment.ejb.SessionStatelessDesc;
import org.ow2.jonas.lib.util.Log;



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

/**
 * This class is a factory for JServiceEndpoint objects.
 * @author Philippe Durieux
 */
public abstract class JServiceEndpointHome {

    /**
     * Logger, used also in the generated part.
     */
    protected static Logger logger = Log.getLogger("org.ow2.jonas.lib.ejb21.endpoint");
    protected static Logger lognaming = Log.getLogger(Log.JONAS_NAMING_PREFIX);

    protected SessionStatelessDesc dd;

    protected JFactory bf;

    // The static table of all JServiceEndpointHome objects
    protected static Map sehomeList = new HashMap();

    /**
     * constructor
     * @param dd The Session Deployment Decriptor
     * @param bf The Session Factory
     */
    public JServiceEndpointHome(SessionStatelessDesc dd, JStatelessFactory bf) {
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "");
        }
        this.dd = dd;
        this.bf = bf;
    }

    /**
     * register this bean to JNDI (rebind) We register actually a Reference
     * object.
     */
    protected void register() throws NamingException {
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "");
        }
        String name = dd.getJndiServiceEndpointName();

        // Keep it in the static list for later retrieving.
        sehomeList.put(name, this);

        Reference ref = new Reference("org.ow2.jonas.lib.ejb21.JServiceEndpointHome",
                "org.ow2.jonas.lib.ejb21.HomeFactory", null);
        ref.add(new StringRefAddr("bean.name", name));
        bf.getInitialContext().rebind(name, ref);
    }

    /**
     * unregister this bean in JNDI (unbind)
     */
    protected void unregister() throws NamingException {
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "");
        }
        String name = dd.getJndiServiceEndpointName();
        // unregister in default InitialContext
        bf.getInitialContext().unbind(name);
        // remove from the static list
        sehomeList.remove(name);
    }

    /**
     * Get JServiceEndpointHome by its name
     * used by HomeFactory to retrieve object from its reference.
     * @param beanName The Bean JNDI local Name
     * @return The Bean ServiceEndpointHome
     */
    public static JServiceEndpointHome getSEHome(String beanName) {
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "");
        }
        JServiceEndpointHome seh = (JServiceEndpointHome) sehomeList.get(beanName);
        return seh;
    }

    /**
     * unique create method
     */
    public JServiceEndpoint create() throws RemoteException {
        if (TraceEjb.isDebugIc()) {
            TraceEjb.interp.log(BasicLevel.DEBUG, "");
        }
        RequestCtx rctx = bf.preInvoke(MethodDesc.TX_NOT_SET);
        bf.checkSecurity(null);
        JStatelessSwitch bs = null;
        try {
            bs = (JStatelessSwitch) ((JStatelessFactory) bf).createEJB();
        } catch (javax.ejb.AccessLocalException e) {
            throw new EJBException("Security Exception thrown by an enterprise Bean", e);
        } catch (EJBException e) {
            rctx.sysExc = e;
            throw e;
        } catch (RuntimeException e) {
            rctx.sysExc = e;
            throw new EJBException("RuntimeException thrown by an enterprise Bean", e);
        } catch (Error e) {
            rctx.sysExc = e;
            throw new EJBException("Error thrown by an enterprise Bean" + e);
        } catch (RemoteException e) {
            rctx.sysExc = e;
            throw new EJBException("Remote Exception raised:", e);
        } finally {
            bf.postInvoke(rctx);
        }
        return bs.getServiceEndpoint();
    }

    /**
     * Set the bean environment in current context
     * @return previous Context
     */
    public Context setCompCtx() {
        if (lognaming.isLoggable(BasicLevel.DEBUG)) {
            lognaming.log(BasicLevel.DEBUG, "");
        }
        return bf.setComponentContext();
    }

    /**
     * Restore old value
     * @return previous Context
     */
    public void resetCompCtx(Context ctx) {
        if (lognaming.isLoggable(BasicLevel.DEBUG)) {
            lognaming.log(BasicLevel.DEBUG, "reset ctx:" + ctx);
        }
        bf.resetComponentContext(ctx);
    }

    /**
     * @return A JServiceEndpoint that can be used by the JonasEJBProvider
     */
    public abstract JServiceEndpoint createServiceEndpointObject() throws RemoteException;

    public JStatelessFactory getBeanFactory() {
        return (JStatelessFactory) bf;
    }
}

