(message continued from previous post)
The following are the proposed changes to the ConnectionPooling code:
1. Class DB (and subclasses): added the following two methods:
/**
* Returns a new JDBC <code>PooledConnection</code>.
* The JDBC driver should support the JDBC 2.0 extenstions. Since the
* implementation of this class is driver specific, the actual class
* of the JDBC driver that implements the PooledConnection interface
* should be defined in the specific DB Adapter
*
* @return A JDBC <code>PooledConnection</code> object for this
* database.
* @exception SQLException if the driver does not support
PooledConnection
* objects
*/
public PooledConnection getPooledConnection()
throws SQLException
{
try{
Class PC = Class.forName(getPooledConnectionClassName());
Constructor ctr = PC.getConstructor(new Class[]{
String.class, String.class, String.class});
Object instance = ctr.newInstance(new Object[]{DB_CONNECTION,
DB_USER,
DB_PASS});
return (PooledConnection) instance;
} catch (Exception e){
throw new SQLException("Could not create PooledConnection
object");
}
}
/**
* This method returns the class name of the actual object used by the
JDBC
* driver to create PooledConnection objects
*/
protected String getPooledConnectionClassName()
throws SQLException
{
throw new SQLException("PooledConnection objects not supported by
JDBC driver");
}
If the Jdbc driver supports the JDBC2.0 extensions, then the corresponding
adapter should
override the getPooledconnectionClassName() and return the class that
implements the
PooledConnection. For oracle (DBOracle class) the method should be overriden
as:
protected String getPooledConnectionClassName()
throws SQLException
{
return "oracle.jdbc.pool.OraclePooledConnection";
}
If the method is not overriden, the default implementation just throws a
SQLException
signaling that support for JDBC2.0 PooledConnection is not present.
2. ConnectionPool class:
The getNewConnection method tries to create a PooledConnection first, and if
it fails resorts
to plain Connection objects
/**
* Returns a fresh connection to the database. The database type
* is specified by <code>driver</code>, and its connection
* information by <code>url</code>, <code>username</code>, and
* <code>password</code>.
*
* @return A database connection.
* @exception Exception
*/
protected DBConnection getNewConnection()
throws Exception
{
/*old code
DBConnection dbc = new DBConnection( getDB().getConnection(), url );
totalConnections++;
return dbc;
*/
try
{
PooledConnection pc = getDB().getPooledConnection();
DBConnection dbc = new DBConnection( pc, url, null, null );
totalConnections++;
return dbc;
}
catch ( SQLException ignore )
{
//Pooled connection not supported, attempt a java.sql.Connection
DBConnection dbc = new DBConnection( getDB().getConnection(),
url );
totalConnections++;
return dbc;
}
}
(The methods getPooledConnection are useless here, correct?)
3. DBConnetion:
a) added constructor for PooledConnection
/**
* Creates a Turbine <code>DBConnection</code> that is part of
* a pool.
*
* @param connection The JDBC connection to wrap.
* @param url The URL we're connecting to.
* @param username The user name we are connecting as
* @param pool The ConnectionPool that this DBConnection belongs
to
*/
protected DBConnection(PooledConnection pooledConnection, String url,
String username,
ConnectionPool pool)
{
this.pooledConnection = pooledConnection;
pooledConnection.addConnectionEventListener(this);
this.url = url;
this.username = username;
this.pool = pool;
this.timestamp = System.currentTimeMillis();
eventListeners = new Vector();
}
b) now implementing ConnectionEventListener
public class DBConnection implements PooledConnection,
ConnectionEventListener...
c)private field for holding reference to PooledConnection
/**
* The JDBC PooledConnection (if supported by the JDBC driver). If this
* is null, then this class uses the classic Connection object to manage
* connection. Else, the PooledConnection object is used.
*/
private PooledConnection pooledConnection = null;
d)changed method link, unlink, addConnectionEventListener,
removeConnectionEventListener,
getConnection, close
/**
* Links this DBConnection with a ConnectionPool.
*
* @param The pool to link to.
*/
protected void link(ConnectionPool pool)
{
if (pool == null)
{
throw new NullPointerException
("Cannot link to a null database ConnectionPool");
}
this.pool = pool;
//If we use a PooledConnection object, then request from it a
Connection
//object. This forces the PooledConnection to create a wrapper
for the
//physical connection it represents and return a Logical
Connection object
//that is currently in control of it.
if ( pooledConnection != null )
{
try
{
if ( connection != null )
{
connection = pooledConnection.getConnection();
}
}
catch (Exception ignore)
{
//ignore this
}
}
}
/**
* Unlink the DBConnection from it's pool.
*
* @param pool The pool to unlink from.
* @exception Exception Attempt to unlink from another pool.
*/
protected void unlink(ConnectionPool pool) throws Exception
{
if (this.pool != pool && pool != null)
{
throw new IllegalArgumentException
("Trying to unlink from the wrong pool");
}
this.pool = null;
//if we use a PooledConnection object, then this method will
release
//the physical connection that this PooledConnection represents
and
//allow for its reuse.
if ( pooledConnection != null )
{
if ( connection != null )
connection.close();
connection = null;
}
}
/**
* Add an event listener.
*/
public void addConnectionEventListener(ConnectionEventListener listener)
{
if ( pooledConnection != null )
{
pooledConnection.addConnectionEventListener( listener );
}
else
{
eventListeners.add (listener);
}
}
/**
* Remove an event listener.
*/
public void removeConnectionEventListener(ConnectionEventListener
listener)
{
if ( pooledConnection != null )
{
pooledConnection.removeConnectionEventListener( listener );
}
else
{
eventListeners.remove (listener);
}
}
/**
* Returns a JDBC connection.
*
* @return The database connection.
*/
public Connection getConnection()
throws SQLException
{
//if we manage an actual PooledConnection, just delegate the
call
if ( pooledConnection != null )
{
//if the link method has been called first, then the
reference will
//contain a valid connection object. If not, get it from
here.
if ( connection != null )
{
return connection;
}
else
{
return pooledConnection.getConnection();
}
}
//else, we try to mimic the PooledConnection interface
if (connection == null)
{
throw new SQLException ("Connection object is null!");
}
else if (connection.isClosed())
{
throw new SQLException ("Connection is closed!");
}
else
{
return connection;
}
}
e) implemented ConnectionEventListener interface
/**
* This method is not implemented
*/
public void connectionClosed(ConnectionEvent event) {
}
/**
* If a fatal error occurs, close the undelying physical connection so
as not to
* be returned in the future
*/
public void connectionErrorOccurred(ConnectionEvent e) {
try {
//remove this from the listener list because we are no more
interested in errors
//since we are about to close this connection
( (PooledConnection)
e.getSource() ).removeConnectionEventListener(this);
try
{
//this one will close the underlying physical connection
( (PooledConnection) e.getSource() ).close();
}
catch (Exception ignore)
{
//just ignore
}
//this will also close the Logical Connection object so a
future
//call to isClosed() will return true
try
{
connection.close();
}
catch (Exception ex)
{
//ignore
}
}
catch (Exception ignore) {
//just ignore
}
}
f) still missing constructor with less than 4 arguments using
PooledConnection instead
of Connection.
With the above modifications code such as:
DBConnection db = null;
Connection con = null;
try{
db = TurbineDB.getConnection();
con = db.getConnection();
Statement s = con.createStatement();
}catch(Exception sqle){
}
finally{
try{
TurbineDB.releaseConnection(db);
}catch(Exception ignore){};
}
which is the way that everyone has been coding will work and will recover
after a full
db restart (also, notice that the Statement s is not closed but that's ok
with the
modifications since when the connection is released, the resources are
de-allocated internally... )
I would like your comments on the above since they are a big change to the
code. Also,
to be absolutely honest, the way that DBConnection is used is not quite
right. I would prefer
a re-write of the ConnectionPool+DBConnection classes in order to actually
make use of
all the JDBC2.0 extenstions (Use PooledConnection, DataSources, etc) and use
correctly
the new interfaces (this can actually be done without breaking existing
compatibility).
For example, on the above code, the DBConnection object is registered as a
listener to the
PooledConnection object it wraps: this is not correct (the ConnectionPool
should be registered
as listener) but there is no other way to do this since the actual pooling
is done with DBConnection
objects and not with PooledConnection objects. Also the close() method is
quite tricky (should not
close the connection).
Waiting for your comments on the above,
Sorry again for the big e-mail but the changes are quite significant.
Thanks in advance,
Costas
P.S. I couldn't use the csv to upload the above code due to some firewall
restrictions. Can you
please specify me the ports used for the Win-CVS client?
------------------------------------------------------------
To subscribe: [EMAIL PROTECTED]
To unsubscribe: [EMAIL PROTECTED]
Search: <http://www.mail-archive.com/turbine%40list.working-dogs.com/>
Problems?: [EMAIL PROTECTED]