Hello Everybody!
I'm Andrea from italy, and i'm very interested about the jakarta httpclient.
I tried it and i find it very easy to use, but i found (i wrote about it some time ago) a bug in the multithredconnectionmanger.
It seems that the opened connections are tested for closure only when they ahve to be given back from the pool to the client. In this way, after some time where the connections are not used, the connections are still open but the are in CLOSE_WAIT state: they are shut down when a client request for a new connection form the pool, but the pool finds the old conenction in a "CLOSE_WAIT" state, so it shuts down the conenction and creates a new one.
Now, int this manner there could be a wate of resources, if nobody uses connections for a long time.
I have seen that something has been done (in cvs) about auto closing idle connection, but i still think that the multithreaded connection manager needs a reimplementation.
I think that could be a great idea to reimplement the manager using commons pool as a base.
Simply, the manager has to trak a list of open pools based on GenericObjectPool: every pool in the manager (one for each host) must be created using a factory that manages the connection life-cycle in the pool (in the common pool framework).
I attach the code i've written, so you can take a look at it.


Regards
Andrea Fabris

Errore Apertura DB
package org.apache.commons.httpclient.pool;

import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.httpclient.HttpConnection;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.logging.*;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2004</p>
 * <p>Company: </p>
 * @author not attributable
 * @version 1.0
 */

public class PoolableHttpConnectionFactory implements PoolableObjectFactory {

  private HostConfiguration connConf;
  private HttpPoolConnectionManager manager;
  private static Log log = LogFactory.getLog(PoolableHttpConnectionFactory.class);

  public PoolableHttpConnectionFactory(HostConfiguration hc, HttpPoolConnectionManager manager) {
    connConf = hc;
    this.manager = manager;
  }

  /**
   * Create a new connection using the HostConfiguration passed in the Factory
   * @return a new connection
   */
  public Object makeObject() {
    log.debug("<PoolableHttpConnectionFactory - makeObject> Inizio metodo");
    HttpConnection conn = new HttpConnection(connConf);
    conn.setHttpConnectionManager(manager);
    log.debug("<PoolableHttpConnectionFactory - makeObject> Fine metodo");
    return conn;
  }

  public void destroyObject(Object in) {
    log.debug("<PoolableHttpConnectionFactory - destroyObject> Inizio metodo");
    if (in != null) {
      log.debug("<PoolableHttpConnectionFactory - destroyObject> Connection not null");
      HttpConnection conn = (HttpConnection) in;
      if (conn.isOpen()) {
        log.debug("<PoolableHttpConnectionFactory - destroyObject> Closing connection");
        conn.close();
      }
      in = null;
      log.debug("<PoolableHttpConnectionFactory - destroyObject> Fine metodo");
    }
  }

  public boolean validateObject(Object in) {
    log.debug("<PoolableHttpConnectionFactory - validateObject> Inizio metodo");
    boolean result = false;
    if (in != null) {
      HttpConnection conn = (HttpConnection) in;
      if (conn.isOpen())
        log.debug("<PoolableHttpConnectionFactory - validateObject> Connection opened: valid connection");
        result = true;
    }
    log.debug("<PoolableHttpConnectionFactory - validateObject> Inizio metodo");
    return result;
  }

  public void activateObject(Object in) {
    log.debug("<PoolableHttpConnectionFactory - activateObject> No action");
  }

  public void passivateObject(Object in){
    log.debug("<PoolableHttpConnectionFactory - passivateObject> No action");
  }
}
package org.apache.commons.httpclient.pool;

import org.apache.commons.pool.impl.GenericObjectPool;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2004</p>
 * <p>Company: </p>
 * @author not attributable
 * @version 1.0
 */

public class HttpPoolConnectionManagerConfiguration {
    private final long DEFAULT_TIMEOUT = 2000;
    private final int DEFAULT_MAX_CONNECTIONS_PERHOST = 20;
    private final long DEFAULT_EVICTION_TIME = 1000;
    private final int DEFAULT_NUM_TEST_PEREVICTION = 3;
    protected GenericObjectPool.Config poolconfig;

