/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.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(s): Philippe Durieux
 * Contributor(s):
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas_ejb.container;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EmptyStackException;
import java.util.List;
import java.util.ListIterator;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.naming.NamingException;
import org.objectweb.jonas_ejb.deployment.api.SessionStatelessDesc;

/**
 * This class is a factory for a Session Stateless Bean.
 */
public class JStatelessFactory extends JSessionFactory {

    // instance pool management (list of available JSessionContext objects)
    // Contexts are pooled only for Stateless Session beans because for Stateful 
    // sessions a newInstance() is required by the spec.
    protected List bctxlist = Collections.synchronizedList(new ArrayList());
    protected int instanceCount = 0;

    /**
     * constructor
     */
    public JStatelessFactory(SessionStatelessDesc dd, JContainer cont) {
	super(dd, cont);
	TraceEjb.debugIc("JStatelessFactory constructor");
	isStateful = false;
    }

    // ---------------------------------------------------------------
    // BeanFactory implementation
    // ---------------------------------------------------------------

    /**
     * @return the Instance pool size for this Ejb
     */
    public int getPoolSize() {
	return bctxlist.size();
    }

    // ---------------------------------------------------------------
    // other public methods
    // ---------------------------------------------------------------

    /**
     * Creates a new Session Stateless
     */
    public JSessionSwitch createNewSession() throws RemoteException {
	TraceEjb.debugIc("createNewSession");
	JStatelessSwitch bs = new JStatelessSwitch(this);
	return bs;
    }

    /**
     * Returns a SessionContext for Stateless Session Bean
     */
    public JSessionContext getJContext() {
	TraceEjb.debugIc("getJContext");
	JStatelessContext bctx = null;

	// try to find a free context in the pool
	synchronized(bctxlist) {
	    try {
		ListIterator i = bctxlist.listIterator();
		if (i.hasNext()) {
		    bctx = (JStatelessContext) i.next();
		    i.remove();
		}
	    } catch(IndexOutOfBoundsException ex) {
		// pool is empty
	    }
	}

	if (bctx == null) {
	    // create a new one if pool empty
	    try {
		bctx = createNewInstance();
	    } catch (Exception e) {
		TraceEjb.error("getJContext:"+e);
		throw new EJBException("Cannot create a new instance");
	    }
	}
	return bctx;
    }

    /**
     * Called after each method call
     */
    public void releaseJContext(JContext ctx) {
	TraceEjb.debugIc("releaseJContext");
	JStatelessContext bctx = (JStatelessContext) ctx;
	// TODO clean context before ?
	bctxlist.add(bctx);
    }

    // ---------------------------------------------------------------
    // private methods
    // ---------------------------------------------------------------

    /**
     * Create a new instance of the bean and its StatelessContext
     */
    private JStatelessContext createNewInstance() throws Exception {
	TraceEjb.debugIc("createNewInstance");
	// create the bean instance
	SessionBean bean = null;
	try {
	    bean = (SessionBean) beanclass.newInstance();
	} catch (InstantiationException e) {
	    TraceEjb.error(ejbname+" Cannot instantiate SessionBean");
	    throw e;
	} catch (IllegalAccessException e) {
	    TraceEjb.error(ejbname+" Cannot instantiate SessionBean");
	    throw e;
	}

	// create a new StatelessContext and bind it to the instance
	JStatelessContext bctx = new JStatelessContext(this, bean);
	bean.setSessionContext(bctx);

	// call ejbCreate on the instance
	TraceEjb.debugIc("call ejbCreate on the instance");
	try {
	    beanclass.getMethod("ejbCreate", null).invoke(bean, null);
	} catch (Exception e) {
	    TraceEjb.error(ejbname+" Cannot call ejbCreate on Stateless Session ");
	}
	
	return bctx;
    }

}
