FileDocCategorySizeDatePackage
PhysicalConnection.javaAPI DocExample17262Mon Mar 31 23:10:16 BST 2003org.dasein.persist

PhysicalConnection

public class PhysicalConnection extends Object implements PooledConnection, StatementEventListener, Connection
An abstraction for the physical connection to a vendor's JDBC connection. This particular abstraction lives in a connection pool and performs statement pooling.
Last modified $Date$
version
$Revision$
author
George Reese

Fields Summary
private Connection
database
The actual JDBC connection to the database. This class works with any JDBC-compliant connection instance. For best performance, the connection supplied should not be pooled.
private ArrayList
listeners
The list of objects listening for connection events.
private LogicalConnection
logical
The currently open logical connection, if any.
private StatementPool
pool
The pool of statements open by this connection.
Constructors Summary
public PhysicalConnection(String dsn)
Constructs a new physical connection that pulls its database connections from the specified DSN.

param
dsn the name of a data source providing JDBC connections
throws
java.sql.SQLException an error occurred connecting to the database


                                           
         
        this(dsn, null, null);
    
public PhysicalConnection(String dsn, String uid, String pw)
Constructs a new physical connection that pulls its database connections from the specified DSN.

param
dsn the name of a data source providing JDBC connections
param
uid the user ID to use in making the connection
param
pw the password to use in making the connection
throws
java.sql.SQLException an error occurred connecting to the database

        super();
        try {
            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource)ctx.lookup(dsn);

            if( uid == null && pw == null ) {
                database = ds.getConnection();
            }
            else {
                database = ds.getConnection(uid, pw);
            }
        }
        catch( NamingException e ) {
            throw new SQLException(e.getMessage());
        }
        Thread t = new Thread() {
               public void run() {
                    keepAlive();
                }
            };

        t.setDaemon(true);
        t.setName("KEEP ALIVE");
        t.start();
    
Methods Summary
public voidaddConnectionEventListener(javax.sql.ConnectionEventListener lstnr)
Adds new listeners to connection events. This method is part of the pooled connection's contract with its pooling environment so that the pooling environment knows when connections occur and unrecoverable errors occur.

param
lstnr the new listener

        synchronized( listeners ) {
            listeners.add(lstnr);
        }
    
public voidclearWarnings()
Delegates to the underlying JDBC connection.

throws
java.sql.SQLException a database error occurred

        database.clearWarnings();
    
public voidclose()
Delegates to the underlying JDBC connection.

throws
java.sql.SQLException a database error occurred

        synchronized( listeners ) {
            if( database != null ) {
                database.close();
            }
        }
        logical = null;
    
public voidcommit()
Delegates to the underlying JDBC connection.

throws
java.sql.SQLException a database error occurred

        database.commit();
    
public voidconnectionClosed()
Called by the current logical connection to let the physical connection know that the application has closed the logical connection. This method will thus trigger a connection event notifying the pooling environment that this physical connection is now available for reuse.

        synchronized( listeners ) {
            Iterator it = listeners.iterator();
            
            while( it.hasNext() ) {
                ConnectionEventListener lstnr;

                lstnr = (ConnectionEventListener)it.next();
                lstnr.connectionClosed(new ConnectionEvent(this));
            }
            logical = null;
            listeners.notifyAll();
        }
    
public voidconnectionErrored(java.sql.SQLException e)
Called by the current logical connection to let the physical connection know that an error has occured indicating a need to discard this physical connection. This method will thus trigger a connection event notifying the pooling environment that this physical connection should be permanently out of use.

param
e the exception causing the discard of this connection

        synchronized( listeners ) {
            Iterator it = listeners.iterator();
            
            while( it.hasNext() ) {
                ConnectionEventListener lstnr;

                lstnr = (ConnectionEventListener)it.next();
                lstnr.connectionErrorOccurred(new ConnectionEvent(this, e));
            }
        }
    
public java.sql.StatementcreateStatement(int rst, int rsc)
Delegates to the underlying JDBC connection.

