/**
 * 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.io.Serializable;
import java.rmi.RemoteException;
import java.util.List;

import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import javax.ejb.RemoveException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.xml.rpc.handler.MessageContext;

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

/**
 * This class implements javax.ejb.SessionContext interface. it should be
 * implemented by JStatefulContext and JStatelessContext depending if the beans
 * is stateful or stateless.
 * @author Philippe Coq, Philippe Durieux
 */

public abstract class JSessionContext extends JContext implements SessionContext, Serializable {

    protected JSessionSwitch bs = null;

    protected boolean ismarkedremoved;

    /**
     * Constructs a SessionContext
     * @param bf The Session Factory
     * @param eb The Session bean instance
     */
    public JSessionContext(JSessionFactory bf, SessionBean eb) {
        super(bf, eb);
        if (TraceEjb.isDebugIc()) {
            TraceEjb.interp.log(BasicLevel.DEBUG, "");
        }
    }

    // ------------------------------------------------------------------
    // SessionContext implementation
    // ------------------------------------------------------------------

    /**
     * Obtains a reference to the EJB object that is currently associated with
     * the instance.
     * @return The EJB object currently associated with the instance.
     * @exception IllegalStateException Thrown if the instance invokes this
     *            method while the instance is in a state that does not allow
     *            the instance to invoke this method.
     */
    public EJBObject getEJBObject() throws IllegalStateException {
        if (TraceEjb.isDebugIc()) {
            TraceEjb.interp.log(BasicLevel.DEBUG, "");
        }
        if (ismarkedremoved || bs == null) {
            if (ismarkedremoved)
                TraceEjb.logger.log(BasicLevel.ERROR, "marked removed");
            else
                TraceEjb.logger.log(BasicLevel.ERROR, "no SessionSwitch");
            throw new IllegalStateException("getEJBObject: EJB is removed");
        }
        EJBObject ejbobject = bs.getRemote();
        if (ejbobject == null) {
            throw new IllegalStateException("No Remote Interface for this bean");
        }
        return ejbobject;
    }

    /**
     * Obtain a reference to the EJB local object that is currently associated
     * with the instance.
     * @return The EJB local object currently associated with the instance.
     * @throws java.lang.IllegalStateException - if the instance invokes this
     *         method while the instance is in a state that does not allow the
     *         instance to invoke this method, or if the instance does not have
     *         a local interface.
     */
    public EJBLocalObject getEJBLocalObject() throws IllegalStateException {
        if (TraceEjb.isDebugIc()) {
            TraceEjb.interp.log(BasicLevel.DEBUG, "");
        }
        if (ismarkedremoved || bs == null) {
            if (ismarkedremoved)
                TraceEjb.logger.log(BasicLevel.ERROR, "marked removed");
            else
                TraceEjb.logger.log(BasicLevel.ERROR, "no SessionSwitch");
            throw new IllegalStateException("getEJBLocalObject: EJB is removed");
        }
        EJBLocalObject ejblocalobject = bs.getLocal();
        if (ejblocalobject == null) throw new IllegalStateException("No Local Object for this bean");
        return ejblocalobject;
    }

    /**
     * Obtain a reference to the JAX-RPC MessageContext.
     * @return The MessageContext for this web service invocation.
     * @throws java.lang.IllegalStateException - the instance is in a state that
     *         does not allow access to this method.
     */
    public abstract MessageContext getMessageContext() throws java.lang.IllegalStateException;

    /**
     * Tests if the transaction has been marked for rollback only.
     * @return true if transaction will rollback
     */
    public boolean getRollbackOnly() throws IllegalStateException {
        if (TraceEjb.isDebugIc()) {
            TraceEjb.interp.log(BasicLevel.DEBUG, "");
        }

        if (getState() == CTX_STATE_INITIAL || getState() == CTX_STATE_PASSIVE) {
            throw new IllegalStateException("the instance is not allowed to call this method. ctx state=" + getState());
        }
        return super.getRollbackOnly();
    }

    // -------------------------------------------------------------------
    // Other public methods
    // -------------------------------------------------------------------

    /**
     * Reinit Context for reuse
     * @param bs The SessionSwitch to reuse.
     */
    public void initSessionContext(JSessionSwitch bs) {
        if (TraceEjb.isDebugIc()) {
            TraceEjb.interp.log(BasicLevel.DEBUG, "");
        }
        this.bs = bs;
        ismarkedremoved = false;
    }

    /**
     * Returns the bean instance of this context Used in the generated classes
     * to retrieve the instance
     * @return the bean instance
     * @throws RemoteException if no instance
     */
    // RemoteException is throwned to allow simpler genic templates
    public SessionBean getInstance() throws RemoteException {
        if (myinstance == null) {
            TraceEjb.logger.log(BasicLevel.ERROR, "null!");
            throw new RemoteException("No instance available");
        }
        return (SessionBean) myinstance;
    }

    /**
     * @return True if bean instance is marked removed.
     */
    public boolean isMarkedRemoved() {
        return ismarkedremoved;
    }

    /**
     * Obtain an object that can be used to invoke the current bean through the
     * given business interface.
     * @param <T> the interface of the bean
     * @param businessInterface One of the local business interfaces or remote
     *        business interfaces for this session bean.
     * @return The business object corresponding to the given business
     *         interface.
     * @throws IllegalStateException - Thrown if this method is invoked with an
     *         invalid business interface for the current bean.
     */
    public <T> T getBusinessObject(final Class<T> businessInterface) throws IllegalStateException {
        throw new UnsupportedOperationException("EJB 3.x method, not implemented for EJB 2.x");
    }

    /**
     * Obtain the business interface through which the current business method
     * invocation was made.
     * @return the business interface through which the current business method
     *         invocation was made.
     * @throws IllegalStateException - Thrown if this method is called and the
     *         bean has not been invoked through a business interface.
     */
    public Class getInvokedBusinessInterface() throws IllegalStateException {
        throw new UnsupportedOperationException("EJB 3.x method, not implemented for EJB 2.x");
    }

    // ------------------------------------------------------------------
    // Other methods
    // ------------------------------------------------------------------

    abstract public void setRemoved() throws RemoteException, RemoveException;
    abstract public void setConnectionList(List conlist);
}
