package com.srbenoit.pool;

import com.srbenoit.log.LoggedObject;

/**
 * The base class for objects that can be managed by a pool.
 */
public abstract class AbstractPoolObject extends LoggedObject implements Cloneable {

    /** object on which to synchronize access to this object's data */
    protected final transient Object synch;

    /** the pool from which this object was checked out */
    private transient Pool<? extends AbstractPoolObject> fromPool;

    /**
     * Constructs a new <code>AbstractPoolObject</code>.
     */
    public AbstractPoolObject() {

        super();
        this.synch = new Object();
    }

    /**
     * Sets the pool that this object was checked out from.
     *
     * @param  pool  the pool (<code>null</code> if this object was not checked out from a pool)
     */
    public void setFromPool(final Pool<? extends AbstractPoolObject> pool) {

        this.fromPool = pool;
    }

    /**
     * Gets the pool that this object was checked out from.
     *
     * @return  the pool (<code>null</code> if this object was not checked out from a pool)
     */
    public Pool<? extends AbstractPoolObject> getFromPool() {

        return this.fromPool;
    }

    /**
     * Resets this object to a virgin state (used before the object is returned to a pool). This
     * method must reset the object to a state that is indistinguishable from a newly created
     * object.
     */
    public abstract void toVirginState();

    /**
     * Creates a deep copy of the object - used to create new objects when the pool is empty. This
     * method should be implemented using <code>clone</code> to be more efficient than object
     * construction.
     *
     * @return  the copy, which will be in the same state as a newly created object
     */
    public abstract AbstractPoolObject copy();

    /**
     * Informs the pool object that it is being released for garbage collection and should free any
     * internal resources. The object may not be reused after this method is called.
     */
    public abstract void die();

    /**
     * Returns the object to the pool from which it was checked out. This calls <code>
     * checkIn</code> on the pool.
     */
    public void returnToPool() {

        this.fromPool.checkIn(this);
    }
}