param
rst the result set type
param
rsc the result set concurrency
throws
java.sql.SQLException a database error occurred

        return database.createStatement(rst, rsc);
    
public java.sql.StatementcreateStatement()
Delegates to the underlying JDBC connection.

return
a new statement instance
throws
java.sql.SQLException a database error occurred

        return database.createStatement();
    
public booleangetAutoCommit()
Delegates to the underlying JDBC connection.

return
the current auto-commit state
throws
java.sql.SQLException a database error occurred

        return database.getAutoCommit();
    
public java.lang.StringgetCatalog()
Delegates to the underlying JDBC connection.

return
the currently selected catalog
throws
java.sql.SQLException a database error occurred

        return database.getCatalog();
    
public java.sql.ConnectiongetConnection()
Provides the connection pooling environment with a logical connection that references this physical connection.

return
the logical connection for use by an application
throws
java.sql.SQLException a database error occurred

        synchronized( listeners ) {
            logical = new LogicalConnection(this);
            return logical;
        }
    
public java.sql.DatabaseMetaDatagetMetaData()
Delegates to the underlying JDBC connection.

return
the meta-data for this connection
throws
java.sql.SQLException a database error occurred

        return database.getMetaData();
    
public intgetTransactionIsolation()
Delegates to the underlying JDBC connection.

return
the current transaction isolation level
throws
java.sql.SQLException a database error occurred

        return database.getTransactionIsolation();
    
public java.util.MapgetTypeMap()
Delegates to the underlying JDBC connection.

return
the current type map
throws
java.sql.SQLException a database error occurred

        return database.getTypeMap();
    
public java.sql.SQLWarninggetWarnings()
Delegates to the underlying JDBC connection.

return
any warnings
throws
java.sql.SQLException a database error occurred

        return database.getWarnings();
    
public booleanisClosed()
Delegates to the underlying JDBC connection, if any.

return
true if there is no udnerlying connection or that connection is closed
throws
java.sql.SQLException a database error occurred

        return (database != null && database.isClosed());
    
public booleanisReadOnly()
Delegates to the underlying JDBC connection.

return
the current read only state
throws
java.sql.SQLException a database error occurred

        return database.isReadOnly();
    
private voidkeepAlive()
This method sits in a loop and keeps the underlying connection alive while the connection is in a pool. It keeps the connection alive by periodically sending:
SELECT 1 to the underlying database.

return
any warnings
throws
java.sql.SQLException a database error occurred

        synchronized( listeners ) {
            boolean closed = false;
            
            do {
                try { listeners.wait(60000); }
                catch( InterruptedException e ) { }
                // only do this if the connection is in the pool
                if( logical == null ) {
                    // if an error occurs while testing
                    // this connection will be removed from the pool
                    if( !test() ) {
                        try { database.close(); }
                        catch( SQLException e ) { }
                        database = null;
                        logical = null;
                        return;
                    }
                }
                try {
                    closed = isClosed();
                }
                catch( SQLException e ) {
                    closed = true;
                }
            } while( !closed );
        }
    
public java.lang.StringnativeSQL(java.lang.String sql)
Delegates to the underlying JDBC connection.

param
sql the ANSI SQL to translate
return
the native SQL for the specified ANSI SQL
throws
java.sql.SQLException a database error occurred

        return database.nativeSQL(sql);
    
public java.sql.CallableStatementprepareCall(java.lang.String sql)
Delegates to the underlying JDBC connection.

param
sql the stored procedure to call
return
the callable statement for the specified stored procedure
throws
java.sql.SQLException a database error occurred

        return database.prepareCall(sql);
    
public java.sql.CallableStatementprepareCall(java.lang.String sql, int rst, int rsc)
Delegates to the underlying JDBC connection.

param
sql the stored procedure to call
param
rst the result set type
param
rsc the result set concurrency
return
the callable statement for the specified stored procedure
throws
java.sql.SQLException a database error occurred

        return database.prepareCall(sql, rst, rsc);
    
public java.sql.PreparedStatementprepareStatement(java.lang.String sql)
Looks in the prepared statement pool for matching SQL and if no match is found prepares a new one.

param
sql the prepared SQL
return
a pooled prepared statement
throws
java.sql.SQLException a database error occurred

        PreparedStatement stmt;
        PooledStatement ps;
        
        synchronized( pool ) {
            if( pool.contains(sql) ) {
                stmt = pool.pop(sql);
            }
            else {
                stmt = database.prepareStatement(sql);
            }
        }
        ps = new PooledStatement(logical, sql, stmt);
        ps.addStatementEventListener(this);
        return ps;
    
public java.sql.PreparedStatementprepareStatement(java.lang.String sql, int rst, int rsc)
Prepares a statement for the specified SQL. If the statement pool contains the specified statement and the result sets should be ResultSet.TYPE_FORWARD_ONLY and ResultSet.CONCUR_READ_ONLY, then the statement is pulled from the pool. A new statement is prepared for all other statements. Scrollable and updateable result sets are not supported in this pooling mechanism.

param
sql the SQL to prepare
param
rst the result set type
param
rsc the result set concurrency
return
the prepared statement for the specified SQL
throws
java.sql.SQLException a database error occurred

        if( rst == ResultSet.TYPE_FORWARD_ONLY ) {
            if( rsc == ResultSet.CONCUR_READ_ONLY ) {
                return prepareStatement(sql);
            }
        }
        return database.prepareStatement(sql);
    
public voidremoveConnectionEventListener(javax.sql.ConnectionEventListener lstnr)
Removes a listener from the list of listeners in accordance with this pooled connection's contract with the pooling environment.

param
lstnr the listener to remove

        synchronized( listeners ) {
            listeners.remove(lstnr);
        }
    
public voidrollback()
Delegates to the underlying JDBC connection.

throws
java.sql.SQLException a database error occurred

        database.rollback();
    
public voidsetAutoCommit(boolean ac)
Delegates to the underlying JDBC connection.

param
ac the auto-commit status to assign
throws
java.sql.SQLException a database error occurred

        database.setAutoCommit(ac);
    
public voidsetCatalog(java.lang.String cat)
Delegates to the underlying JDBC connection.

param
cat the catalog to assign
throws
java.sql.SQLException a database error occurred

        database.setCatalog(cat);
    
public voidsetReadOnly(boolean ro)
Delegates to the underlying JDBC connection.

param
ro the read-only status to assign
throws
java.sql.SQLException a database error occurred

        database.setReadOnly(ro);
    
public voidsetTransactionIsolation(int lvl)
Delegates to the underlying JDBC connection.

param
lvl the transaction isolation level to assign
throws
java.sql.SQLException a database error occurred

        database.setTransactionIsolation(lvl);
    
public voidsetTypeMap(java.util.Map map)
Delegates to the underlying JDBC connection.

param
map the type map to assign
throws
java.sql.SQLException a database error occurred

        database.setTypeMap(map);
    
public voidstatementClosed(StatementEvent evt)
Triggered by a statement when the application closes it so that this connection may return the statement to the statement pool.

param
evt the event triggering the return to the pool
throws
java.sql.SQLException a database error occurred

        synchronized( pool ) {
            pool.push(evt.getSQL(), evt.getStatement());
        }
    
private booleantest()
Tests the connection to see if it is still up. If not, it notifies the pooling environment that this connection is no longer valid.

        Statement stmt = null;

        try {
            stmt = database.createStatement();
            stmt.executeQuery("SELECT 1");
            return true;
        }
        catch( SQLException e ) {
            connectionErrored(e);
            return false;
        }
        finally {
            if( stmt != null ) {
                try { stmt.close(); }
                catch( SQLException e ) { }
            }
        }
    
public java.lang.StringtoString()

        if( database != null ) {
            return super.toString() + " [" + database.toString() + "]";
        }
        else {
            return super.toString();
        }