package org.jcon.df.request;

import org.jcon.df.Integrity;
import org.jcon.util.GenLib;
import java.rmi.RemoteException;
import java.util.Stack;

/**
 * Manages a pool of Performers by allowing checkOut and
 * checkIn of Performers. Currently pool size is not
 * controlled by this class.
 * <p>
 * Note each Performer has its own RequestServices, each of
 * which has its own Connector. This allows a unique JDBC
 * Connection and Statement per request.
 *
 * @author Jack Harich
 */
public class PerformerPool {

//---------- Private Fields ------------------------------
private RequestServices prototypeServices;
private Stack           idleStack = new Stack();
private Integrity       integrity;

//---------- Properties ----------------------------------
public void setRequestServices(RequestServices services) {
    prototypeServices = services;
}
public void setIntegrity(Integrity integrity) {
    this.integrity = integrity;
}
//---------- Public Methods ------------------------------
/**
 * Gets a Performer from the pool, for immediate use. If
 * the pool is empty then a new Performer is created and
 * initialized. Complains and returns null if failure.
 */
public synchronized Performer checkOut() {
Performer performer = null;
if (idleStack.isEmpty()) {
    try {
        // Create and configure new Performer
        RequestServices newServices = new RequestServices();
        newServices.setTranslator(prototypeServices.getTranslator());
        newServices.setConnector(prototypeServices.cloneConnector());
        newServices.setSchema(prototypeServices.getSchema());
        newServices.setEntityLockPool(prototypeServices.getEntityLockPool());
        newServices.setIntegrity(integrity);

        performer = new Performer();
        performer.setPerformerPool(this);
        performer.setRequestServices(newServices);
        performer.start();

    } catch(RemoteException ex) {
        GenLib.exception("PerformerPool.checkOut()",
            "Failure instantating a Performer.", ex);
        return null;
    }
} else {
    performer = (Performer)idleStack.pop();
}
printIdleStackInfo("checkOut");
return performer;
} // End method
/**
 * Returns a Performer to the pool, for future reuse.
 * The Performer should be idle. Complains and has no effect
 * if the performer is already in the pool.
 */
public synchronized void checkIn(Performer performer,
        boolean unreferenced) {
    if (idleStack.search(performer) > -1) {
        // Unreferenced can occur if already checked in
        if (! unreferenced) {
            GenLib.error("PerformerPool.checkIn()",
                "Pool already contains this performer.");
        }
    } else {
        performer.stop();
        idleStack.push(performer);
    }
    printIdleStackInfo("checkIn");
}
/**
 * Removes, stops and dereferences all checked in Performers.
 * This can be called anytime with no harm, probably for the
 * purpose of closing a database or reducing memory use.
 */
public synchronized void clearAllCheckedIn() {
    while (! idleStack.isEmpty()) {
        Performer performer = (Performer)idleStack.pop();
        performer.stop();
    }
}
//---------- Private Methods -----------------------------
private void printIdleStackInfo(String which) {
    print(" - performer idleStack size = " +
        idleStack.size() + " after " + which);
}
//--- Std
private static void print(String text) {
    System.out.println("PerformerPool" + text);
}

} // End class
