/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2005 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.NoSuchObjectException;
import java.rmi.RemoteException;

import javax.ejb.RemoveException;
import javax.transaction.Transaction;
import javax.xml.rpc.handler.MessageContext;

import org.ow2.jonas.lib.timer.TraceTimer;

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

/**
 * JStatelessSwitch is the implementation of JSessionSwitch dedicated to the
 * Stateless Session Bean.
 * @author Philippe Durieux
 */
public class JStatelessSwitch extends JSessionSwitch {

    /**
     * Service Endpoint
     */
    private JServiceEndpoint se = null;

    /**
     * Keep this object alive, because it is unique.
     */
    private boolean keepalive;

    /**
     * constructor.
     * @param bf The Bean Factory
     * @throws RemoteException if the constructor fails
     */
    public JStatelessSwitch(JStatelessFactory bf) throws RemoteException {
        super(bf);
        if (TraceEjb.isDebugIc()) {
            TraceEjb.interp.log(BasicLevel.DEBUG, "");
        }

        // Create ServiceEndpoint if defined in the bean descriptor
        if (bf.getSEHome() != null) {
            se = bf.getSEHome().createServiceEndpointObject();
            se.setSessionSwitch(this);
        }
        keepalive = (bf.singleSwitchOn());
    }

    // ===============================================================
    // TimerEventListener implementation
    // ===============================================================

    /**
     * The session timeout has expired, or a Timer on this bean has expired.
     * @param arg Not Used.
     */
    public synchronized void timeoutExpired(Object arg) {
        if (TraceTimer.logger.isLoggable(BasicLevel.DEBUG)) {
            TraceTimer.logger.log(BasicLevel.DEBUG, "stateless session '" + bf.getEJBName() + "' : timeout expired");
        }
        mytimer = null;
        noLongerUsed();
    }

    // ===============================================================
    // other public methods
    // ===============================================================

    /**
     * @return The ServiceEndpoint
     */
    public JServiceEndpoint getServiceEndpoint() {
        return se;
    }

    /**
     * @return The JAX-RPC MessageContext
     */
    public MessageContext getMsgContext() {
        if (se == null) {
            TraceEjb.logger.log(BasicLevel.ERROR, "No ServiceEndpoint for this bean");
            return null;
        }
        return se.getMessageContext();
    }

    /**
     * get an initialized Bean Context
     * @param tx Current transaction (not used)
     * @return the Session Context
     * @throws RemoteException if context cannot be obtained
     */
    public JSessionContext getICtx(Transaction tx) throws RemoteException {
        if (TraceEjb.isDebugIc()) {
            TraceEjb.interp.log(BasicLevel.DEBUG, "");
        }
        return (JStatelessContext) ((JStatelessFactory) bf).getJContext(this);
    }

    /**
     * release the bean context. Assumes that only 1 Context is managed at a
     * time. Contexts are release at each request, in case of stateless session.
     * @param tx Current transaction (not used)
     */
    public void releaseICtx(RequestCtx req, boolean discard) {
        if (TraceEjb.isDebugIc()) {
            TraceEjb.interp.log(BasicLevel.DEBUG, "");
        }
        JStatelessContext bctx = (JStatelessContext) req.ejbContext;
        if (bctx == null) {
            TraceEjb.interp.log(BasicLevel.WARN, "No ejbContext");
            return;
        }
        if ((bctx.isMarkedRemoved() || discard) && !keepalive) {
            stopTimer();
            noLongerUsed();
        }
        ((JStatelessFactory) bf).releaseJContext(bctx);
    }

    /**
     * This Session is no longer used.
     */
    public void noLongerUsed() {
        if (TraceEjb.isDebugIc()) {
            TraceEjb.interp.log(BasicLevel.DEBUG, "");
        }

        // Unexport the EJBObject from the Orb
        if (myremote != null) {
            try {
                myremote.unexportObject();
            } catch (NoSuchObjectException e) {
                TraceEjb.logger.log(BasicLevel.ERROR, "exception", e);
            }
        }

        // return the SessionSwitch in the pool.
        // will be reused for another Session.
        bf.removeEJB(this);
    }

    /**
     * This is not used for stateless
     * @param mc Not Used.
     */
    public void setMustCommit(boolean mc) {
    }

    /**
     * This is not used for stateless
     */
    public void pushConnectionList() {
    }

    /**
     * This is not used for stateless
     */
    public void popConnectionList() {
    }

    /**
     * This is not used for stateless
     * @param tx the transaction object
     */
    public void enlistConnections(Transaction tx) {
    }
    /**
     * This is not used for stateless
     * @param tx the transaction object
     */
    public void delistConnections(Transaction tx) {
    }
    /**
     * This do nothing for stateless
     */
    public void saveBeanTx() {
    }
}
