/* JFox, the OpenSource J2EE Application Server
 *
 * Copyright (C) 2002 huihoo.org
 * Distributable under GNU LGPL license
 * See the GNU Lesser General Public License for more details.
 */

package org.huihoo.jfox.pool;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * 
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class SimpleObjectPool extends AbstractObjectPool {
  //已从池中取出的对象数目
  private volatile int numWorking = 0;
  private List pool = Collections.synchronizedList(new ArrayList());

  /** the number of "sleeping" instances in the pool. */
  private int maxRest = 10;

  private int initNum = 5;

  public SimpleObjectPool(ObjectFactory factory) {
    this(factory,5,10);
  }

  public SimpleObjectPool(ObjectFactory factory, int initNum, int maxRest){
    super(factory);
    this.factory = factory;
    this.initNum = initNum;
    this.maxRest = maxRest;
  }

  public SimpleObjectPool(String objectFactoryClassName, String poolableClassName) {
    super(objectFactoryClassName, poolableClassName);
  }

  public SimpleObjectPool(String objectFactoryClassName, String poolableClassName, int initNum, int maxRest) {
    super(objectFactoryClassName, poolableClassName);
    this.initNum = initNum;
    this.maxRest = maxRest;
  }
  /**
   * retrieve Object from object pool
   * @return
   */
  public synchronized PoolableObject retrieveObject() throws Exception {
    logger.debug("retrieve object, pool size is " + pool.size() + ", max rest is " + maxRest);
    PoolableObject obj = null;
    synchronized(pool) {
      if(pool.size() > 0){
        obj = (PoolableObject)pool.remove(0);
      }
    }
    if(obj == null){ // 池中已经没有了
      obj = factory.makeObject();
    }
    if(obj != null) {
      obj.activate();
    }
    numWorking++;
    return obj;
  }

  /**
   * restore the retrived object to object pool
   * @return true if object passivate && push success, false if failed
   */
  public boolean restoreObject(PoolableObject obj) {
    logger.debug("restore object " + obj + ", pool size " + pool.size());
    numWorking--;
    PoolableObject realObject = obj;

// Proxy PoolableObject 也支持 destory 等操作,所以不用特殊对待
//    if(Proxy.isProxyClass(obj.getClass())) {
//      realObject = ((PoolableObjectInvocationHandler)Proxy.getInvocationHandler(obj)).getPoolableObject();
//    }

    if(factory.validateObject(realObject)) {
      try {
        obj.passivate();
        synchronized(pool){
          // 未达初始值或者系统忙且还没有达到上限,返回池
          if(pool.size() < initNum || (pool.size() < maxRest && numWorking > 0)) {
            pool.add(realObject);
            return true;
          }
          else {
            factory.destroyObject(realObject);
            return false;
          }
        }
      }
      catch(Exception e){
        try {
          factory.destroyObject(realObject);
        }
        catch(Exception ex) {
          logger.warn(e);
        }
        return false;
        // do nothing , just jump to below
      }
    }
    else {
      try {
        factory.destroyObject(realObject);
      }
      catch(Exception e){
        logger.warn(e.getMessage(),e);
      }
      return false;
    }
  }

  public boolean removeObject(PoolableObject obj) {
    logger.debug("remove object " + obj);
    return pool.remove(obj);
  }

  // clear the pool
  public synchronized void clear() {
    logger.debug("clear object pool");
    Iterator iter = pool.iterator();
    while(iter.hasNext()) {
      try {
        factory.destroyObject((PoolableObject)iter.next());
      }
      catch(Exception e) {
        logger.warn(e);
      }
    }
    synchronized (pool){
      pool.clear();
    }
  }

  public int getWorking() {
    return numWorking;
  }

  public int getRest() {
    return pool.size();
  }

  protected void doInit() throws Exception {
    logger.debug("make " + initNum + " poolable object");
    int i = initNum;
    while(i-- > 0){
      try {
        pool.add(factory.makeObject());
      }
      catch(Exception e){
        throw new RuntimeException(e);
      }
    }
  }

  // just do clear
  protected void doDestroy() throws Exception {
    this.clear();
  }

  public int getInitNum() {
    return initNum;
  }

  public int getMaxRest() {
    return maxRest;
  }

  public static void main(String[] args) {

  }
}