Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

AbstractPoolConnectionManager.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2004 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Emmanuel Cecchet. 
00022  * Contributor(s): Mathieu Peltier.
00023  */
00024 
00025 package org.objectweb.cjdbc.controller.connection;
00026 
00027 import java.io.Serializable;
00028 import java.sql.Connection;
00029 import java.sql.SQLException;
00030 import java.util.Stack;
00031 import java.util.Vector;
00032 
00033 import org.objectweb.cjdbc.common.i18n.Translate;
00034 
00035 /**
00036  * This connection manager uses a pool of persistent connections with the
00037  * database. The allocation/release policy is implemented by the subclasses
00038  * (abstract
00039  * {@link org.objectweb.cjdbc.controller.connection.AbstractConnectionManager#getConnection()}/
00040  * {@link org.objectweb.cjdbc.controller.connection.AbstractConnectionManager#releaseConnection(Connection)}
00041  * from
00042  * {@link org.objectweb.cjdbc.controller.connection.AbstractConnectionManager}).
00043  * 
00044  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00045  * @author <a href="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier </a>
00046  * @version 1.0
00047  */
00048 public abstract class AbstractPoolConnectionManager
00049     extends
00050       AbstractConnectionManager implements Serializable
00051 {
00052   /*
00053    * How the code is organized ? 1. Member variables 2. Constructor(s) 3.
00054    * Connection handling 4. Getter/Setter (possibly in alphabetical order)
00055    */
00056 
00057   /** Stack of available connections (pool). */
00058   protected transient Stack  freeConnections;
00059 
00060   /**
00061    * Pool of currently used connections (<code>Vector</code> type because
00062    * synchronisation is needed).
00063    */
00064   protected transient Vector activeConnections;
00065 
00066   /** Size of the connection pool with the real database. */
00067   protected int              poolSize;
00068 
00069   /*
00070    * Constructor(s)
00071    */
00072 
00073   /**
00074    * Creates a new <code>AbstractPoolConnectionManager</code> instance.
00075    * 
00076    * @param backendUrl URL of the <code>DatabaseBackend</code> owning this
00077    *          connection manager.
00078    * @param backendName name of the <code>DatabaseBackend</code> owning this
00079    *          connection manager.
00080    * @param login backend connection login to be used by this connection
00081    *          manager.
00082    * @param password backend connection password to be used by this connection
00083    *          manager.
00084    * @param driverPath path for driver
00085    * @param driverClassName class name for driver
00086    * @param poolSize size of the connection pool.
00087    */
00088   public AbstractPoolConnectionManager(String backendUrl, String backendName,
00089       String login, String password, String driverPath, String driverClassName,
00090       int poolSize)
00091   {
00092     super(backendUrl, backendName, login, password, driverPath, driverClassName);
00093 
00094     if (poolSize < 1)
00095       throw new IllegalArgumentException(
00096           "Illegal value for size of the pool connection manager: " + poolSize);
00097 
00098     this.poolSize = poolSize;
00099     this.freeConnections = new Stack();
00100     this.activeConnections = new Vector(poolSize);
00101     this.initialized = false;
00102 
00103     if (logger.isDebugEnabled())
00104       logger.debug(Translate.get("connection.backend.pool.created",
00105           new String[]{backendName, String.valueOf(poolSize)}));
00106   }
00107 
00108   /*
00109    * Connection handling
00110    */
00111 
00112   /**
00113    * @see org.objectweb.cjdbc.controller.connection.AbstractConnectionManager#initializeConnections()
00114    */
00115   public synchronized void initializeConnections() throws SQLException
00116   {
00117     initializeConnections(poolSize);
00118   }
00119 
00120   /**
00121    * Initialize initPoolSize connections in the pool.
00122    * 
00123    * @param initPoolSize number of connections to initialize
00124    * @throws SQLException if an error occurs
00125    */
00126   public synchronized void initializeConnections(int initPoolSize)
00127       throws SQLException
00128   {
00129     if (initialized)
00130       throw new SQLException("Connection pool for backend '" + backendUrl
00131           + "' already initialized");
00132 
00133     if (initPoolSize > poolSize)
00134     {
00135       logger.warn(Translate.get("connection.max.poolsize.reached",
00136           new String[]{String.valueOf(initPoolSize), String.valueOf(poolSize),
00137               String.valueOf(poolSize)}));
00138       initPoolSize = poolSize;
00139     }
00140 
00141     Connection c = null;
00142 
00143     boolean connectionsAvailable = true;
00144     int i = 0;
00145     while ((i < initPoolSize) && connectionsAvailable)
00146     {
00147       c = getConnectionFromDriver();
00148 
00149       if (c == null)
00150         connectionsAvailable = false;
00151 
00152       if (!connectionsAvailable)
00153       {
00154         if (i > 0)
00155         {
00156           logger.warn(Translate.get("connection.limit.poolsize", i));
00157         }
00158         else
00159         {
00160           logger.warn(Translate.get("connection.initialize.pool.failed"));
00161           poolSize = 0;
00162         }
00163       }
00164       else
00165       {
00166         freeConnections.push(c);
00167         i++;
00168       }
00169     }
00170 
00171     poolSize = i;
00172     initialized = true;
00173 
00174     if (poolSize == 0) // Should never happen
00175       logger.error(Translate.get("connection.empty.pool"));
00176     if (logger.isDebugEnabled())
00177       logger.debug(Translate.get("connection.pool.initialized", new String[]{
00178           String.valueOf(initPoolSize), backendUrl}));
00179 
00180   }
00181 
00182   /**
00183    * @see org.objectweb.cjdbc.controller.connection.AbstractConnectionManager#finalizeConnections()
00184    */
00185   public synchronized void finalizeConnections() throws SQLException
00186   {
00187     if (!initialized)
00188     {
00189       String msg = Translate.get("connection.pool.not.initialized");
00190       logger.error(msg);
00191       throw new SQLException(msg);
00192     }
00193 
00194     Connection c;
00195     boolean error = false;
00196 
00197     // Close free connections
00198     initialized = false;
00199     int freed = 0;
00200     while (!freeConnections.isEmpty())
00201     {
00202       c = (Connection) freeConnections.pop();
00203       try
00204       {
00205         c.close();
00206       }
00207       catch (SQLException e)
00208       {
00209         error = true;
00210       }
00211       freed++;
00212     }
00213     if (logger.isInfoEnabled())
00214       logger.info(Translate.get("connection.freed.connection", new String[]{
00215           String.valueOf(freed), backendUrl}));
00216 
00217     // Close active connections
00218     int size = activeConnections.size();
00219     if (size > 0)
00220     {
00221       logger.warn(Translate.get("connection.connections.still.active", size));
00222       for (int i = 0; i < size; i++)
00223       {
00224         c = (Connection) activeConnections.get(i);
00225         try
00226         {
00227           c.close();
00228         }
00229         catch (SQLException e)
00230         {
00231           error = true;
00232         }
00233       }
00234     }
00235 
00236     // Clear connections to ensure that the eventually not closed connections
00237     // will be closed when the objects will be garbage collected
00238     freeConnections.clear();
00239     activeConnections.clear();
00240 
00241     if (error)
00242     {
00243       String msg = Translate.get("connection.free.connections.failed");
00244       logger.error(msg);
00245       throw new SQLException(msg);
00246     }
00247   }
00248 
00249   /**
00250    * @see org.objectweb.cjdbc.controller.connection.AbstractConnectionManager#getCurrentNumberOfConnections()
00251    */
00252   public int getCurrentNumberOfConnections()
00253   {
00254     return poolSize;
00255   }
00256 
00257 }

Generated on Mon Apr 11 22:01:28 2005 for C-JDBC by  doxygen 1.3.9.1