    /**
     * Default constructor
     * It initializes the pool configuration with default values
     */
    public HttpPoolConnectionManagerConfiguration() {
      poolconfig = new GenericObjectPool.Config();
      //pool configuration
      poolconfig.maxActive = DEFAULT_MAX_CONNECTIONS_PERHOST;
      //eviction thread
      poolconfig.minEvictableIdleTimeMillis = DEFAULT_TIMEOUT;
      poolconfig.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK;
      poolconfig.timeBetweenEvictionRunsMillis = DEFAULT_EVICTION_TIME;
      poolconfig.numTestsPerEvictionRun = DEFAULT_NUM_TEST_PEREVICTION;
      poolconfig.testWhileIdle = true;
    }

    /**
     * Sets the maximum number of connections that could be idle in the pool
     * @param max max idle connection in the pool
     */
    public void setMaxIdle(int max) {
      poolconfig.maxIdle = max;
    }

    /**
     * Sets the maximum number of connections that could be idle in the pool
     * @param min min idle connection pool
     */
    public void setMinIdle(int min) {
      poolconfig.minIdle = min;
    }

    /**
     * Sets if the connection has to be tested for validity before being returned to the pool
     * @param test true if the connection has to be tested before being returned to the pool
     */
    public void setTestOnReturn(boolean test) {
      poolconfig.testOnReturn = test;
    }

    /**
     * Sets if the connection has to be tested for validity before being borrowed from the pool
     * @param test true if the connection has to be tested before being borrowed from the pool
     */
    public void setTestOnBorrow(boolean test) {
      poolconfig.testOnBorrow = test;
    }

    /**
     * Sets how many milliseconds the client can wait for a connection from the pool
     * @param wait maximum wait time
     */
    public void setMaxWait(long wait) {
      poolconfig.maxWait = wait;
    }

    /**
     * Set the maximum number of connection allowed in the pool
     * @param max max connection in the pool
     */
    public void setMaxActive(int max) {
      poolconfig.maxActive = max;
    }

    /**
     * Sets how many milliseconds an dle connection could remain in the pool before being closed
     * @param timeout maximum idle time
     */
    public void setPoolIdleTime(long timeout) {
      poolconfig.minEvictableIdleTimeMillis = timeout;
    }

    /**
     * Sets the time (in milliseconds) between two runs of the check thred in the pool
     * @param time
     */
    public void setPoolCheckTime(long time) {
      poolconfig.timeBetweenEvictionRunsMillis = time;
    }

    /**
     * Sets how meny tests have to be perfomrmed during the eviction run
     * @param test int
     */
    public void setTestPerCheck(int test) {
      poolconfig.numTestsPerEvictionRun = test;
    }
}
package org.apache.commons.httpclient.pool;

import java.util.*;

import org.apache.commons.httpclient.*;
import org.apache.commons.logging.*;
import org.apache.commons.pool.impl.*;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2004</p>
 * <p>Company: </p>
 * @author not attributable
 * @version 1.0
 */

