All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.ibm.as400.access.AS400JDBCPooledConnection Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
//                                                                             
// JTOpen (IBM Toolbox for Java - OSS version)                                 
//                                                                             
// Filename: AS400JDBCPooledConnection.java
//                                                                             
// The source code contained herein is licensed under the IBM Public License   
// Version 1.0, which has been approved by the Open Source Initiative.         
// Copyright (C) 1997-2003 International Business Machines Corporation and     
// others. All rights reserved.                                                
//                                                                             
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener;
import javax.sql.PooledConnection;
/* ifdef JDBC40 
import javax.sql.StatementEventListener;
endif */ 

import java.sql.Connection;
import java.sql.SQLException;
import java.lang.ref.SoftReference;

/**
*  The AS400JDBCPooledConnection class represents a connection object
*  that provides hooks for connection pool management. This object is returned
*  by the {@link com.ibm.as400.access.AS400JDBCConnectionPoolDataSource#getPooledConnection AS400JDBCConnectionPoolDataSource.getPooledConnection()} method.
*
*  The following example creates an AS400JDBCPooledConnection object that can be used to cache JDBC connections.
*
*  
*  // Create a data source for making the connection.
*  AS400JDBCConnectionPoolDataSource dataSource = new AS400JDBCConnectionPoolDataSource("myAS400");
*  datasource.setUser("Mickey Mouse");
*  datasource.setPassword("IAMNORAT");
*
*  // Get a PooledConnection and get the connection handle to the database.
*  AS400JDBCPooledConnection pooledConnection = datasource.getPooledConnection();
*  Connection connection = pooledConnection.getConnection();
*
*  ... work with the connection handle.
*
*  // Close the connection handle to make available for reuse (physical connection not closed).
*  connection.close();
*
*  // Reuse the connection somewhere else.
*  Connection reusedConnection = pooledConnection.getConnection();
*  ... work with the connection handle.
*  reusedConnection.close();
*
*  // Close the physical connection.
*  pooledConnection.close();  
*  
* *

* AS400JDBCPooledConnection objects generate the following events: *

    *
  • javax.sql.ConnectionEvent - The events fired are: *
      *
    • connectionClosed
    • *
    • connectionErrorOccurred
    • *
    *
  • *
**/ public class AS400JDBCPooledConnection implements PooledConnection { static final String copyright = "Copyright (C) 1997-2010 International Business Machines Corporation and others."; private AS400JDBCConnection connection_; // The database connection. //@CRS - If we maintain a [direct] reference to the handle, and the user doesn't call close(), it // will never get closed because it will never get garbage collected. // Instead, we are a listener to the handle, so we know when either the user or the // garbage collector closes it. At that point, this PooledConnection is no longer // considered "in use" and can hand out a new handle when someone calls getConnection(). //@pda (bug reported) A AS400JDBCPooledConnection can get expired and moved back to available queue. So this // handle class needs a way for AS400JDBCPooledConnection to notify it of this change in state. // This way, when finalize() is called by GC we will not try to double-close the connection. // Without this method, it is possible for two handles to have references to the same pooledConnection. // After we are done with handle_, we must set it to null, so AS400JDBCConnectionHandle can be GCed. // In order for the handle to be GCed, a leaked connection has to be Expired and have handle_ set to null // upon returning to available queue. private SoftReference handle_; // The handle to the connection. //@pdc make use of reference to handle // This is a soft reference to an AS400JDBCConnectionHandle object. // DESIGN NOTE: // We use a soft reference (rather than a direct reference) in order to avoid // having circular/mutual direct references between the handle and the connection. // In some scenarios, such circular references can prevent such pairs of objects // from being garbage-collected; which can result in memory leaks. // Advantage of a soft reference: If the connection requester gives up their // reference to the handle but neglects to call close() first, // then the only remaining reference to the handle is the soft reference // from the associated AS400JDBCPooledConnection. // The garbage collector will then notice that the only reference to the handle // is a soft reference; and the GC will then collect/remove the handle. private PoolItemProperties properties_; // The usage properties. private AS400JDBCConnectionEventSupport eventManager_; private int hashCode_; //@CPMa // The following fields are reserved for use by JDConnectionPoolManager. //@CPMa JDConnectionPoolKey poolKey_; // connection-pool key for this connection long timeWhenCreated_; // time when this connection was created. long timeWhenPoolStatusLastModified_; // time when this connection's pooling status last changed. boolean fatalConnectionErrorOccurred_; // this clues the pool manager not to reuse connection // @L16A private boolean defaultAutoCommit_; private int defaultTransactionIsolation_; private int defaultHoldability_; private String defaultSchema_; private boolean defaultReadOnly_; /** * Constructs an AS400JDBCPooledConnection object. * @param connection The physical connection to be pooled. * @exception SQLException If a database error occurs. **/ AS400JDBCPooledConnection(Connection connection) throws SQLException { if (connection == null) throw new NullPointerException("connection"); connection_ = (AS400JDBCConnection)connection; // Save default settings for several changeable properties @L16A defaultAutoCommit_ = connection_.getAutoCommit(); defaultTransactionIsolation_ = connection_.getTransactionIsolation(); defaultHoldability_ = connection_.getInternalHoldability(); defaultSchema_ = connection_.getSchema(); if ("*LIBL".equals(defaultSchema_)) { defaultSchema_="DEFAULT"; } defaultReadOnly_ = connection_.getReadOnly(); properties_ = new PoolItemProperties(); eventManager_ = new AS400JDBCConnectionEventSupport(); hashCode_ = connection_.hashCode(); timeWhenCreated_ = System.currentTimeMillis(); if (JDTrace.isTraceOn()) //@G2A { JDTrace.logInformation(this, "A new AS400JDBCPooledConnection was created"); //@G2A } } /** * Adds a ConnectionEventListener. * @param listener The listener. **/ public void addConnectionEventListener(ConnectionEventListener listener) { eventManager_.addConnectionEventListener(listener); } /** * Closes the physical connection. * @exception SQLException If an error occurs closing the connection. **/ public synchronized void close() throws SQLException { if (connection_.isClosed()) return; // Note: AS400JDBCConnectionHandle.close() calls fireConnectionCloseEvent(). connection_.close(); // close the physical connection // Reset the usage timers. properties_.clear(); if (JDTrace.isTraceOn()) { //@G2C JDTrace.logInformation(this, "close() was called on this AS400JDBCPooledConnection"); //@G2C } } //@G4A JDBC 3.0 /** * Closes all the Statement objects that have been opened by this PooledConnection * object. This method is not supported. * @exception SQLException Always thrown because this method is not supported. **/ public void closeAll() throws SQLException { JDError.throwSQLException(JDError.EXC_FUNCTION_NOT_SUPPORTED); } // JDConnectionPoolManager needs this when identifying returned connections. public boolean equals(Object obj) { if (obj == null) return false; try { AS400JDBCPooledConnection pc = (AS400JDBCPooledConnection)obj; return (connection_.equals(pc.connection_)); } catch (Throwable e) { return false; } } // Needed for good hashing. public int hashCode() { return hashCode_; } // Note: The following method is called by AS400JDBCConnectionHandle.close(). /** * Fire the connection closed event. * @param event The ConnectionEvent. **/ void fireConnectionCloseEvent(ConnectionEvent event) { if (JDTrace.isTraceOn()) { JDTrace.logInformation(this, "fireConnectionCloseEvent("+event+")"); } returned(); // Reset the pooledConnection. if (JDTrace.isTraceOn()) { JDTrace.logInformation(this, "fireConnectionCloseEvent() calling eventManager_.fireCloseEvent"); } eventManager_.fireCloseEvent(event); // Notify the pool. } // Note: The following method is called by AS400JDBCConnectionHandle.close(). /** * Fire the connection error event. * @param event The ConnectionEvent. **/ void fireConnectionErrorEvent(ConnectionEvent event) { // Don't bother cleaning up the connection, it won't get re-used. eventManager_.fireErrorEvent(event); // Notify the pool. } /** * Returns the connection handle to the database. Only one connection handle can be open * at a time for any given AS400JDBCPooledConnection object. * @return The connection handle. * @exception SQLException If a database error occurs or if this PooledConnection is already in use. **/ public synchronized Connection getConnection() throws SQLException { if (JDTrace.isTraceOn()) //@G2C { JDTrace.logInformation(this, "AS400JDBCPooledConnection.getConnection() was called"); //@G2C } return getConnectionHandle(); } // Used by JDConnectionPoolManager. //@CPMa /** * Returns the connection handle to the database. Only one connection handle can be open * at a time for any given AS400JDBCPooledConnection object. * @return The connection handle. * @exception SQLException If a database error occurs or if this PooledConnection is already in use. **/ synchronized final AS400JDBCConnectionHandle getConnectionHandle() throws SQLException { if (connection_.isClosed()) { if (JDTrace.isTraceOn()) // @G2A { JDTrace.logInformation(this, "This AS400JDBCPooledConnection is invalid because connection is closed."); // @G2A } JDError.throwSQLException(this, JDError.EXC_CONNECTION_NONE); //@G2A } // Note: The JDBC Tutorial says that if PooledConnection.getConnection() is called while already in use, this should close the existing connection. "The purpose of allowing the server to invoke the method getConnection a 2nd time is to give the application server a way to take a connection away from an application and give it to someone else. This will probably rarely happen, but the capability is there." // However, we haven't had a request for this behavior, so we just throw an exception instead. if (isInUse()) { if (JDTrace.isTraceOn()) { JDTrace.logInformation(this, "This AS400JDBCPooledConnection is already in use."); } JDError.throwSQLException(this, JDError.EXC_CONNECTION_UNABLE); // Is this the right thing to throw here? } // Start the connection tracking timers. setInUse(true); AS400JDBCConnectionHandle handle = new AS400JDBCConnectionHandle(this, connection_); //@pdc handle handle_ = new SoftReference(handle); return handle; //@pda handle } // For exclusive use by JDConnectionPoolManager. //@CPMa final JDConnectionPoolKey getPoolKey() { return poolKey_; } AS400JDBCConnection getInternalConnection() //@G1A { //@G1A return connection_; //@G1A } //@G1A /** * Returns the elapsed time the connection has been idle waiting in the pool. * @return The idle time (milliseconds). **/ public long getInactivityTime() { return properties_.getInactivityTime(); } /** * Returns the elapsed time the connection has been in use. * @return The elapsed time (milliseconds). **/ public long getInUseTime() { return properties_.getInUseTime(); } /** * Returns the elapsed time the pooled connection has been alive. * @return The elapsed time (milliseconds). **/ public long getLifeSpan() { return properties_.getLifeSpan(); } /** * Returns the number of times the pooled connection has been used. * @return The number of times used. **/ public int getUseCount() { return properties_.getUseCount(); } /** * Ping the connection to check the status. * @return true if the connection is active; false otherwise. **/ boolean isConnected() throws SQLException // @A3A { return connection_.getAS400().isConnected(AS400.DATABASE); } /** * Determine whether the connection is still alive. * @return true if the connection is alive; false otherwise. **/ boolean isConnectionAlive() throws SQLException { return connection_.getAS400().isConnectionAlive(AS400.DATABASE); } /** * Indicates if the pooled connection is in use. * @return true if the pooled connection is in use; false otherwise. **/ public boolean isInUse() { return properties_.isInUse(); } /** * Removes a ConnectionEventListener. * @param listener The listener to be removed. **/ public void removeConnectionEventListener(ConnectionEventListener listener) { eventManager_.removeConnectionEventListener(listener); } /** * Returns the connection after usage. * Update the connection timers and invalidate connection handle. **/ synchronized void returned() { if (JDTrace.isTraceOn()) //@G2C { JDTrace.logInformation(this, "returned() This AS400JDBCPooledConnection is being returned."); //@G2C } // Reset the timers. setInUse(false); try { //@CPMa connection_.clearWarnings(); // This seems safe and reasonable enough. // @L16A connection_.setAutoCommit(defaultAutoCommit_); connection_.setTransactionIsolation(defaultTransactionIsolation_); connection_.setHoldability(defaultHoldability_); try { connection_.setSchema(defaultSchema_); } catch (Exception e) { // Ignore errors on setSchema. If this code // cannot set the schema, then other code // code not set the schema. } connection_.setReadOnly(defaultReadOnly_); if (handle_ != null) //@pda handle { AS400JDBCConnectionHandle handle = (AS400JDBCConnectionHandle)handle_.get(); if (handle != null) { handle.invalidate(); //@pda Invalidate the handle. // So if this pooledConnection gets expired then also need to invalidate handle (remove reference from handle to pooledConnection). //if the handle gets GCed (due to connection leak), then handle.finalize() will not try to close this pooledConnection, which could have been already assigned to a new handle. //(ie prevent two handles from pointing to one pooledConnection) } handle_ = null; //remove reference also, so handle is free for GC. } } catch (SQLException e) { JDTrace.logException(this, "Exception while resetting properties of returned connection.", e); } // Note: We can assume that if the connection has been used and then returned to the pool, it has been sufficiently cleaned-up/reset by AS400JDBCConnectionHandle.close(), which calls AS400JDBCConnection.pseudoClose(), which does any needed rollbacks and/or statement closing. //@CPMa } /** * Sets the connection timer values based on the active usage state of the connection. * @param inUse true if the connection is currently active; false otherwise. **/ synchronized void setInUse(boolean inUse) { properties_.setInUse(inUse); } // For exclusive use by JDConnectionPoolManager. //@CPMa final void setPoolKey(JDConnectionPoolKey key) { poolKey_ = key; } //@PDA jdbc40 //JDBC40DOC /** //JDBC40DOC * Registers a StatementEventListener with this PooledConnection object. Components that //JDBC40DOC * wish to be notified when PreparedStatements created by the //JDBC40DOC * connection are closed or are detected to be invalid may use this method //JDBC40DOC * to register a StatementEventListener with this PooledConnection object. //JDBC40DOC *

//JDBC40DOC * @param listener an component which implements the StatementEventListener //JDBC40DOC * interface that is to be registered with this PooledConnection object //JDBC40DOC */ /* ifdef JDBC40 public void addStatementEventListener(StatementEventListener listener) { //Currently toolbox does not have a pooledStatemnt. //Method can not throw SQLException in current driver //For now just do nothing in this method. if (JDTrace.isTraceOn()) //@G2C { JDTrace.logInformation(this, "AS400JDBCPooledConnection.addStatementEventListener is called, but is N/A."); } } endif */ //@PDA jdbc40 //JDBC40DOC /** //JDBC40DOC * Removes the specified StatementEventListener from the list of //JDBC40DOC * components that will be notified when the driver detects that a //JDBC40DOC * PreparedStatement has been closed or is invalid. //JDBC40DOC *

//JDBC40DOC * @param listener the component which implements the //JDBC40DOC * StatementEventListener interface that was previously //JDBC40DOC * registered with this PooledConnection object //JDBC40DOC */ /* ifdef JDBC40 public void removeStatementEventListener(StatementEventListener listener) { //Method can not throw SQLException //For now just do nothing if (JDTrace.isTraceOn()) //@G2C { JDTrace.logInformation(this, "AS400JDBCPooledConnection.removeStatementEventListener is called, but is N/A."); } } endif */ }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy