You are on page 1of 36

///////////////////////////////////////////////////////////////////////////////

//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: AS400ConnectionPool.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.
//
///////////////////////////////////////////////////////////////////////////////
// @C1 - 2008-06-06 - Added support for ProfileTokenCredential authentication.
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

import com.ibm.as400.security.auth.ProfileTokenCredential;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Vector;
import java.util.Enumeration;
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;

/**
* Manages a pool of AS400 objects. A connection pool is used to
* share connections and manage the number of connections a user can have to the
system.
* <p>
* A connection is defined by a systemName, userID, and an optional password
and/or service.
* Services should be referred to using constants from the AS400 class
* (FILE, PRINT, COMMAND, DATAQUEUE, etc.)
* <p>
* When a connection
* is requested, a fully functional AS400 object is returned to the calling
application.
* It is then
* up to the application to return the AS400 object to the pool. It is not
recommended
* that an application use this object to create additional connections
* as the pool would not keep track of these connections.
* <p>
* The AS400ConnectionPool class keeps track of the number of connections it
creates.
* The user can set the maximum number of connections that can be given out by a
* pool. If the maximum number of connections has already been given out when an
* additional connection is requested, an exception is thrown.
* <p>
* Note: AS400ConnectionPool objects are threadsafe.
* <p>
* This example creates an AS400ConnectionPool with a limit of 128 connections:
*
* <BLOCKQUOTE><PRE>
* // Create an AS400ConnectionPool.
* AS400ConnectionPool testPool = new AS400ConnectionPool();
* // Set a maximum of 128 connections to this pool.
* testPool.setMaxConnections(128);
* // Preconnect 5 connections to the AS400.COMMAND service.
* testPool.fill("myAS400", "myUserID", "myPassword", AS400.COMMAND, 5);
* // Create a connection to the AS400.COMMAND service. (Use the service number
constants
* // defined in the AS400 class (FILE, PRINT, COMMAND, DATAQUEUE, etc.))
* AS400 newConn = testPool.getConnection("myAS400", "myUserID", "myPassword",
AS400.COMMAND);
* // Create a new command call object and run a command.
* CommandCall cmd = new CommandCall(newConn);
* cmd.run("CRTLIB FRED");
* // Return the connection to the pool.
* testPool.returnConnectionToPool(newConn);
* // Close the test pool.
* testPool.close();
* </PRE></BLOCKQUOTE>
*
* <P>AS400ConnectionPool objects generate the following events:
* <ul>
* <li><a href="ConnectionPoolEvent.html">ConnectionPoolEvent</a> - The events
fired are:
* <ul>
* <li>CONNECTION_CREATED</li>
* <li>CONNECTION_EXPIRED</li>
* <li>CONNECTION_POOL_CLOSED</li>
* <li>CONNECTION_RELEASED</li>
* <li>CONNECTION_RETURNED</li>
* <li>MAINTENANCE_THREAD_RUN</li>
* </ul>
* </li>
* <li>PropertyChangeEvent</li>
* </ul>
**/
public class AS400ConnectionPool extends ConnectionPool implements Serializable
{
static final long serialVersionUID = 4L;

/**
Indicates that the CCSID used for new connections is the same as the system
default CCSID.
**/
public static final int CCSID_DEFAULT = ConnectionPool.CCSID_DEFAULT;

private transient Hashtable as400ConnectionPool_;


// Hashtable of lists of connections that have been marked invalid by the user
// by calling removeFromPool().
private transient Hashtable removedAS400ConnectionPool_; //@A6A
private transient Log log_;
private SocketProperties socketProperties_;
private transient long lastRun_=0; //@D1A Last time cleanupConnections() was
called. Added for fix to JTOpen Bug #3863
private transient boolean connectionHasBeenCreated_ = false;

// Handles loading the appropriate resource bundle


//@CRS private static ResourceBundleLoader loader_;
/**
* Constructs an AS400ConnectionPool with default ConnectionPoolProperties.
**/
public AS400ConnectionPool()
{
super();
initializeTransient();
}

/**
* Remove any connections that have exceeded maximum inactivity time, replace any

* that have aged past maximum usage or maximum lifetime, and remove any that
have
* been in use too long.
*
* @see ConnectionPoolProperties
**/
void cleanupConnections()
{
synchronized (as400ConnectionPool_)
{
Enumeration keys = as400ConnectionPool_.keys();
while (keys.hasMoreElements())
{
String key = (String)keys.nextElement();
try
{
ConnectionList connList = (ConnectionList)as400ConnectionPool_.get(key);
connList.removeExpiredConnections(poolListeners_);
}
catch (Exception e)
{
log(e, key);
}
}
}
if (poolListeners_ != null)
{
ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this,
ConnectionPoolEvent.MAINTENANCE_THREAD_RUN);
poolListeners_.fireMaintenanceThreadRun(poolEvent);
}
lastRun_ = System.currentTimeMillis(); //@D1A
}

/**
* Close and cleanup the connection pool.
**/
public void close()
{
log(ResourceBundleLoader.getText("AS400CP_SHUTDOWN"));
synchronized (as400ConnectionPool_)
{
Enumeration keys = as400ConnectionPool_.keys();
while (keys.hasMoreElements())
{
String key = (String)keys.nextElement();
ConnectionList connList = (ConnectionList)as400ConnectionPool_.get(key);
connList.close();
}
as400ConnectionPool_.clear();
}

// Terminate the maintenance thread, if it's still alive.


if (maintenance_ != null && maintenance_.isAlive()) {
maintenance_.shutdown(); // tell the thread to terminate
}

if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(this,
ConnectionPoolEvent.CONNECTION_POOL_CLOSED);
poolListeners_.fireClosedEvent(event);
}
log(ResourceBundleLoader.getText("AS400CP_SHUTDOWNCOMP"));
}

/**
* Create a key to use to access the connections hashtable.
*
* @param systemName The name of the system being queried.
* @param userID The name of the user.
* @return The key to use for the hashtable.
**/
private String createKey(String systemName, String userID)
{
systemName = systemName.trim();
userID = userID.trim();
return systemName.toUpperCase() + "/" + userID.toUpperCase();
}

/**
* Preconnects a specified number of connections to a specific system, userID,
* profileToken, and service.
*
* @param systemName The name of the system where the connections should exist.
* @param userID The name of the user.
* @param profileToken The profile token to use to authenticate to the system.
* @param service The service to be connected. See the service number constants
defined by AS400 class.
* @param numberOfConnections The number of connections to be made.
*
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public void fill(String systemName, String userID, ProfileTokenCredential
profileToken, int service, int numberOfConnections) //@C1A
throws ConnectionPoolException
{
fill(systemName, userID, profileToken, service, numberOfConnections, null);
}

/**
* Preconnects a specified number of connections to a specific system, userID,
* profileToken, service, and Locale.
*
* @param systemName The name of the system where the connections should exist.
* @param userID The name of the user.
* @param profileToken The profile token to use to authenticate to the system.
* @param service The service to be connected. See the service number constants
defined by AS400 class.
* @param numberOfConnections The number of connections to be made.
* @param locale The Locale used to set the National Language Version (NLV) on
the system for the AS400 objects
* created. Only the COMMAND, PRINT, and DATABASE services accept an NLV.
*
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public void fill(String systemName, String userID, ProfileTokenCredential
profileToken, int service, int numberOfConnections, Locale locale) //@C1A
throws ConnectionPoolException
{
if (numberOfConnections < 1)
throw new ExtendedIllegalArgumentException("numberOfConnections",
ExtendedIllegalArgumentException.RANGE_NOT_VALID);
Vector newAS400Connections = new Vector();
if (Trace.traceOn_)
log(Trace.INFORMATION, "fill() key before resolving= " + systemName + "/" +
userID);
systemName = AS400.resolveSystem(systemName);
userID = AS400.resolveUserId(userID.toUpperCase()); //@KBA
String key = createKey(systemName, userID);
if (Trace.traceOn_)
log(Trace.INFORMATION, "fill() key after resolving= " + key);
try
{
ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);
if (log_ != null || Trace.traceOn_)

log(ResourceBundleLoader.substitute(ResourceBundleLoader.getText("AS400CP_FILLING")
, new String[] { (new Integer(numberOfConnections)).toString(),
systemName, userID} ));
// create the specified number of connections
for (int i = 0; i < numberOfConnections; i++)
{
newAS400Connections.addElement(getConnection(systemName, userID, service,
true, false, locale, profileToken));
// Note: When filling an empty pool, getConnection() creates a new element
and adds it to pool.
}
connections = (ConnectionList)as400ConnectionPool_.get(key);
for (int j = 0; j < numberOfConnections; j++)
{

connections.findElement((AS400)newAS400Connections.elementAt(j)).setInUse(false);
}
if (Trace.traceOn_ && locale != null)
log(Trace.INFORMATION, "Created " + numberOfConnections + "with a
locale.");
}
catch (AS400SecurityException e)
{
// If exception occurs, stop creating connections, run maintenance thread,
and
// throw whatever exception was received on creation to user.
ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);
for (int k = 0; k < newAS400Connections.size(); k++)
{

connections.findElement((AS400)newAS400Connections.elementAt(k)).setInUse(false);
}
if (maintenance_ != null && maintenance_.isRunning())
cleanupConnections();
log(ResourceBundleLoader.getText("AS400CP_FILLEXC"));
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
// If exception occurs, stop creating connections, run maintenance thread,
and
// throw whatever exception was received on creation to user.

ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);

for (int k = 0; k < newAS400Connections.size(); k++)


{

connections.findElement((AS400)newAS400Connections.elementAt(k)).setInUse(false);
}
if (maintenance_ != null && maintenance_.isRunning())
cleanupConnections();
log(ResourceBundleLoader.getText("AS400CP_FILLEXC"));
throw new ConnectionPoolException(ie);
}
}

/**
* Preconnects a specified number of connections to a specific system, userID,
* password, and service.
*
* @param systemName The name of the system where the connections should exist.
* @param userID The name of the user.
* @param password The password of the user.
* @param service The service to be connected. See the service number constants
defined by AS400 class.
* @param numberOfConnections The number of connections to be made.
*
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public void fill(String systemName, String userID, String password, int service,
int numberOfConnections)
throws ConnectionPoolException
{
fill(systemName, userID, password, service, numberOfConnections, null);
}

//@B3A
/**
* Preconnects a specified number of connections to a specific system, userID,
* password, service, and Locale.
*
* @param systemName The name of the system where the connections should exist.
* @param userID The name of the user.
* @param password The password of the user.
* @param service The service to be connected. See the service number constants
defined by AS400 class.
* @param numberOfConnections The number of connections to be made.
* @param locale The Locale used to set the National Language Version (NLV) on
the system for the AS400 objects
* created. Only the COMMAND, PRINT, and DATABASE services accept an NLV.
*
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public void fill(String systemName, String userID, String password, int service,
int numberOfConnections, Locale locale)
throws ConnectionPoolException
{
if (numberOfConnections < 1)
throw new ExtendedIllegalArgumentException("numberOfConnections",
ExtendedIllegalArgumentException.RANGE_NOT_VALID);
Vector newAS400Connections = new Vector();
if (Trace.traceOn_)
log(Trace.INFORMATION, "fill() key before resolving= " + systemName + "/" +
userID);
systemName = AS400.resolveSystem(systemName);
userID = AS400.resolveUserId(userID.toUpperCase()); //@KBA
String key = createKey(systemName, userID);
if (Trace.traceOn_)
log(Trace.INFORMATION, "fill() key after resolving= " + key);
try
{
ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);
if (log_ != null || Trace.traceOn_)

log(ResourceBundleLoader.substitute(ResourceBundleLoader.getText("AS400CP_FILLING")
, new String[] { (new Integer(numberOfConnections)).toString(),
systemName, userID} ));
// create the specified number of connections
//@B4D AS400.addPasswordCacheEntry(systemName, userID, password);
for (int i = 0; i < numberOfConnections; i++)
{
newAS400Connections.addElement(getConnection(systemName, userID, service,
true, false, locale, password)); //@B4C
// Note: When filling an empty pool, getConnection() creates a new element
and adds it to pool.
}
connections = (ConnectionList)as400ConnectionPool_.get(key);
for (int j = 0; j < numberOfConnections; j++)
{

connections.findElement((AS400)newAS400Connections.elementAt(j)).setInUse(false);
}
if (Trace.traceOn_ && locale != null)
log(Trace.INFORMATION, "Created " + numberOfConnections + "with a
locale.");
}
catch (AS400SecurityException e)
{
// If exception occurs, stop creating connections, run maintenance thread,
and
// throw whatever exception was received on creation to user.
ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);
for (int k = 0; k < newAS400Connections.size(); k++)
{

connections.findElement((AS400)newAS400Connections.elementAt(k)).setInUse(false);
}
if (maintenance_ != null && maintenance_.isRunning())
cleanupConnections();
log(ResourceBundleLoader.getText("AS400CP_FILLEXC"));
throw new ConnectionPoolException(e);
}
catch (IOException ie) //@A2A
{
//@A2A
// If exception occurs, stop creating connections, run maintenance thread,
and
// throw whatever exception was received on creation to user.

ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);

for (int k = 0; k < newAS400Connections.size(); k++)


{ //@A2A

connections.findElement((AS400)newAS400Connections.elementAt(k)).setInUse(false);
} //@A2A
if (maintenance_ != null && maintenance_.isRunning())
cleanupConnections(); //@A2A

log(ResourceBundleLoader.getText("AS400CP_FILLEXC")); //@A2A
throw new ConnectionPoolException(ie); //@A2A
} //@A2A
}

/**
* Closes the connection if not explicitly closed by the caller.
*
* @exception Throwable If an error occurs.
**/
protected void finalize ()
throws Throwable
{
close();

super.finalize ();
}

/**
* Get the number of active (in-use) connections to a system.
* Note: The value returned is based only on systemName and userID, and does not
* reflect the authentication scheme (e.g. password, profile token).
*
* @param systemName The name of the system where the connections exist.
* @param userID The name of the user.
* @return The number of connections that are currently in use.
**/
public int getActiveConnectionCount(String systemName, String userID)
{
if (systemName == null)
throw new NullPointerException("systemName");
if (userID == null)
throw new NullPointerException("userID");
systemName = AS400.resolveSystem(systemName); //@A5A
userID = AS400.resolveUserId(userID.toUpperCase()); //@A5A //@KBA
String key = createKey(systemName, userID);
if (Trace.traceOn_) //@A5A
log(Trace.INFORMATION, "getActiveConnectionCount key= " + key); //@A5A
ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);
if (connections == null)
{
if (Trace.traceOn_) //@A5A
log(Trace.WARNING, "getActiveConnectionCount found no " + key + " list in
the pool"); //@A5A
return 0;
}
return(connections.getActiveConnectionCount());
}

/**
* Get the number of available connections to a system.
* Note: The value returned is based only on systemName and userID, and does not
* reflect the authentication scheme (e.g. password, profile token).
*
* @param systemName The name of the system where the connections exist.
* @param userID The name of the user.
* @return The number of connections that are not currently in use.
**/
public int getAvailableConnectionCount(String systemName, String userID)
{
if (systemName == null)
throw new NullPointerException("systemName");
if (userID == null)
throw new NullPointerException("userID");
systemName = AS400.resolveSystem(systemName); //@A5A
userID = AS400.resolveUserId(userID.toUpperCase()); //@A5A //@KBA
String key = createKey(systemName, userID);
if (Trace.traceOn_) //@A5A
log(Trace.INFORMATION, "getAvailableConnectionCount key= " + key); //@A5A
ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);
if (connections == null)
{
if (Trace.traceOn_) //@A5A
log(Trace.WARNING, "getAvailableConnectionCount found no " + key + " list
in the pool"); //@A5A
return 0;
}
return connections.getAvailableConnectionCount();
}

/**
* Returns the CCSID that is used when creating new connections.
* The default value is the system default CCSID as determined by the AS400
class.
* @return The CCSID, or {@link #CCSID_DEFAULT CCSID_DEFAULT} if the system
default CCSID is used.
**/
public int getCCSID()
{
return super.getCCSID();
}

/**
* Get a connected AS400 object from the connection pool. If an appropriate one
is
* not found, one is created. If the maximum connection limit has been reached,
an exception
* will be thrown.
* Note that the password is validated only when creating a <b>new</b>
connection,
* of the match criteria to pull a connection out of the pool. This means that
* if an <b>existing</b> connection in the pool matches the systemName and userID

* passed in, a connection will be returned without the password being validated.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param password The password of the user.
* @param service The service to connect. See the service number constants
defined by AS400 class.
* @return A connected AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getConnection(String systemName, String userID, String password, int
service)
throws ConnectionPoolException
{
try
{
//@B4D AS400.addPasswordCacheEntry(systemName, userID, password);
AS400 releaseConnection = getConnection(systemName, userID, service, true,
false, null, password); //@B3C add null locale //@B4C
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED); //@A7C
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

//@B3A
/**
* Get a connected AS400 object from the connection pool with the specified
Locale. If an appropriate one is
* not found, one is created. If the maximum connection limit has been reached,
an exception
* will be thrown.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param password The password of the user.
* @param service The service to connect. See the service number constants
defined by AS400 class.
* @param locale The Locale used to set the National Language Version (NLV)
on the system for the AS400 object returned.
* Only the COMMAND, PRINT, and DATABASE services accept an NLV.
* @return A connected AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getConnection(String systemName, String userID, String password, int
service, Locale locale)
throws ConnectionPoolException
{
try
{
//@B4D AS400.addPasswordCacheEntry(systemName, userID, password);
AS400 releaseConnection = getConnection(systemName, userID, service, true,
false, locale, password); //@B4C
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED);
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

/**
* Get a connected AS400 object from the connection pool. If an appropriate one
is
* not found, one is created. If the maximum connection limit has been reached,
an exception
* will be thrown.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param service The service to connect. See the service number constants
defined by AS400 class.
* @return A connected AS400 object.
* @exception ConnectionPoolException Always thrown because this method has
been deprecated.
* @deprecated Use getConnection(String systemName, String userID, String
password, int service) instead.
**/
public AS400 getConnection(String systemName, String userID, int service)
throws ConnectionPoolException
{
//@B4D try
//@B4D {
//@B4D AS400 releaseConnection = getConnection(systemName, userID, service,
true, false, null); //@B3C add null locale
//@B4D ConnectionPoolEvent event = new
ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED); //@A7C
//@B4D poolListeners_.fireConnectionReleasedEvent(event);
//@B4D return releaseConnection;
//@B4D }
//@B4D catch (AS400SecurityException e)
//@B4D {
//@B4D throw new ConnectionPoolException(e);
//@B4D }
//@B4D catch (IOException ie)
//@B4D {
//@B4D throw new ConnectionPoolException(ie);
//@B4D }
throw new ConnectionPoolException(new
ExtendedIOException(ExtendedIOException.REQUEST_NOT_SUPPORTED)); //@B4A
}

/**
* Get an AS400 object from the connection pool. If an appropriate one is not
found,
* one is created. If the maximum connection limit has been reached, an
exception
* will be thrown. The AS400 object may not be connected to any services.
* Note that the password is validated only when creating a <b>new</b>
connection,
* of the match criteria to pull a connection out of the pool. This means that
* if an <b>existing</b> connection in the pool matches the systemName and userID

* passed in, a connection will be returned without the password being validated.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param password The password of the user.
* @return An AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getConnection(String systemName, String userID, String password)
throws ConnectionPoolException
{
try
{
//@B4D AS400.addPasswordCacheEntry(systemName, userID, password);
AS400 releaseConnection = getConnection(systemName, userID, 0, false, false,
null, password); //@B3C add null locale //@B4C
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED); //@A7C
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

//@B3A
/**
* Get an AS400 object from the connection pool with the specified Locale. If an
appropriate one is not found,
* one is created. If the maximum connection limit has been reached, an
exception
* will be thrown. The AS400 object may not be connected to any services.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param password The password of the user.
* @param locale The Locale used to set the National Language Version (NLV)
on the system for the AS400 object returned.
* Only the COMMAND, PRINT, and DATABASE services accept an NLV.
* @return An AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getConnection(String systemName, String userID, String password,
Locale locale)
throws ConnectionPoolException
{
try
{
//@B4D AS400.addPasswordCacheEntry(systemName, userID, password);
AS400 releaseConnection = getConnection(systemName, userID, 0, false, false,
locale, password); //@B4C
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED);
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}
/**
* Get an AS400 object from the connection pool. If an appropriate one is not
found,
* one is created. If the maximum connection limit has been reached, an
exception
* will be thrown. The AS400 object may not be connected to any services.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @return An AS400 object.
* @exception ConnectionPoolException Always thrown because this method has been
deprecated.
* @deprecated Use getConnection(String systemName, String userID, String
password) instead.
**/
public AS400 getConnection(String systemName, String userID)
throws ConnectionPoolException
{
//@B4D try
//@B4D {
//@B4D AS400 releaseConnection = getConnection(systemName, userID, 0,
false, false, null); //@B3C add null locale
//@B4D releaseConnection.getVRM();
//@B4D ConnectionPoolEvent event = new
ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED); //@A7C
//@B4D poolListeners_.fireConnectionReleasedEvent(event);
//@B4D return releaseConnection;
//@B4D }
//@B4D catch (AS400SecurityException ae)
//@B4D {
//@B4D throw new ConnectionPoolException(ae);
//@B4D }
//@B4D catch (IOException ie)
//@B4D {
//@B4D throw new ConnectionPoolException(ie);
//@B4D }
throw new ConnectionPoolException(new
ExtendedIOException(ExtendedIOException.REQUEST_NOT_SUPPORTED)); //@B4A
}

/**
* Get a connected AS400 object from the connection pool. If an appropriate one
is
* not found, one is created. If the maximum connection limit has been reached,
an exception
* will be thrown.
* Note that the profileTokenCredential is validated only when creating a
<b>new</b>
* connection, of the match criteria to pull a connection out of the pool. This
means
* that if an <b>existing</b> connection in the pool matches the systemName and
* userID passed in, a connection will be returned without the
profileTokenCredential
* being validated.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param profileToken The profile token to use to authenticate to the system.
* @param service The service to connect. See the service number constants
defined by AS400 class.
* @return A connected AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getConnection(String systemName, String userID,
ProfileTokenCredential profileToken, int service) //@C1A
throws ConnectionPoolException
{
try
{
AS400 releaseConnection = getConnection(systemName, userID, service, true,
false, null, profileToken);
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED);
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

/**
* Get a connected AS400 object from the connection pool with the specified
Locale. If an appropriate one is
* not found, one is created. If the maximum connection limit has been reached,
an exception
* will be thrown.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param profileToken The profile token to use to authenticate to the system.
* @param service The service to connect. See the service number constants
defined by AS400 class.
* @param locale The Locale used to set the National Language Version (NLV)
on the system for the AS400 object returned.
* Only the COMMAND, PRINT, and DATABASE services accept an NLV.
* @return A connected AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getConnection(String systemName, String userID,
ProfileTokenCredential profileToken, int service, Locale locale) //@C1A
throws ConnectionPoolException
{
try
{
AS400 releaseConnection = getConnection(systemName, userID, service, true,
false, locale, profileToken);
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED);
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

/**
* Get an AS400 object from the connection pool. If an appropriate one is not
found,
* one is created. If the maximum connection limit has been reached, an
exception
* will be thrown. The AS400 object may not be connected to any services.
* Note that the password is validated only when creating a new connection, not
as part
* of the match criteria to pull a connection out of the pool. This means that
* if a connection in the pool matches the systemName and userID passed in, a
* connection will be returned without the password being validated.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param profileToken The profile token to use to authenticate to the system.
* @return An AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getConnection(String systemName, String userID,
ProfileTokenCredential profileToken) //@C1A
throws ConnectionPoolException
{
try
{
AS400 releaseConnection = getConnection(systemName, userID, 0, false, false,
null, profileToken);
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED);
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

/**
* Get an AS400 object from the connection pool with the specified Locale. If an
appropriate one is not found,
* one is created. If the maximum connection limit has been reached, an
exception
* will be thrown. The AS400 object may not be connected to any services.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param profileToken The profile token to use to authenticate to the system.
* @param locale The Locale used to set the National Language Version (NLV)
on the system for the AS400 object returned.
* Only the COMMAND, PRINT, and DATABASE services accept an NLV.
* @return An AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getConnection(String systemName, String userID,
ProfileTokenCredential profileToken, Locale locale) //@C1A
throws ConnectionPoolException
{
try
{
AS400 releaseConnection = getConnection(systemName, userID, 0, false, false,
locale, profileToken);
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED);
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

private AS400 getConnection(String systemName, String userID, int service,


boolean connect, boolean secure, Locale locale, AS400ConnectionPoolAuthentication
poolAuth) //@B3C //@B4C //@C1C
throws AS400SecurityException, IOException, ConnectionPoolException
{
if (systemName == null)
throw new NullPointerException("systemName");
if (systemName.length() == 0)
throw new ExtendedIllegalArgumentException("systemName",
ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
if (userID == null)
throw new NullPointerException("userID");
if (userID.length() == 0)
throw new ExtendedIllegalArgumentException("userID",
ExtendedIllegalArgumentException.LENGTH_NOT_VALID);

if (Trace.traceOn_) //@A5A
{
log(Trace.INFORMATION, "getConnection() key before resolving= " + systemName
+ "/" + userID); //@A5A
}
systemName = AS400.resolveSystem(systemName); //@A5A
userID = AS400.resolveUserId(userID.toUpperCase()); //@A5A
//@KBA

String key = createKey(systemName, userID);


if (Trace.traceOn_) //@A5A
{
log(Trace.INFORMATION, "getConnection() key after resolving= " + key); //@A5A
}

if (!isInUse()) //@A3A
{
//@A3A
setInUse(true); // threadUsed property can now not be changed. //@A3A
} //@A3A

//Work with maintenance thread


if (isThreadUsed() && isRunMaintenance())
{
// Start thread if it has not been initialized.
if (maintenance_ == null)
{
synchronized(this) //@CRS
{
if (maintenance_ == null) //@CRS
{
maintenance_ = new PoolMaintenance(this);
maintenance_.start();
}
}
}
// Restart the thread.
if (!maintenance_.isRunning()) maintenance_.setRunning(true);
}
else if (!isThreadUsed() && isRunMaintenance() &&
((System.currentTimeMillis() - lastRun_) > getCleanupInterval())) // If
running single-threaded and cleanup interval has elapsed, run cleanup
{
cleanupConnections();
}

//@CRS - Let's do a double-check here for performance, per JTOpen bug #3727.
ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);

if (connections == null)
{
synchronized (as400ConnectionPool_) //@B1M
{
connections = (ConnectionList)as400ConnectionPool_.get(key); //@B1C
if (connections == null) //@CRS - Double-check idiom.
{
// no connection list exists, start a new list
if (log_ != null || Trace.traceOn_)
{

log(ResourceBundleLoader.substitute(ResourceBundleLoader.getText("AS400CP_CONNLIST"
), new String[] {systemName, userID} ));
}
connections = new ConnectionList(systemName, userID, properties_);
// log_ can be null, meaning events should not be logged
connections.setLog(log_);

// create a new connection


as400ConnectionPool_.put(key, connections);
}
}
}

//@CRS - Moved the block below out of the synch block above per JTOpen bug
#3727...
// We don't want to hold the lock on the entire pool if we are trying to get a
connection
// for a system that is down or non-existent. ConnectionList.getConnection() is
synchronized
// inside itself, anyway.

//Get a connection from the list


AS400 connection = null;
if (connect)
{
connection = connections.getConnection(service, secure, poolListeners_,
locale, poolAuth, socketProperties_, getCCSID()).getAS400Object(); //@B3C add null
locale //@B4C //@C1C
}
else
{
connection = connections.getConnection(secure, poolListeners_, locale,
poolAuth, socketProperties_, getCCSID()).getAS400Object(); //@B3C add null locale
//@B4C //@C1C
}
connectionHasBeenCreated_ = true; // remember that we've created at least 1
connection
return connection;
}

/**
* Get an AS400 object from the connection pool. If an appropriate one is not
found,
* one is created. The AS400 object may not be connected to any services.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param service The service to connect. See the service number constants
defined by AS400 class.
* @param connect If true connect to specified service.
* @param secure If true secure AS400 object was requested.
* @param locale The Locale used to set the National Language Version (NLV)
on the system for the AS400 object returned.
* Only the COMMAND, PRINT, and DATABASE services accept an NLV.
* @return An AS400 object.
*
* @exception AS400SecurityException If a security error occurred.
* @exception IOException If a communications error occurred.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
private AS400 getConnection(String systemName, String userID, int service,
boolean connect, boolean secure, Locale locale, String password) //@B3C //@B4C
throws AS400SecurityException, IOException, ConnectionPoolException
{
AS400ConnectionPoolAuthentication poolAuth = new
AS400ConnectionPoolAuthentication(password); //@C1A
return (getConnection(systemName, userID, service, connect, secure, locale,
poolAuth)); //@C1C
}

/**
* Get an AS400 object from the connection pool. If an appropriate one is not
found,
* one is created. The AS400 object may not be connected to any services.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param service The service to connect. See the service number constants
defined by AS400 class.
* @param connect If true connect to specified service.
* @param secure If true secure AS400 object was requested.
* @param locale The Locale used to set the National Language Version (NLV)
on the system for the AS400 object returned.
* Only the COMMAND, PRINT, and DATABASE services accept an NLV.
* @return An AS400 object.
*
* @exception AS400SecurityException If a security error occurred.
* @exception IOException If a communications error occurred.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
private AS400 getConnection(String systemName, String userID, int service,
boolean connect, boolean secure, Locale locale, ProfileTokenCredential
profileToken)
throws AS400SecurityException, IOException, ConnectionPoolException
{
AS400ConnectionPoolAuthentication poolAuth = new
AS400ConnectionPoolAuthentication(profileToken); //@C1A
return (getConnection(systemName, userID, service, connect, secure, locale,
poolAuth)); //@C1C
}

/**
* Get an secure connected AS400 object from the connection pool. If an
appropriate one is not found,
* one is created. If the maximum connection limit has been reached, an
exception
* will be thrown. The AS400 object may not be connected to any services.
* Note that the password is validated only when creating a <b>new</b>
connection,
* of the match criteria to pull a connection out of the pool. This means that
* if an <b>existing</b> connection in the pool matches the systemName and userID
* passed in, a connection will be returned without the password being validated.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param password The password of the user.
* @return A secure connected AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getSecureConnection(String systemName, String userID, String
password)
throws ConnectionPoolException
{
try
{
//@B4D AS400.addPasswordCacheEntry(systemName, userID, password);
AS400 releaseConnection = getConnection(systemName, userID, 0, false, true,
null, password); //@B3C add null locale //@B4C
releaseConnection.getVRM();
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED);
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

/**
* Get an secure connected AS400 object from the connection pool. If an
appropriate one is not found,
* one is created. If the maximum connection limit has been reached, an
exception
* will be thrown. The AS400 object may not be connected to any services.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @return A secure connected AS400 object.
* @exception ConnectionPoolException Always thrown because this method has
been deprecated.
* @deprecated Use getSecureConnection(String systemName, String userID,
String password) instead.
**/
public AS400 getSecureConnection(String systemName, String userID)
throws ConnectionPoolException
{
//@B4D try
//@B4D {
//@B4D AS400 releaseConnection = getConnection(systemName, userID, 0,
false, true, null); //@B3C add null locale
//@B4D releaseConnection.getVRM();
//@B4D ConnectionPoolEvent event = new
ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED); //@A7C
//@B4D poolListeners_.fireConnectionReleasedEvent(event);
//@B4D return releaseConnection;
//@B4D }
//@B4D catch (AS400SecurityException ae)
//@B4D {
//@B4D throw new ConnectionPoolException(ae);
//@B4D }
//@B4D catch (IOException ie)
//@B4D {
//@B4D throw new ConnectionPoolException(ie);
//@B4D }
throw new ConnectionPoolException(new
ExtendedIOException(ExtendedIOException.REQUEST_NOT_SUPPORTED)); //@B4A
}

/**
* Get a secure connected AS400 object from the connection pool. If an
appropriate one is
* not found, one is created. If the maximum connection limit has been reached,
an exception
* will be thrown.
* Note that the password is validated only when creating a <b>new</b>
connection,
* of the match criteria to pull a connection out of the pool. This means that
* if an <b>existing</b> connection in the pool matches the systemName and
userID
* passed in, a connection will be returned without the password being
validated.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param password The password of the user.
* @param service The service to connect. See the service number constants
defined by AS400 class.
* @return A connected AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getSecureConnection(String systemName, String userID, String
password, int service)
throws ConnectionPoolException
{
try
{
//@B4D AS400.addPasswordCacheEntry(systemName, userID, password);
AS400 releaseConnection = getConnection(systemName, userID, service, true,
true, null, password); //@B3C add null locale //@B4C
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED); //@A7C
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

/**
* Get a secure connected AS400 object from the connection pool. If an
appropriate one is
* not found, one is created. If the maximum connection limit has been reached,
an exception
* will be thrown.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param service The service to connect. See the service number constants
defined by AS400 class.
* @return A connected AS400 object.
* @exception ConnectionPoolException Always thrown because this method has
been deprecated.
* @deprecated Use getConnection(String systemName, String userID, String
password, int service) instead.
**/
public AS400 getSecureConnection(String systemName, String userID, int service)
throws ConnectionPoolException
{
//@B4D try
//@B4D {
//@B4D AS400 releaseConnection = getConnection(systemName, userID, service,
true, true, null); //@B3C add null locale
//@B4D ConnectionPoolEvent event = new
ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED); //@A7C
//@B4D poolListeners_.fireConnectionReleasedEvent(event);
//@B4D return releaseConnection;
//@B4D }
//@B4D catch (AS400SecurityException e)
//@B4D {
//@B4D throw new ConnectionPoolException(e);
//@B4D }
//@B4D catch (IOException ie)
//@B4D {
//@B4D throw new ConnectionPoolException(ie);
//@B4D }
throw new ConnectionPoolException(new
ExtendedIOException(ExtendedIOException.REQUEST_NOT_SUPPORTED)); //@B4A
}

/**
* Get an secure connected AS400 object from the connection pool. If an
appropriate one is not found,
* one is created. If the maximum connection limit has been reached, an
exception
* will be thrown. The AS400 object may not be connected to any services.
* Note that the profileTokenCredential is validated only when creating a
<b>new</b>
* connection, of the match criteria to pull a connection out of the pool. This
means
* that if an <b>existing</b> connection in the pool matches the systemName and
* userID passed in, a connection will be returned without the
profileTokenCredential
* being validated.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param profileToken The profile token to use to authenticate to the system.
* @return A secure connected AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getSecureConnection(String systemName, String userID,
ProfileTokenCredential profileToken) //@C1A
throws ConnectionPoolException
{
try
{
AS400 releaseConnection = getConnection(systemName, userID, 0, false, true,
null, profileToken);
releaseConnection.getVRM();
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED);
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

/**
* Get a secure connected AS400 object from the connection pool. If an
appropriate one is
* not found, one is created. If the maximum connection limit has been reached,
an exception
* will be thrown.
* Note that the profileTokenCredential is validated only when creating a
<b>new</b>
* connection, of the match criteria to pull a connection out of the pool. This
means
* that if an <b>existing</b> connection in the pool matches the systemName and
* userID passed in, a connection will be returned without the
profileTokenCredential
* being validated.
*
* @param systemName The name of the system where the object should exist.
* @param userID The name of the user.
* @param profileToken The profile token to use to authenticate to the system.
* @param service The service to connect. See the service number constants
defined by AS400 class.
* @return A connected AS400 object.
* @exception ConnectionPoolException If a connection pool error occurred.
**/
public AS400 getSecureConnection(String systemName, String userID,
ProfileTokenCredential profileToken, int service) //@C1A
throws ConnectionPoolException
{
try
{
AS400 releaseConnection = getConnection(systemName, userID, service, true,
true, null, profileToken);
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new ConnectionPoolEvent(releaseConnection,
ConnectionPoolEvent.CONNECTION_RELEASED);
poolListeners_.fireConnectionReleasedEvent(event);
}
return releaseConnection;
}
catch (AS400SecurityException e)
{
throw new ConnectionPoolException(e);
}
catch (IOException ie)
{
throw new ConnectionPoolException(ie);
}
}

/**
Returns a copy of the socket properties that this AS400ConnectionPool specifies
when it creates new AS400 objects, for example in <tt>fill()</tt>,
<tt>getConnection()</tt>, or <tt>getSecureConnection()</tt>.
@return The socket properties. A null value indicates that this
AS400ConnectionPool specifies no socket properties.
**/
public SocketProperties getSocketProperties()
{
if (Trace.traceOn_) log(Trace.DIAGNOSTIC, "Getting socket properties.");
if (socketProperties_ == null) return null;
else {
SocketProperties socketProperties = new SocketProperties();
socketProperties.copyValues(socketProperties_);
return socketProperties;
}
}

/**
* Get a list of the system names in the pool.
*
* @return A list of the system names in the pool.
* If the the pool is empty, returns a zero-length list.
**/
public String[] getSystemNames()
{
Enumeration keys = as400ConnectionPool_.keys();
Vector hosts = new Vector();
while (keys.hasMoreElements())
{
String key = (String)keys.nextElement();
String host = key.substring(0, key.indexOf("/"));
if (!hosts.contains(host)) hosts.addElement(host);
}
String[] hostsArr = new String[hosts.size()];
hosts.copyInto(hostsArr);
return hostsArr;
}

//@B2A
/**
* Get an enumeration of the systemName/userId pairs in the pool.
* Note: The returned information is regardless of the authentication
* scheme used when filling the pool (e.g. password, profile token).
*
* @return An enumeration of the systemName/userIds in the pool
**/
public Enumeration getUsers()
{
return as400ConnectionPool_.keys();
}

/**
* Get a list of the userIds in the pool with connections to a specific system.
* UserIds are listed regardless of whether their connections are
* currently active or disconnected.
* Note: The returned information is regardless of the authentication
* scheme used when filling the pool (e.g. password, profile token).
*
* @param systemName The name of the system of interest.
* @return A list of the userIds in the pool for system <tt>systemName</tt>.
* If there are no userIDs for that system, empty list is returned.
**/
public String[] getUsers(String systemName)
{
if (systemName == null) throw new NullPointerException("systemName");
return getUsers(systemName, false);
}

/**
* Get a list of the userIds in the pool with connections to a specific system.
* Only userIds with currently active (non-disconnected) connections are listed.
* Note: The returned information is regardless of the authentication
* scheme used when filling the pool (e.g. password, profile token).
*
* @param systemName The name of the system of interest.
* @return A list of the connected userIds in the pool for system
<tt>systemName</tt>.
* If there are no connected userIDs for that system, empty list is
returned.
**/
public String[] getConnectedUsers(String systemName)
{
if (systemName == null) throw new NullPointerException("systemName");
return getUsers(systemName, true);
}

private String[] getUsers(String systemName, boolean listConnectedOnly)


{
Enumeration keys = as400ConnectionPool_.keys();
Vector users = new Vector();
systemName = systemName.toUpperCase().trim();
String compareKey = systemName+"/";
while (keys.hasMoreElements())
{
String key = (String)keys.nextElement();
if (key.startsWith(compareKey))
{
ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);
if (!listConnectedOnly || connections.hasConnectedConnection())
{
String user = key.substring(key.indexOf("/")+1);
if (!users.contains(user)) users.addElement(user);
}
}
}
String[] usersArr = new String[users.size()];
users.copyInto(usersArr);
return usersArr;
}

/**
* Initializes the transient data.
**/
private void initializeTransient()
{
// log_ was originally not transient, however the EventLog class (one of the
possible
// implementations of the Log interface) uses a java.io.PrintWriter object
which is
// not serializable. Therefore, log_ was changed to be transient and the user
// will need to reset log_ after a serialization of the pool.
as400ConnectionPool_ = new Hashtable();
removedAS400ConnectionPool_ = new Hashtable(); //@A5A
lastRun_ = System.currentTimeMillis();
connectionHasBeenCreated_ = false;
}

/**
* Log the message to the log.
*
* @param msg The message to log.
**/
private final void log(String msg)
{
if (Trace.traceOn_)
Trace.log(Trace.INFORMATION, msg);
if (log_ != null)
{
log_.log(msg);
}
}

/**
* Log the message to the log.
*
* @param category The trace category.
* @param msg The message to log.
**/
private final void log(int category, String msg)
{
if (Trace.traceOn_ && Trace.isTraceOn(category))
{
Trace.log(category, msg);
if (log_ != null)
{
log_.log(msg);
}
}
}

/**
* Log the exception and message to the log.
*
* @param exception The exception to log.
* @param msg The message to log.
**/
private final void log(Exception exception, String msg)
{
if (Trace.traceOn_)
Trace.log(Trace.ERROR, msg, exception);
if (log_ != null)
{
log_.log(msg, exception);
}
}

/**
* Deserializes and initializes transient data.
* @exception IOException If a file I/O error occurs.
* @exception ClassNotFoundException If a file error occurs.
**/
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException
{
in.defaultReadObject();
initializeTransient();
}

//@A6A
/**
* Remove the connections for a systemName/userID. Call this function if
connections for a
* particular system/userID would no longer be valid. For example, if you change
the password for a
* userId, you will want to call this method to remove the connections for the
old userID
* combination. This will not invalidate connections in use; rather it will mean
that the next time
* a connection is requested for that userID, a new connection
* will be established to the system. After you call this method, you may want
* to fill the pool with connections with your new password to avoid connection
time.
* Note: This method will remove connections regardless of the authentication
scheme
* used when filling the pool (e.g. password, profile token).
*
* @param systemName The system name of connections you want to remove.
* @param userID The user ID of connections you want to remove.
**/
public void removeFromPool(String systemName, String userID)
{
if (systemName == null)
throw new NullPointerException("systemName");
if (userID == null)
throw new NullPointerException("userID");
if (Trace.traceOn_)
{
log(Trace.INFORMATION, "removeFromPool("+systemName+","+userID);
}
systemName = AS400.resolveSystem(systemName);
userID = AS400.resolveUserId(userID.toUpperCase()); //@KBA
String key = createKey(systemName, userID);
ConnectionList listToBeRemoved = (ConnectionList)as400ConnectionPool_.get(key);
if (listToBeRemoved != null)
{
listToBeRemoved.removeUnusedElements(); // this disconnects the connections
removedAS400ConnectionPool_.put(key, listToBeRemoved);
as400ConnectionPool_.remove(key);
}
else if (Trace.traceOn_)
{
log(Trace.WARNING, "A list of connections for: " + key + " does not exist.");
}
}

private static final boolean DISCARD_CONNECTION = true;

/**
* Remove the specified connection from the pool, and disconnect it.
* Call this function if a specific connection has been discovered to
* no longer be valid.
* <p>
* This method should only be called by the process or thread to which
* the connection is currently allocated; that is,
* the process or thread that most recently obtained the connection
* via <tt>getConnection()</tt> or <tt>getSecureConnection()</tt>.
* To remove the connection from the pool, the process or thread
* holding the connection should call this method <i>rather than</i>
* {@link #returnConnectionToPool returnConnectionToPool()}.
* <p>
* Caution: The pool does not verify that the process or thread removing
* the connection, is the same as the process or thread to which
* the connection is currently allocated.
* This may cause unpredictable results if the connection is in use
* by another process or thread.
*
* @param system The system to remove from the pool.
**/
public void removeFromPool(AS400 system)
{
if (system == null) throw new NullPointerException("system");
if (Trace.traceOn_)
{
log(Trace.INFORMATION, "removeFromPool() key= " + system.getSystemName() +
"/" + system.getUserId() + "; hashcode= " + system.hashCode());
}

// Remove the connection from the pool, and disconnect it.


acceptReturnedConnection(system, DISCARD_CONNECTION);
}

/**
* Return the AS400 object to the connection pool.
* <p>
* This method should only be called by the process or thread to which
* the connection is currently allocated; that is,
* the process or thread that most recently obtained the connection
* via <tt>getConnection()</tt> or <tt>getSecureConnection()</tt>.
* <p>
* Caution: The pool does not verify that the process or thread returning
* the connection, is the same as the process or thread to which
* the connection is currently allocated.
* This may cause unpredictable results if the connection is in use
* by another process or thread.
*
* @param system The system to return to the pool.
* @see #removeFromPool(AS400)
**/
public void returnConnectionToPool(AS400 system)
//@A4D throws AS400SecurityException, IOException, ConnectionPoolException
{
// This method searches the lists of connections for a reference to the AS400
// object that was returned. There will be one list per systemName/userId key.
if (system == null) throw new NullPointerException("system");
if (Trace.traceOn_)
{
log(Trace.INFORMATION, "returnConnectionToPool() key= " +
system.getSystemName() + "/" + system.getUserId()); //@A5A
}

// Return the connection to the pool, making it available for re-use.


acceptReturnedConnection(system, !DISCARD_CONNECTION);

//If running single-threaded and cleanup interval has elapsed, run cleanup.
if (!isThreadUsed() && isRunMaintenance() &&
((System.currentTimeMillis() - lastRun_) > getCleanupInterval())) //@D1C
replace maintenance_.getLastTime() with lastRun_
{
cleanupConnections();
}
}

/**
Process a connection that is being returned to the pool.
@param discardConnection Whether the connection should be discarded, or
retained in the pool (and made available for subsequent re-use).
**/
private void acceptReturnedConnection(AS400 system, boolean discardConnection)
{
String key = createKey(system.getSystemName(), system.getUserId());
ConnectionList connections = (ConnectionList)as400ConnectionPool_.get(key);
PoolItem poolItem = null;

// First look for the list for the systemName/userId key for the AS400 object.
// If such a list exists, search that list for a reference to the AS400 object
returned.
if (connections != null)
{
poolItem = connections.findElement(system);
}

// If such an item is found, set it "not in use" and send an event that the
connection was returned to the pool.
if (poolItem != null)
{
if (discardConnection) // caller wants the connection deleted from the pool
{
if (Trace.traceOn_) {
log(Trace.DIAGNOSTIC, "Disconnecting pooled connection because
removeFromPool() was invoked for that connection.");
}
connections.removeElement(system);
poolItem.getAS400Object().disconnectAllServices();
}
else // caller is simply returning the connection to the pool
{
// Before making the connection available for re-use, see if it's expired.
boolean removed = connections.removeIfExpired(poolItem, poolListeners_);
if (!removed) {
poolItem.setInUse(false); // indicate that this connection is available
}
if (log_ != null || Trace.traceOn_)
{

log(ResourceBundleLoader.substitute(ResourceBundleLoader.getText("AS400CP_RETCONN")
, new String[] {system.getSystemName(), system.getUserId()} ));
}
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new
ConnectionPoolEvent(poolItem.getAS400Object(),
ConnectionPoolEvent.CONNECTION_RETURNED); //@A7C
poolListeners_.fireConnectionReturnedEvent(event);
}
}
}
// If the item was not found, search all the lists, looking for a reference to
that
// item. If it is found, disconnect it and remove it from the pool since its
// systemName/userId has been changed from what was expected.
if (poolItem == null)
{
Enumeration keys = as400ConnectionPool_.keys();
while (keys.hasMoreElements())
{
String tryKey = (String)keys.nextElement();
ConnectionList connList = (ConnectionList)as400ConnectionPool_.get(tryKey);
poolItem = connList.findElement(system);
if (poolItem != null)
{
if (Trace.traceOn_)
{
log(Trace.WARNING, "Disconnecting pooled connection because it was
returned, and belongs to a different list than expected.");
}
connList.removeElement(system);
poolItem.getAS400Object().disconnectAllServices();
break;
}
}
}

// A list of connections will


// be moved into the removed pool if removeFromPool() with the
systemName/userId of the
// list is called. This allows us to keep references to an AS400 object until
// the user calls returnConnectionToPool() on it, but not give it out again
// to the user.
// Code was added here to handle checking in removed pool for the connection
// and removing it from that pool if it is found.

// If the pooled connection was not found in the regular lists, start looking
// in the lists in the removed pool.
if (poolItem == null)
{
ConnectionList removedConnections =
(ConnectionList)removedAS400ConnectionPool_.get(key);

// Start looking in the list with the systemName/userId combination.


if (removedConnections != null)
{
poolItem = removedConnections.findElement(system);
}

// If the object is found, disconnect it and remove the element from removed
pool.
if (poolItem != null)
{
if (Trace.traceOn_)
{
log(Trace.DIAGNOSTIC, "Disconnecting pooled connection because it was
returned, and removeFromPool() has been called for its systemName/userID.");
}
removedConnections.removeElement(system);
poolItem.getAS400Object().disconnectAllServices();
if (log_ != null || Trace.traceOn_)
{

log(ResourceBundleLoader.substitute(ResourceBundleLoader.getText("AS400CP_RETCONN")
, new String[] {system.getSystemName(), system.getUserId()} ));
}
if (poolListeners_ != null)
{
ConnectionPoolEvent event = new
ConnectionPoolEvent(poolItem.getAS400Object(),
ConnectionPoolEvent.CONNECTION_RETURNED); //@A7C
poolListeners_.fireConnectionReturnedEvent(event);
}
}

// If the object was not found, search through every list in the removed
pool,
// looking for a reference to the object.
if (poolItem == null)
{
Enumeration keys = removedAS400ConnectionPool_.keys();
while (keys.hasMoreElements())
{
String tryKey = (String)keys.nextElement();
ConnectionList connList =
(ConnectionList)removedAS400ConnectionPool_.get(tryKey);
poolItem = connList.findElement(system);
if (poolItem != null)
{
if (Trace.traceOn_)
{
log(Trace.DIAGNOSTIC, "Disconnecting pooled connection because it was
returned, and removeFromPool() has been called for its systemName/userID.");
}
connList.removeElement(system);
poolItem.getAS400Object().disconnectAllServices();
break;
}
}
}

// If the object was not found in any of our lists, it does not belong to
this pool.
// In that case, just disconnect the connection.
if (poolItem == null)
{
if (discardConnection) // the caller wants the connection disconnected
{
if (Trace.traceOn_) {
log(Trace.WARNING, "Disconnecting pooled connection because
removeFromPool(AS400) was called. The connection is not currently a member of this
pool.");
}
}
else {
log(Trace.ERROR, "Disconnecting pooled connection because it was
returned, and the connection is not currently a member of this pool.");
}
system.disconnectAllServices();
}
}
}

/**
* Notify the maintenance thread to run cleanupConnections().
* @param reduced true if need to check current num connections; false
otherwise.
**/
void runMaintenance(boolean reduced)
{
if (maintenance_ != null)
{
synchronized(maintenance_)
{
if (maintenance_.isRunning())
{
if (reduced)
{
synchronized (as400ConnectionPool_)
{
Enumeration keys = as400ConnectionPool_.keys();
while (keys.hasMoreElements())
{
String key = (String)keys.nextElement();
try
{
ConnectionList connList =
(ConnectionList)as400ConnectionPool_.get(key);
connList.shutDownOldest();
}
catch (Exception e)
{
if (log_ != null || Trace.traceOn_)
log(e, key);
}
}
}
}
//@A6A Start new code
synchronized (removedAS400ConnectionPool_)
{
Enumeration removedKeys = removedAS400ConnectionPool_.keys();
while (removedKeys != null && removedKeys.hasMoreElements())
{
//go through each list of systemName/userID
String key = (String)removedKeys.nextElement();

ConnectionList connList =
(ConnectionList)removedAS400ConnectionPool_.get(key);
//disconnect and remove any unused connections from the list
if (!connList.removeUnusedElements()) // this disconnects the
connections
{
//if there are no more connections remaining, remove the
//list from the pool
removedAS400ConnectionPool_.remove(key);
}
}
}
//@A6A End new code

maintenance_.notify(); // PoolMaintenance.run() calls


ConnectionPool.cleanupConnections()
}
}
}
}

/**
* Sets the CCSID to use when creating new connections.
* The default value is the system default CCSID as determined by the AS400
class.
* Note: This method only affects the CCSID of newly-created connections.
* Existing connections are not affected.
* @param ccsid The CCSID to use for connections in the pool, or {@link
#CCSID_DEFAULT CCSID_DEFAULT} to indicate that the system default CCSID should be
used.
**/
public void setCCSID(int ccsid)
{
if (Trace.traceOn_) {
Trace.log(Trace.INFORMATION, "setCCSID("+ccsid+")");
if (connectionHasBeenCreated_) {
log(Trace.WARNING, "setCCSID() was called after the pool already contains
connections.");
}
}
super.setCCSID(ccsid);
}

/**
* Set the Log object to log events. The default is to not log events.
*
* @param log The log object to use, or null if events should not be logged.
*
* @see com.ibm.as400.access.Log
**/
public void setLog(Log log)
{
if (Trace.traceOn_) {
String val = ( log == null ? "null" : log.toString() );
Trace.log(Trace.INFORMATION, "setLog("+val+")");
}
this.log_ = log;
}

/**
Sets the socket properties that this AS400ConnectionPool specifies when it
creates new AS400 objects, for example in <tt>fill()</tt>,
<tt>getConnection()</tt>, or <tt>getSecureConnection()</tt>.
<br>Note that <tt>properties</tt> will apply only to AS400 objects created
<em>after</em> this method is called. Any AS400 objects already in the pool are
not affected.
@param properties The socket properties. If null, then this
AS400ConnectionPool will specify no socket properties when it creates new AS400
objects. That is, <tt>setSocketProperties(null)</tt> cancels the effects of any
previous <tt>setSocketProperties()</tt>.
**/
public void setSocketProperties(SocketProperties properties)
{
if (Trace.traceOn_) {
Trace.log(Trace.INFORMATION, "setSocketProperties()");
}
socketProperties_ = properties;
}

You might also like