public class HttpPoolConnectionManager
    implements HttpConnectionManager {

  private HashMap poolsMap = new HashMap();
  private static Log log = LogFactory.getLog(HttpPoolConnectionManager.class);
  private static int DEFAULT_MAX_CONNECTIONS = 100;

  HttpPoolConnectionManagerConfiguration config;
  private int maxConnections;

  public HttpPoolConnectionManager() {
    config = new HttpPoolConnectionManagerConfiguration();
    maxConnections = DEFAULT_MAX_CONNECTIONS;
  }

  /**
   * HttpPoolConnectionManager
   *
   * @param configuration HttpPoolConnectionManager
   */
  public HttpPoolConnectionManager(HttpPoolConnectionManagerConfiguration
                                   configuration) {
    config = configuration;
    maxConnections = DEFAULT_MAX_CONNECTIONS;
  }

  public HttpConnection getConnection(HostConfiguration hostConfiguration) {
    try {
      return getConnection(hostConfiguration, -1);
    } catch (HttpException ex) {
      log.error("<HttpPoolConnectionManager - getConnection> " + ex.toString());
      return null;
    }
  }

  public HttpConnection getConnection(HostConfiguration hostConfiguration,
                                      long timeout)
      throws HttpException {
    log.debug("<HttpConnectionManager - getConnection> Inizio metodo");
    //Ottengo la "chiave"
    String key = hostConfiguration.getHost() + ":" + hostConfiguration.getPort();
    log.debug("<HttpConnectionManager - getConnection> Pool [" + key + "]");
    GenericObjectPool pool = null;
    synchronized (this) {
      pool = (GenericObjectPool) poolsMap.get(key);
      if (pool == null) {
        //creo pool e ottengo connessione
        log.debug("<HttpConnectionManager - getConnection> Pool da creare");
        config.setMaxWait(timeout);
        GenericObjectPool newpool = new GenericObjectPool(new
            PoolableHttpConnectionFactory(hostConfiguration, this),
            config.poolconfig);
        poolsMap.put(key, newpool);
        log.debug("<HttpConnectionManager - getConnection> Fine metodo");
        try {
          return (HttpConnection) newpool.borrowObject();
        } catch (Exception ex) {
          log.error("<HttpConnectionManager - getConnection> " + ex.toString());
          throw new HttpException(ex.getMessage());
        }
      }
    }
    //pool in cache
    log.debug("<HttpConnectionManager - getConnection> Pool già usato");
    log.debug("<HttpConnectionManager - getConnection> Fine metodo");
    try {
      return (HttpConnection) (pool).borrowObject();
    } catch (Exception ex) {
      log.error("<HttpConnectionManager - getConnection> " + ex.toString());
      throw new HttpException(ex.getMessage());
    }
  }

  public void releaseConnection(HttpConnection conn) {
    log.debug("<HttpConnectionManager - releaseConnection> Inizio metodo");
    String key = conn.getHost() + ":" + conn.getPort();
    log.debug("<HttpConnectionManager - releaseConnection> Pool [" + key + "]");
    if (poolsMap.containsKey(key)) {
      GenericObjectPool pool = (GenericObjectPool) poolsMap.get(key);
      try {
        pool.returnObject(conn);
      } catch (Exception ex) {
        log.error("<HttpPoolConnectionManager - releaseConnection> " +
                  ex.toString());
      }
    }
    log.debug("<HttpConnectionManager - releaseConnection> Fine metodo");
  }

  public void finalize() {
    log.debug("<HttpPoolConnectionManager - finalize> Inizio metodo");
    if (this.poolsMap != null) {
      Iterator keyiter = this.poolsMap.keySet().iterator();
      while (keyiter.hasNext()) {
        String key = (String) keyiter.next();
        log.debug("<HttpPoolConnectionManager - finalize> Destroying [" + key +
                  "]");
        GenericObjectPool pool = (GenericObjectPool)this.poolsMap.get(key);
        try {
          pool.close();
          this.poolsMap.put(key, null);
        } catch (Exception ex) {
          log.error("<HttpPoolConnectionManager - finalize> " + ex.toString());
        }
      }
      this.poolsMap = null;
    }
    log.debug("<HttpPoolConnectionManager - finalize> Fine metodo");
  }

  public void shutdown() {
    log.debug("<HttpPoolConnectionManager - shutdown> Inizio metodo");
    Iterator keyiter = this.poolsMap.keySet().iterator();
    while (keyiter.hasNext()) {
      String key = (String) keyiter.next();
      log.debug("<HttpPoolConnectionManager - shutdown> Destroying [" + key +
                "]");
      GenericObjectPool pool = (GenericObjectPool)this.poolsMap.get(key);
      try {
        pool.close();
        this.poolsMap.put(key, null);
      } catch (Exception ex) {
        log.error("<HttpPoolConnectionManager - shutdown> " + ex.toString());
      }
    }
    this.poolsMap = null;
    log.debug("<HttpPoolConnectionManager - shutdown> Fine metodo");
  }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to