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

com.ibm.as400.access.ConnectionList Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
//                                                                             
// JTOpen (IBM Toolbox for Java - OSS version)                              
//                                                                             
// Filename: ConnectionList.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
//                    by using AS400ConnectionPoolAuthentication class.
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

import java.util.Vector;    // Java 2
import java.io.IOException;
import java.util.Locale;      //@B2A

/** 
  *  ConnectionList is a list of connections specific to an IBM i system and userID.  The 
  *  connection list is used to create new connections and get connections from the pool.
  *  The connection list can remove connections that have exceeded inactivity time and 
  *  replace connections that have exceeded the maximum use count or maximum lifetime.
 **/
final class ConnectionList 
{
    // Values returned by checkConnectionExpiration().
    // Note: These correspond to MRI text IDs in class MRI2.
    private static final String NOT_EXPIRED = null;
    private static final String EXPIRED_INACTIVE = "CL_REMUNUSED";
    private static final String EXPIRED_MAX_LIFETIME = "CL_REMLIFE";
    private static final String EXPIRED_MAX_USE_COUNT = "CL_REMUSECOUNT";
    private static final String EXPIRED_MAX_USE_TIME = "CL_REMUSETIME";
    private static final String EXPIRED_FAILED_PRETEST = "CL_REMPRETEST";

    private String systemName_;
    private String userID_;
    private ConnectionPoolProperties properties_;
    private Log log_;
    private Vector connectionList_ = new Vector(); 

    /**
     *  Construct a ConnectionList object.  
     *  @param systemName The system where the ConnectionList will exist.
     *  @param userID The name of the user.
     *  @param properties The properties of the ConnectionList.
    **/
    ConnectionList(String systemName, String userID, ConnectionPoolProperties properties)  
    {
        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 (properties == null) throw new NullPointerException("properties");

        this.systemName_ = systemName;
        this.userID_ = userID;
        this.properties_ = properties;
    }


    /**
     * Sees if the specified connection is due for removal.
     *
     * @param poolItem The pool item.
     * @return The MRI textID specifying the type of expiration, or null if not expired.
     **/
    private String checkConnectionExpiration(PoolItem poolItem)
    {
        // See if the item has exceeded the maximum inactivity time.
        if ((properties_.getMaxInactivity() >= 0) && (poolItem.getInactivityTime() >= properties_.getMaxInactivity()))
            return EXPIRED_INACTIVE;

        // See if the item has exceeded the maximum use count.
        if ((properties_.getMaxUseCount() >= 0) && (poolItem.getUseCount() >= properties_.getMaxUseCount()))
            return EXPIRED_MAX_USE_COUNT;

        // See if the item has exceeded the maximum lifetime.
        if ( (properties_.getMaxLifetime() >= 0) && (poolItem.getLifeSpan() >= properties_.getMaxLifetime()))
            return EXPIRED_MAX_LIFETIME;

        // See if the item has exceeded the maximum use time.
        if ((properties_.getMaxUseTime() >= 0) && (poolItem.getInUseTime() >= properties_.getMaxUseTime()))
            return EXPIRED_MAX_USE_TIME;

        return NOT_EXPIRED;
    }

    /**
     *  Close the connection.
     **/
    void close()
    {
        if (log_ != null || Trace.traceOn_) log(ResourceBundleLoader.getText("CL_CLEANUP", new String[] {systemName_, userID_} ));
        
        synchronized (connectionList_) 
        {
            int size = connectionList_.size();  //@A5M
            for (int i=0; i 0) && (getConnectionCount() >= properties_.getMaxConnections()))
        {
            if (log_ != null || Trace.traceOn_) log(ResourceBundleLoader.getText("CL_CLEANUPEXP"));
      
            // see if anything frees up
            removeExpiredConnections(poolListeners);

            // if that didn't do the trick, try shutting down unused connections
            if (getConnectionCount() >= properties_.getMaxConnections())
            {
                if (log_ != null || Trace.traceOn_) log(ResourceBundleLoader.getText("CL_CLEANUPOLD"));
                
                shutDownOldest(); 
                
                // if not enough connections were freed, throw an exception!
                if (getConnectionCount() >= properties_.getMaxConnections())
                    throw new ConnectionPoolException(ConnectionPoolException.MAX_CONNECTIONS_REACHED);
            }
        }

        boolean threadUse = properties_.isThreadUsed();
        // create a new connection
        PoolItem sys = new PoolItem (systemName_, userID_, poolAuth, secure, locale, service, connect, threadUse, socketProperties, ccsid);

        // set the item is in use since we are going to return it to caller
        sys.setInUse(true);
        connectionList_.addElement(sys);  

        if (poolListeners != null)
        {
            ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(sys.getAS400Object(), ConnectionPoolEvent.CONNECTION_CREATED);
            poolListeners.fireConnectionCreatedEvent(poolEvent);  
        }
        
        if (log_ != null || Trace.traceOn_) log(ResourceBundleLoader.getText("CL_CREATED", new String[] {systemName_, userID_} ));

        return sys;
    }

    /**
     *  Return the poolItem in the list that contains this AS400 instance.
     *
     *  @return The matching poolItem.
     **/
    PoolItem findElement(AS400 systemToFind)
    {
        synchronized (connectionList_)
        {
            int size = connectionList_.size();        
            for (int i=0; i=0; i--)
            {
                PoolItem p = (PoolItem)connectionList_.elementAt(i);    

                // Be conservative about removing in-use connections.
                if (p.isInUse())
                {
                    // Reclaim an in-use connection, only if its maxUseTime limit is exceeded.
                    if ((properties_.getMaxUseTime() >= 0) && (p.getInUseTime() >= properties_.getMaxUseTime()))
                    {
                        // Limit exceeded, so disconnect and remove the connection.
                        if (log_ != null || Trace.traceOn_) {
                            log(ResourceBundleLoader.getText(EXPIRED_MAX_USE_TIME, new String[] {systemName_, userID_} ));
                            log(Trace.WARNING, "Disconnecting pooled connection (currently in use) because it has exceeded the maximum use time limit of " + properties_.getMaxUseTime() + " milliseconds.");
                        }
                        
                        p.getAS400Object().resetAllServices();
                        connectionList_.removeElementAt(i);
                        if (poolListeners != null)
                        {
                            ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(p.getAS400Object(), ConnectionPoolEvent.CONNECTION_EXPIRED); //@A5C
                            poolListeners.fireConnectionExpiredEvent(poolEvent);  
                        }
                    }
                }
                else if (p.isFailedPretest())
                {
                    // Pool item has failed a connection validity pretest, so disconnect and remove the connection.
                    if (log_ != null || Trace.traceOn_)
                    {
                        log(ResourceBundleLoader.getText(EXPIRED_FAILED_PRETEST, new String[] {systemName_, userID_} ));
                        log(Trace.DIAGNOSTIC, "Disconnecting pooled connection (not currently in use) because it has failed a validation pretest.");
                    }
                    
                    p.getAS400Object().resetAllServices();
                    connectionList_.removeElementAt(i);
                    if (poolListeners != null)
                    {
                        ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(p.getAS400Object(), ConnectionPoolEvent.CONNECTION_EXPIRED);
                        poolListeners.fireConnectionExpiredEvent(poolEvent);  
                    }
                }
                else if ((properties_.getMaxInactivity() >= 0) && (p.getInactivityTime() >= properties_.getMaxInactivity()))
                {
                    // Connection has exceeded the maximum inactivity time, so disconnect and remove the connection.
                    if (log_ != null || Trace.traceOn_)
                    {
                        log(ResourceBundleLoader.getText(EXPIRED_INACTIVE, new String[] {systemName_, userID_} ));
                        log(Trace.DIAGNOSTIC, "Disconnecting pooled connection (not currently in use) because it has exceeded the maximum inactivity time limit of " + properties_.getMaxInactivity() + " milliseconds.");
                    }
                    
                    p.getAS400Object().resetAllServices();
                    connectionList_.removeElementAt(i);
                    if (poolListeners != null)
                    {
                        ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(p.getAS400Object(), ConnectionPoolEvent.CONNECTION_EXPIRED); //@A5C
                        poolListeners.fireConnectionExpiredEvent(poolEvent);  
                    }
                }
                else if ((properties_.getMaxUseCount() >= 0) && (p.getUseCount() >= properties_.getMaxUseCount()))
                {
                    // Connection has exceeded the maximum use count, so disconnect and remove the connection.
                    if (log_ != null || Trace.traceOn_)
                    {
                        log(ResourceBundleLoader.getText(EXPIRED_MAX_USE_COUNT, new String[] {systemName_, userID_} ));
                        log(Trace.DIAGNOSTIC, "Disconnecting pooled connection (not currently in use) because it has exceeded the maximum use count of " + properties_.getMaxUseCount());
                    }
                    
                    p.getAS400Object().resetAllServices();
                    connectionList_.removeElementAt(i);             
                    if (poolListeners != null)
                    {
                        ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(p.getAS400Object(), ConnectionPoolEvent.CONNECTION_EXPIRED); //@A5C //@B2C
                        poolListeners.fireConnectionExpiredEvent(poolEvent);  
                    }
                }
                else if ( (properties_.getMaxLifetime() >= 0) &&  (p.getLifeSpan() >= properties_.getMaxLifetime()))
                {
                    // Connection has exceeded the maximum lifetime, so disconnect and remove the connection.
                    if (log_ != null || Trace.traceOn_)
                    {
                        log(ResourceBundleLoader.getText(EXPIRED_MAX_LIFETIME, new String[] {systemName_, userID_} ));
                        log(Trace.DIAGNOSTIC, "Disconnecting pooled connection (not currently in use) because it has exceeded the maximum lifetime limit of " + properties_.getMaxLifetime() + " milliseconds.");
                    }
                    
                    p.getAS400Object().resetAllServices();
                    connectionList_.removeElementAt(i);           
                    if (poolListeners != null)
                    {
                        ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(p.getAS400Object(), ConnectionPoolEvent.CONNECTION_EXPIRED); //@A5C //@B2C
                        poolListeners.fireConnectionExpiredEvent(poolEvent);  
                    }
                }
            }//end 'for' loop
        }//@B1A end synchronized
    }

    /**
     * Removes the connection from the pool if it is due for removal.
     *
     * @param poolItem The pool item.
     * @param poolListeners The pool listeners to which events will be fired.
     * @return true if the pool item was found and removed from the pool; false otherwise.
     * @exception AS400SecurityException If a security error occured.
     * @exception IOException If a communications error occured.
     **/
    boolean removeIfExpired(PoolItem poolItem, ConnectionPoolEventSupport poolListeners)
    {
        if (connectionList_.isEmpty())
            return false;

        boolean connectionIsExpired = false;
        String expirationStatus = null;
        synchronized (connectionList_)
        {
            expirationStatus = checkConnectionExpiration(poolItem);
            if (expirationStatus == NOT_EXPIRED) {}  // do nothing
            else {
                connectionList_.removeElement(poolItem);
                connectionIsExpired = true;
            }
        }
        
        // Now that we're out of the sync block (and the connection has been removed from connectionList_), disconnect the connection.
        if (connectionIsExpired)
        {
            if ((log_ != null || Trace.traceOn_) && expirationStatus != null)
                log(ResourceBundleLoader.getText(expirationStatus, new String[] {systemName_, userID_} ));

            if (poolListeners != null)
            {
                ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(poolItem.getAS400Object(), ConnectionPoolEvent.CONNECTION_EXPIRED);
                poolListeners.fireConnectionExpiredEvent(poolEvent);  
            }
            
            if (Trace.traceOn_)
                log(Trace.DIAGNOSTIC, "Disconnecting pooled connection (not currently in use) because it has expired.");

            poolItem.getAS400Object().resetAllServices();
        }

        return connectionIsExpired;
    }

    /**
     *  New method to work with AS400ConnectionPool.removeFromPool().
     **/
    boolean removeUnusedElements()
    {
        synchronized (connectionList_)
        {
            if (connectionList_.size() > 0)
            {
                int size = connectionList_.size();

                if (size == 0)
                    return false;
        
                // incrementally search the list, looking for elements that are not in
                // use to remove

                for (int numToCheck = size - 1; numToCheck >= 0; numToCheck--)
                {
                    PoolItem item = (PoolItem)connectionList_.elementAt(numToCheck);
                    if (!item.isInUse())
                    {
                        if (Trace.traceOn_) log(Trace.DIAGNOSTIC, "Disconnecting pooled connection (not currently in use) because removeFromPool() was called.");
                      
                        item.getAS400Object().resetAllServices();
                        connectionList_.removeElementAt(numToCheck);   
                    }
                }
            }  
        }
      
        return true;
    }

    /**
     *  Remove the pool item in the list that contains this AS400 instance.
     *  The caller takes responsibility for subsequently calling resetAllServices().
     *  Called by AS400ConnectionPool.
     **/
    void removeElement(AS400 systemToFind)
    {
        synchronized(connectionList_)
        {
            int size = connectionList_.size();    
   
            for (int i=0; i 0)
                {
                    long t = 0;
                    int size = connectionList_.size();            
                    for (int i=0; i t || oldest == 0)
                            {
                                oldest = i;
                                t = item.getInactivityTime();
                            }
                        }
                    }

                    //only disconnect oldest item if it is not in use
                    PoolItem item = (PoolItem)connectionList_.elementAt(oldest);      
                    if (!item.isInUse())
                    {
                        if (Trace.traceOn_)
                            log(Trace.DIAGNOSTIC, "Disconnecting pooled connection (not currently in use) during removal of oldest unallocated connections.");

                        item.getAS400Object().resetAllServices();
                        connectionList_.removeElementAt(oldest);   
                        if (log_ != null || Trace.traceOn_)
                            log(ResourceBundleLoader.getText("CL_REMOLDCOMP", new String[] {systemName_, userID_} ));
                    }
                } 
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy