Package com.sun.enterprise.ee.web.sessmgmt

Source Code of com.sun.enterprise.ee.web.sessmgmt.HAStore

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/

/*
* HAStore.java
*
* Created on April 22, 2002, 5:25 PM
*/

package com.sun.enterprise.ee.web.sessmgmt;

/**
* This class extends the abstract StoreBase class defined as part of
* Apache Tomcat.  The HAStore class uses the HADB data store to provide
* HA support for session state under Tomcat.
*/

import org.apache.catalina.session.*;
import org.apache.catalina.util.*;
//import org.apache.catalina.authenticator.*;
import org.apache.catalina.*;
import java.sql.*;
import java.io.*;
import java.util.*;
import javax.naming.*;
import javax.sql.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.logging.LogDomains;

//import com.sun.hadb.jdbc.*;

import com.sun.enterprise.web.ServerConfigLookup;

import com.sun.enterprise.ComponentInvocation;
import com.sun.enterprise.Switch;
import com.sun.enterprise.InvocationManager;

import com.sun.enterprise.ee.web.authenticator.*;
import com.sun.enterprise.security.web.SingleSignOn;
import com.sun.enterprise.security.web.SingleSignOnEntry;
import com.sun.enterprise.ee.web.initialization.ServerConfigReader;
import com.sun.appserv.util.cache.BaseCache;
//Bug 4832603 : EJB Reference Failover
import com.sun.ejb.EJBUtils;
//end - Bug 4832603

/**
*
* @author  lwhite
* @version
*/
public class HAStore extends StoreBase implements HAStorePoolElement {
   
    protected static int _maxBaseCacheSize = 4096;
    protected static float _loadFactor = 0.75f;
   
    /**
     * Name to register for the background thread.
     */
    protected String threadName = "HAStore";
       
    /**
    * Our write-through cache of session objects
    */
    protected BaseCache sessions = new BaseCache();

    /**
    * get the sessions cache
    */
    public BaseCache getSessions() {
        return sessions;
    }
 
    /**
    * set the sessions cache
    * @param sesstable
    */
    public void setSessions(BaseCache sesstable) {
        sessions = sesstable;
    }
   
    public BaseCache getMainStoreCache() {
        PersistentManagerBase pmb = (PersistentManagerBase)this.getManager();
        HAStore myStore = (HAStore)pmb.getStore();
        return myStore.getSessions();
    }
   
    protected void putSessionInMainStoreCache(Session session) {
        if(session == null) {
            return;
        }
        BaseCache theSessions = this.getMainStoreCache();
        theSessions.put(session.getIdInternal(), session);
    }
   
    protected Session getSessionFromMainStoreCache(String id) {   
        BaseCache theSessions = this.getMainStoreCache();
        return (Session)theSessions.get(id);
    }   
   
    /**
    * remove a session from the store cache
    * Hercules: added method
    */   
    public void removeSessionFromMainStoreCache(String id) {
        BaseCache theSessions = this.getMainStoreCache();   
        theSessions.remove(id);    
    }   
 
    /**
    * Our write-through cache of session objects
    */
    //protected Hashtable sessions = new Hashtable();

    /**
    * get the sessions cache
    */
    /*
    public Hashtable getSessions() {
      return sessions;
    }
    */

 
    /**
    * set the sessions cache
    * @param sesstable
    */
    /*
    public void setSessions(Hashtable sesstable) {
      sessions = sesstable;
    }
    **

 
    /**
    * The logger we use to log messages
    */
    //Logger logger;
  
    /**
     * The logger to use for logging ALL web container related messages.
     */
    private static Logger _logger = null;
   
    /** chunk size for delete operations
     */
    private static int CHUNK_SIZE = 100;    
   
    /**
     * Controls the verbosity of the web container subsystem's debug messages.
     *
     * This value is non-zero only when the level is one of FINE, FINER
     * or FINEST.
     *
     */
    protected int _debug = 0;
   
    /**
     * The current level of logging verbosity for this object.
     */
    protected Level _logLevel = null;
   
    /**
     * get the utility class used to call into services from IOUtils
     */
    protected IOUtilsCaller getWebUtilsCaller() {
        if(webUtilsCaller == null) {
            WebIOUtilsFactory factory = new WebIOUtilsFactory();
            webUtilsCaller = factory.createWebIOUtil();           
        }
        return webUtilsCaller;
    }   
   
    /**
     * Set _debug flag and _logLevel based on the log level.
     */
    protected void setLogLevel() {
        Level level = _logger.getLevel();
        _logLevel = level;

        // Determine the appropriate value our debug level
        if (level.equals(Level.FINE))
            _debug = 1;
        else if (level.equals(Level.FINER))
            _debug = 2;
        else if (level.equals(Level.FINEST))
            _debug = 5;
        else
            _debug = 0;
    }   
   
   
    static
  {
            checkSessionCacheProperties();
  }
   
    protected static boolean checkSessionCacheProperties() {
        boolean result = false;
  try
        {
            Properties props = System.getProperties();
            String cacheSize=props.getProperty("HTTP_SESSION_CACHE_MAX_BASE_CACHE_SIZE");
            if(null!=cacheSize) {
                _maxBaseCacheSize = (new Integer (cacheSize).intValue());
           
            String loadFactor=props.getProperty("HTTP_SESSION_CACHE_MAX_BASE_LOAD_FACTOR");
            if(null!=loadFactor) {
                _loadFactor = (new Float (loadFactor).floatValue());
            }
            /*
            System.out.println("_maxBaseCacheSize=" + _maxBaseCacheSize);
            System.out.println("_loadFactor=" + _loadFactor);
             */
        } catch(Exception e)
        {
            //do nothing accept defaults
        }
        return result;
    }
   
    /**
     * A utility class used to call into services from IOUtils
     */
    private IOUtilsCaller webUtilsCaller = null;    
 
    /**
    * The table storing session data
    */
    protected String blobSessionTable = "blobsessions";    
 
    /**
    * The name of the HA store JDBC driver
    */
    protected String driverName = "com.sun.hadb.jdbc.Driver";
 
    /**
    * The number of seconds to wait before timing out a transaction
    * Default is 5 minutes.
    */
    protected String timeoutSecs = new Long(5 * 60).toString();
   
    /**
    * The number of seconds to wait before timing out a transaction
    * Default here is 2 minutes. (trial use by clear)
    */   
    protected String timeoutSecs2 = new Long(2 * 60).toString();   

    /**
    * The database connection.
    */
    protected Connection conn = null;
 
    /**
    * The helper class used to manage retryable errors from the HA store
    */
    protected HAErrorManager haErr = null;
   
    /**
    * The helper class used to manage retryable errors from the HA store
    * dedicated to the load method
    */
    protected HAErrorManager haErrLoad = null
   
    /**
    * The helper class used to manage retryable errors from the HA store
    * dedicated to the remove method
    */
    protected HAErrorManager haErrRemove = null;
   
    /**
    * The helper class used to manage retryable errors from the HA store
    * dedicated to the processExpires method
    */
    protected HAErrorManager haErrRemoveExpired = null;   
   
    /**
    * The helper class used to manage retryable errors from the HA store
    * dedicated to the clear method
    */
    protected HAErrorManager haErrClear = null;
   
    /**
    * The helper class used to manage retryable errors from the HA store
    * dedicated to the keys method
    */
    protected HAErrorManager haErrKeys = null;   
   
    /**
    * The helper class used to manage retryable errors from the HA store
    * dedicated to the getSize method
    */
    protected HAErrorManager haErrSize = null;   
   
    /**
    * The helper class used to manage retryable errors from the HA store
    * dedicated to the sessionInStore method used for save
    */
    protected HAErrorManager haErrExists = null
   
    /**
    * The helper class used to manage retryable errors from the HA store
    * dedicated to the sessionInStore method used for valveSave
    */
    protected HAErrorManager haErrExists2 = null;
   
    /**
    * The helper class used to manage retryable errors from the HA store
    * dedicated to the expiredKeys method
    */
    protected HAErrorManager haErrExpiredKeys = null;   
 
    /**
    * The helper class used to obtain connections; both
    * both cached and from the connection pool
    */
    protected ConnectionUtil connectionUtil = null
 
    /**
    * Various cached statements that we can reuse...
    */
    private PreparedStatement preparedKeysSql = null;
    private PreparedStatement preparedExpiredKeysSql = null;
    private PreparedStatement preparedRemoveExpiredKeysSql = null;
    private PreparedStatement preparedSizeSql = null;
    private PreparedStatement preparedDualSql = null;
    private PreparedStatement preparedLoadSql = null
    private PreparedStatement preparedInsertSql = null;
    private PreparedStatement preparedRemoveSql = null;
    private PreparedStatement preparedClearSql = null;
    private PreparedStatement preparedUpdateSql = null;
    /**
    * The prepared statement used by the HA store
    * dedicated to the sessionInStore method used for save
    */
    private PreparedStatement preparedExistsSql = null;
    /**
    * The prepared statement used by the HA store
    * dedicated to the sessionInStore method used for valveSave
    */
    private PreparedStatement preparedExistsSql2 = null;   
    private PreparedStatement preparedUpdateNoSessionSql = null;
 

    /**
    * Return the cluster id for this Store as defined in server.xml.
    */ 
    protected String getClusterIdFromConfig() {
        ServerConfigLookup lookup = new ServerConfigLookup();
        return lookup.getClusterIdFromConfig();
    }

    /**
    * The cluster id
    */ 
    protected String clusterId = null;
 
    /**
    * Return the cluster id for this Store
    */
    protected String getClusterId() {
        if(clusterId == null)
            clusterId = getClusterIdFromConfig();
        return clusterId;
    }

    /**
    * Return the instance of ConnectionUtil for this Store.
    */  
    protected ConnectionUtil getConnectionUtil() {
        if(connectionUtil == null) {
            //connectionUtil = new ConnectionUtil(this.getManager().getContainer());
            connectionUtil =
              new ConnectionUtil(this.getManager().getContainer(), this.getManager());         
        }
        return connectionUtil;
    }

    /**
    * The application id
    */ 
    protected String applicationId = null;
 
    public String getApplicationId() {
        if(applicationId != null)
            return applicationId;
        Container container = manager.getContainer();
        StringBuffer sb = new StringBuffer(50);
        sb.append(this.getClusterId());
        ArrayList list = new ArrayList();
        while (container != null) {           
            if(container.getName() != null) {
                if(container.getName().equals("")) {
                    list.add(":/");
                } else {
                    list.add(":" + container.getName());
                }
            }           
            container = container.getParent();
        }
        for(int i=(list.size() -1); i>-1; i--) {
            String nextString = (String) list.get(i);
            sb.append(nextString);
        }
        applicationId = sb.toString();
        return applicationId;
        /*
        String result = sb.toString();
        applicationId = result;
        //remove after test
        //extractShortApplicationIdFromApplicationId(result);
        return result;
         */
    }
 
    /**
     * The short application id
     * just the cluster and app name
     * excluding the server name
     */ 
    protected String shortApplicationId = null
 
    public String getShortApplicationId() {
        if(shortApplicationId != null)
            return shortApplicationId;
        Container container = manager.getContainer();
        StringBuffer sb = new StringBuffer(50);
        sb.append(this.getClusterId());
        sb.append(":");
        if (container != null) {           
            if(container.getName() != null) {
                if(container.getName().equals("")) {
                    sb.append("/");
                } else {
                    sb.append(container.getName());
                }
            }           
        }
        container = container.getParent();
        shortApplicationId = sb.toString();
        return shortApplicationId;
        /*
        String result = sb.toString();
        shortApplicationId = result;
        return result;
         */       
    }
   
    public String extractShortApplicationIdFromApplicationId(String appid) {
       
        StringTokenizer st = new StringTokenizer(appid, ":");
        ArrayList list = new ArrayList();
        while (st.hasMoreTokens()) {
            String nextToken = st.nextToken();
            list.add(nextToken);
            //System.out.println("nextToken = " + nextToken);
        }
        StringBuffer sb = new StringBuffer();
        int listSize = list.size();
        if(listSize > 2) {
            sb.append(list.get(0));
            sb.append(":");
            //sb.append(list.get(2));
            sb.append(list.get(listSize -1));
        }
        return sb.toString();

        /*
        String result = sb.toString();
        System.out.println("appid = " + appid);
        System.out.println("shortappid = " + getShortApplicationId());
        System.out.println("extractedShortAppId = " + result);
        System.out.println("calc short equals xtract:" + (getShortApplicationId().equals(result)) );
        return result;
         */

    }
 
    /**
    * How long to wait in seconds before giving up on a transaction
    */
    public void setTimeoutSecs(String timeoutSecs)  {
        debug("in setTimeoutSecs");
        String oldTimeoutSecs = this.timeoutSecs;
        this.timeoutSecs = timeoutSecs;
        support.firePropertyChange("timeoutSecs",
                                   oldTimeoutSecs,
                                   this.timeoutSecs);
    }
 
    /**
    * Return the time to wait in seconcs
    */
    public String getTimeoutSecs()  {
        debug("in getTimeoutSecs");
        return this.timeoutSecs;
    }
   
    protected long getTimeout() {
        return new Long(timeoutSecs).longValue();
    }

    protected void debug(String message) {
        log(message);
        System.out.println(message);
    }
 
    public HAStore()  {
        info = "S1AS7.0EE HAStore/1.0";
        threadName = "HAStore";
        storeName = "HAStore";

        long timeout = new Long(timeoutSecs).longValue();
        long timeout2 = new Long(timeoutSecs2).longValue();
        haErr = new HAErrorManager(timeout, threadName);
        haErrLoad = new HAErrorManager(timeout, threadName);                
        haErrRemove = new HAErrorManager(timeout, threadName);
        haErrRemoveExpired = new HAErrorManager(timeout, threadName);
        haErrExpiredKeys = new HAErrorManager(timeout, threadName);
        haErrKeys = new HAErrorManager(timeout, threadName);
        haErrSize = new HAErrorManager(timeout, threadName);
        //begin trial fix for 6526592
        haErrClear = new HAErrorManager(timeout2, threadName);
        //end trial fix for 6526592
        haErrExists = new HAErrorManager(timeout, threadName);
        haErrExists2 = new HAErrorManager(timeout, threadName);

        if (_logger == null) {
            _logger = LogDomains.getLogger(LogDomains.WEB_LOGGER);
        }
        setLogLevel();

        //initialize sessions cache
        sessions = new BaseCache();
        sessions.init(_maxBaseCacheSize, _loadFactor, null);

        /*
        try {
          Logger.setLogWriter(new PrintWriter(
            new FileOutputStream("logfile.out"), true));
          Logger.setLogLevel(Logger.INFO);
        }
        catch ( FileNotFoundException e ) {
          log("Clustra JDBC log file could not be opened");
        }
         */
    }
 
    public int getSize() throws IOException {
        //debug("in getSize");
        return getSize(blobSessionTable);
    }
 
    /**
     * Return the number of Sessions present in this Store.
     *
     * @exception IOException if an input/output error occurs
     */
    public int getSize(String sessionTable) throws IOException {
        //debug("in getSize");

        int size = 0;
        //only want count for sessions for this app               
        String sizeSql = "SELECT COUNT(id) FROM " + sessionTable
            + " WHERE appid = ?";
        Connection conn = getConnection(false);
        ResultSet rst = null;

        try {
            if (preparedSizeSql == null) {
                preparedSizeSql = conn.prepareStatement(sizeSql);
            }
            preparedSizeSql.setString(1, getApplicationId());
            rst = executeStatement(preparedSizeSql, true, haErrSize);

            if (rst.next()) {
                size = rst.getInt(1);
            }
            ((Connection)conn).commit();
        }
        catch(SQLException e) {
            try{((Connection)conn).rollback();}catch(SQLException ee){} 
            IOException ex1 =
                (IOException) new IOException("Error from HA Store: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        finally {
            closeResultSet(rst);
        }

        return size;
    }

    /**
    * Return an array containing the session identifiers of all Sessions
    * currently saved in this Store.  If there are no such Sessions, a
    * zero-length array is returned.
    *
    * @exception IOException if an input/output error occurred
    */ 
    public String[] keys() throws IOException  {
        //debug("in keys");
        return keys(blobSessionTable);
    }
   
    /**
     * Called by our background reaper thread to check if Sessions
     * saved in our store are subject of being expired. If so expire
     * the Session and remove it from the Store.
     * Note: this is an aggregate form of this method
     *
     */
    public void processStaleCachedSessions() {
        ServerConfigLookup lookup = new ServerConfigLookup();
        if(!lookup.getStaleSessionCheckingFromConfig()) {
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.finest("stale session checking disabled");
            }
            return;
        }
        if( !EEHADBHealthChecker.isOkToProceed() ) {
            return;
        }        
        Connection connection = null;
        try {
            connection = getConnectionValidated(false);
        } catch (IOException ex) {
        }
        //bail out if cannot get a valid connection
        if (connection == null) {
            return;
        }
       
        try {
            this.removeStaleCachedSessions(connection, CHUNK_SIZE);           
        }       
        catch (IOException ex) {           
            ex.printStackTrace();
        }       
       
        return;       

    }   
   
    /**
     * Called by our background reaper thread to check if Sessions
     * saved in our store are subject of being expired. If so expire
     * the Session and remove it from the Store.
     * Note: this is an aggregate form of this method
     *
     */
    public void processExpires() {
        if( !EEHADBHealthChecker.isOkToProceed() ) {
            return;
        }        
        Connection connection = null;
        try {
            connection = getConnectionValidated(false);
        } catch (IOException ex) {
        }
        //bail out if cannot get a valid connection
        if (connection == null) {
            return;
        }
       
        try {
            this.removeExpiredSessions(connection, CHUNK_SIZE);           
        }       
        catch (IOException ex) {           
            ex.printStackTrace();
        }       
       
        return;       

    }
   
    /**
     * this method returns an array of cached session ids
     * @return String[] array of session ids
     */   
    private String[] getSessionIds() {
        BaseCache mainStoreCachedSessions = this.getMainStoreCache();
        String[] ids = null;
        int numberOfIds = mainStoreCachedSessions.getEntryCount();
        ArrayList idsList = new ArrayList(numberOfIds);
        Iterator keysIter = mainStoreCachedSessions.keys();
        while(keysIter.hasNext()) {
            //String nextKey = (String)keysIter.next();
            idsList.add((String)keysIter.next());
        }
        String[] template = new String[idsList.size()];
        ids = (String[])idsList.toArray(template);
        return ids;
    }
   
    private void removeStaleCachedSessions(Connection connection, int chunksize) throws IOException {
        String[] ids = getSessionIds();
        boolean finished = false;
        int chunk = chunksize;
        int idsSize = ids.length;
        if(idsSize == 0) {
            //nothing to do
            return;
        }
        int startIdx = 0;
        int endIdx = 0;
        if (chunksize > idsSize) {
            chunk = idsSize;
        }
        endIdx = startIdx + chunk;
        while (!finished) {
            removeStaleCachedSessions(connection, ids, startIdx, endIdx);
            startIdx = endIdx + 1;
            endIdx = startIdx + chunk;
            if(startIdx >= idsSize - 1) {
                finished = true;
                break;
            }
            if(endIdx >= idsSize - 1) {
                endIdx = idsSize = 1;
            }
        }
    }
   
    private void removeStaleCachedSessions(Connection connection, String[] ids, int startIdx, int endIdx)
        throws IOException
    {
        if(_logger.isLoggable(Level.FINEST)) {
            _logger.finest("removeStaleCachedSessions: start=" + startIdx + " end=" + endIdx);
        }
        ResultSet rst = null;
        String[] keys = null;
        ArrayList keyList = new ArrayList(100);
        ArrayList staleIdList = new ArrayList(100);
        if (connection == null) {
            return;
        }
       
        String inClause = getInClause(ids, startIdx, endIdx);
        String keysSql = "SELECT id, lastaccess FROM " + blobSessionTable
            + " WHERE appid = ?"
            + " AND id IN " + inClause;
        if(_logger.isLoggable(Level.FINEST)) {
            _logger.finest("keysSql = " + keysSql);
        }
        try {
            haErrRemoveExpired.txStart();
            while ( ! haErrRemoveExpired.isTxCompleted() ) {                
                try {
                    preparedKeysSql = connection.prepareStatement(keysSql);
                    preparedKeysSql.setString(1, getApplicationId());
                    rst = preparedKeysSql.executeQuery();

                    //test if set is empty
                    if (!rst.isBeforeFirst()) {
                        //the set was empty
                        rst.close();
                        break;
                    }

                    while (rst.next()) {                                     
                        String nextKey = rst.getString(1);
                        long nextLastAccessTime = rst.getLong(2);
                        ConfigChangeElement nextElem =
                            new ConfigChangeElement(nextKey, new Long(nextLastAccessTime));
                        keyList.add(nextElem);                           
                    }
                    rst.close();
                   
                    BaseCache mainStoreCachedSessions = this.getMainStoreCache();
                    for(int i=0; i<keyList.size(); i++) {
                        //get persistent values
                        ConfigChangeElement nextElem = (ConfigChangeElement)keyList.get(i);
                        String nextId = nextElem.getName();
                        long nextPersistentLastAccessTime = ((Long)nextElem.getValue()).longValue();
                        //get cached values
                        Session cachedSession = (Session)mainStoreCachedSessions.get(nextId);
                        long nextCachedLastAccessTime = ((StandardSession)cachedSession).getLastAccessedTimeInternal();
                        //if cached last access time is < persistent last access time
                        //then add to list of ids to remove from cache - it is stale
                        if(nextCachedLastAccessTime < nextPersistentLastAccessTime) {
                            staleIdList.add(nextId);
                        }
                    }

                    connection.commit();
                    closeStatement(preparedKeysSql);
                    /* for testing
                    for(int i=0; i<staleIdList.size(); i++) {
                        System.out.println("staleIdList[" + i + "]=" + staleIdList.get(i));
                    }
                     */                   
                    String[] template = new String[staleIdList.size()];
                    keys = (String[])staleIdList.toArray(template);
                    /* for testing
                    System.out.println("String[] keys=" + keys);
                    System.out.println("keys.length=" + keys.length);
                    for(int i=0; i<keys.length; i++) {
                        System.out.println("keys[" + i + "]=" + keys[i]);
                    }
                     */
                    removeSessionsForCache(keys);
                    //remove from manager cache too
                    HAManagerBase mgr = (HAManagerBase)this.getManager();
                    mgr.removeSessionIdsFromManagerCache(keys);                  

                    haErrRemoveExpired.txEnd();                  
                    return;
                } catch (SQLException e) {
                    closeStatement(preparedKeysSql);
                    haErrRemoveExpired.checkError(e, connection);
                }                    
            }               
                              
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                connection.rollback();
                closeStatement(preparedKeysSql);
            }
            catch (SQLException ee) {
                ee.printStackTrace();
            }
        } catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HAStore-removeStaleCachedSessions: " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }        
    }
   
    private String getInClause(String[] ids, int startIdx, int endIdx) {
        StringBuffer sb = new StringBuffer();
        sb.append("(");
        for(int i=startIdx; i<endIdx; i++) {           
            if(i != startIdx) {
                sb.append(", ");
            }
            sb.append("'" + ids[i] + "'");           
        }
        sb.append(")");
        return sb.toString();
    }
   
    /**
    * remove a session from the store cache
    * Hercules: added method
    */   
    public void removeFromStoreCache(String id) {
        this.removeSessionFromMainStoreCache(id);       
    }     
   
    /** this method contacts the DB using the given connection and removes the bean from the HADB.
     * @param sessionTable
     * @param connection
     * @throws IOException
     * @return
     */
    private int removeExpiredSessions(Connection connection, int chunk)
        throws IOException {
        //System.out.println("IN NEW removeExpiredSessions");
        int result = 0;
        String[] keys = null;
        ArrayList keyList = new ArrayList(100);
        if (connection == null) {
            return result;
        }
       
        ResultSet rst = null;
       
        long timeNow = System.currentTimeMillis();
        Manager mgr = this.getManager();
        long maxInactiveIntervalMillis = mgr.getMaxInactiveInterval() * 1000;    
        //long relevantTime = (long) (timeNow - maxInactiveIntervalMillis);
        long relevantTime = (long) (timeNow);
       
        //only selecting keys for this app
        PreparedStatement preparedKeysSql = null;
        String keysSql = "SELECT id FROM " + blobSessionTable
            + " WHERE appid = ?"
            + " AND ((lastaccess + (maxinactive * 1000)) < ? OR valid = '0')" + "ORDER BY id";
       
        //only deleting keys for this app
        PreparedStatement preparedDeleteSql = null;       
        String deleteSql = "DELETE FROM " + blobSessionTable
            + " WHERE id BETWEEN ? AND ? AND appid = ?"
            + " AND ((lastaccess + (maxinactive * 1000)) < ? OR valid = '0')";       
       
        try {

            haErrRemoveExpired.txStart();

            while ( ! haErrRemoveExpired.isTxCompleted() ) {                
                try {
                    boolean moreLeft = true;
                    while (moreLeft) {
                        preparedKeysSql = connection.prepareStatement(keysSql);
                        preparedKeysSql.setString(1, getApplicationId());
                        preparedKeysSql.setLong(2, relevantTime);
                        rst = preparedKeysSql.executeQuery();
                       
                        //test if set is empty
                        if (!rst.isBeforeFirst()) {
                            //the set was empty
                            rst.close();
                            moreLeft = false;
                            break;
                        }
                       
                        int rowno = 0;
                        String keyLow = null;
                        String keyHigh = null;
                        boolean chunkSizeReached = false;
                        while (rst.next()) {
                            if (rowno == 0) {
                                keyLow = rst.getString(1);
                            }
                            keyHigh = rst.getString(1);
                            keyList.add(rst.getString(1));
                            if(++rowno >= chunk) {
                                chunkSizeReached = true;
                                break;
                            }                           
                        }
                        if(!chunkSizeReached) {
                            moreLeft = false;
                        }
                        rst.close();
                       
                        preparedDeleteSql = connection.prepareStatement(deleteSql);
                        preparedDeleteSql.setString(1, keyLow);
                        preparedDeleteSql.setString(2, keyHigh);
                        preparedDeleteSql.setString(3, getApplicationId());
                        preparedDeleteSql.setLong(4, relevantTime);
                        int cnt = preparedDeleteSql.executeUpdate();
                        result += cnt;
                        connection.commit();
                    }

                    connection.commit();
                    closeStatement(preparedKeysSql);
                    closeStatement(preparedDeleteSql);
                    /* for testing
                    for(int i=0; i<keyList.size(); i++) {
                        System.out.println("HAStore>>removeExpiredSessions: key[" + i + "]=" + keyList.get(i));
                    }
                     */
                    String[] template = new String[keyList.size()];
                    keys = (String[])keyList.toArray(template);
                    removeSessionsForCache(keys);

                    haErrRemoveExpired.txEnd();
                    _logger.finest("HAStore>>removeExpiredSessions: result = " + result);
                    return result;
                } catch (SQLException e) {
                    closeStatement(preparedKeysSql);
                    closeStatement(preparedDeleteSql);                   
                    haErrRemoveExpired.checkError(e, connection);
                }                    
            }               
                              
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                connection.rollback();
                closeStatement(preparedKeysSql);
                closeStatement(preparedDeleteSql);
            }
            catch (SQLException ee) {
                ee.printStackTrace();
            }
        } catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HAStore-removeExpiredSessions: " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }       
        _logger.finest("HAStore>>removeExpiredSessions: result = " + result);
        return result;       
    }
   
    protected void removeSessionsForCache(String[] sessionIds) {
        HAManagerBase mgr = (HAManagerBase)this.getManager();
        BaseCache mainStoreCachedSessions = this.getMainStoreCache();
        synchronized(mainStoreCachedSessions) {
            for(int i=0; i<sessionIds.length; i++) {
                String nextId = sessionIds[i];
                StandardSession nextSess = null;
                try {
                    //SJSAS 6406580 START
                    //nextSess = (StandardSession)mgr.findSession(nextId);
                    nextSess = (StandardSession)mgr.findSessionFromCacheOnly(nextId);
                    //SJSAS 6406580 END                   
                } catch (IOException ex) {}               
                if(nextSess != null) {
                    //this should expire and fire the notifications
                    //but already removed from store
                    nextSess.expire(true, false);
                    // Take it out of the cache - remove does not handle nulls
                    if(nextId != null) {
                        mainStoreCachedSessions.remove(nextId);
                    }
                }               
            }
        }
    }      
 
    /**
     * Return an array containing the session identifiers of all Sessions
     * currently saved in this Store for this container.  If there are no such Sessions, a
     * zero-length array is returned.
     *
     * @exception IOException if an input/output error occurred
     */
    public String[] keys(String sessionTable) throws IOException  {
        //debug("in keys");
        String[] result = {};
        //only selecting keys for this app
        String keysSql = "SELECT id FROM " + sessionTable
            + " WHERE appid = ?";      

        try {
            Connection conn = getConnectionValidated(false);
        } catch (IOException ex) {
        }
        //bail out if cannot get a valid connection
        if (conn == null) {
            return result;
        }       

        ResultSet rst = null;
        String keys[] = null;

        try {
            if (preparedKeysSql == null) {
                preparedKeysSql = conn.prepareStatement(keysSql);
            }
           
            preparedKeysSql.setString(1, getApplicationId());
            rst = executeStatement(preparedKeysSql, true, haErrKeys);
            if ( rst == null ) {
                if (_debug > 0) {               
                    debug("keys(): No rows returned, returning an empty array");
                }
                return new String[0];
            }

            ArrayList keysArray = new ArrayList();

            for ( int i = 0 ; rst.next() ; i++ )  {
                if (_debug > 0) {
                    debug("in keys, id is " + rst.getString(1));
                }
                keysArray.add(rst.getString(1));
            }

            keys = (String []) keysArray.toArray(new String[0]);
            ((Connection)conn).commit();
        }
        catch(SQLException e) {
            try{((Connection)conn).rollback();}catch(SQLException ee){} 
            IOException ex1 =
                (IOException) new IOException("Error from HA Store: " + e.getMessage()).initCause(e);
            throw ex1;            
        }
        finally {
            closeResultSet(rst);
        }

        return keys;   
   
    }
 
    /**
     * Return an array containing the session identifiers of all Sessions
     * currently saved in this Store for this container that are eligible
     * to be expired. If there are no such Sessions, a
     * zero-length array is returned.
     *
     * @exception IOException if an input/output error occurred
     */ 
    public String[] expiredKeys() throws IOException  {
        //debug("in expiredKeys");
  return expiredKeys(blobSessionTable);
    }
   
    /**
     * Return an array containing the session identifiers of all Sessions
     * currently saved in this Store for this container that are eligible
     * to be expired.  If there are no such Sessions, a
     * zero-length array is returned.
     *
     * @exception IOException if an input/output error occurred
     */
    public String[] expiredKeys(String sessionTable) throws IOException  {
        //System.out.println("in new HAStore>>expiredKeys");
        //debug("in expiredKeys");
        String[] result = {};
        long timeNow = System.currentTimeMillis();
        Manager mgr = this.getManager();
        long maxInactiveIntervalMillis = mgr.getMaxInactiveInterval() * 1000;    
        long relevantTime = (long) (timeNow - maxInactiveIntervalMillis);
        //only selecting keys for this app
        /*
        String expiredKeysSql = "SELECT id FROM " + sessionTable
            + " WHERE appid = '" + getApplicationId() + "'"
            + " AND (lastaccess < " + relevantTime + " OR valid = '0')";
         */
        String expiredKeysSql = "SELECT id FROM " + sessionTable
            + " WHERE appid = ?"
            + " AND (lastaccess < ? OR valid = '0')";       
        //System.out.println("HAStore>>expiredKeys: SQL = " + expiredKeysSql);

        try {
            Connection conn = getConnectionValidated(false);
        } catch (IOException ex) {
        }
        //bail out if cannot get a valid connection
        if (conn == null) {
            return result;
        }
       
        ResultSet rst = null;
        String keys[] = null;

        try {

            haErrExpiredKeys.txStart();

            while ( ! haErrExpiredKeys.isTxCompleted() ) {
                try {                   
                    if (preparedExpiredKeysSql == null) {
                        preparedExpiredKeysSql = conn.prepareStatement(expiredKeysSql);
                    }
                    preparedExpiredKeysSql.setString(1, getApplicationId());
                    preparedExpiredKeysSql.setLong(2, relevantTime);
                    rst = preparedExpiredKeysSql.executeQuery();
                    if ( rst == null ) {
                        if (_debug > 0) {
                            debug("expiredKeys(): No rows returned, returning an empty array");
                        }
                        return new String[0];
                    }

                    ArrayList keysArray = new ArrayList();

                    for ( int i = 0 ; rst.next() ; i++ )  {
                        if (_debug > 0) {
                            debug("in expiredKeys, id is " + rst.getString(1));
                        }
                        keysArray.add(rst.getString(1));
                    }

                    keys = (String []) keysArray.toArray(new String[0]);
                    ((Connection)conn).commit();

                    haErrExpiredKeys.txEnd();
                } catch (SQLException e) {
                    haErrExpiredKeys.checkError(e, conn);
                }                    
            }
              
        }
        catch(SQLException e) {
            try{((Connection)conn).rollback();}catch(SQLException ee){} 
            IOException ex1 =
                (IOException) new IOException("Error from HA Store expiredKeys: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HA Store expiredKeys " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }       
        finally {
            closeResultSet(rst);
        }
        //FIXME remove after testing
        /*
        System.out.println("returning expiredKeys size = " + keys.length);
        for(int i=0; i<keys.length; i++) {
            String nextKey = keys[i];
            System.out.println("key[" + i + "]= " + nextKey);
        }
         */
        return keys;   
    }
   
    /**
    * Load and return the Session associated with the specified session
    * identifier from this Store, without removing it.  If there is no
    * such stored Session, return <code>null</code>.
    *
    * @param id Session identifier of the session to load
    *
    * @exception ClassNotFoundException if a deserialization error occurs
    * @exception IOException if an input/output error occurs
    */
    public synchronized Session load(String id) throws ClassNotFoundException, IOException {
        //debug("in load");
        if(_logger.isLoggable(Level.FINEST)) {
            _logger.finest("IN NEW LOAD METHOD");
        }
        if( !EEHADBHealthChecker.isOkToProceed() ) {
            return null;
        }
        if ( id == null ) {
            if (_debug > 0) {
                debug("in load, id is null, returning null");
            }
            Thread.dumpStack();
            return null;
        }

        // Check to see if it's in our cache first
        //Session session = (Session)sessions.get(id);
        Session session = this.getSessionFromMainStoreCache(id);

        if ( session != null ) {
            if (_debug > 0) {
                debug("Session " + id + " loaded from cache");
            }
            return session;
        }

        ResultSet rst = null;

        HADBConnectionGroup connGroup = null;
        try {
            connGroup = this.getConnectionsFromPool(true);
        } catch (IOException ex) {
            //this means failure to obtain connection
            //we will ignore the exception, log it and return null
            //from the load; protect the thread from crashing
            Object[] params = { "HAStore>>load" };
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure1", params);
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure2", params);
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure3", params);
        }
        if(connGroup == null) {
            if (_debug > 0) {
                debug("HAStore>>load: Failure to obtain connection from pool: returning null");
            }
            ServerConfigLookup config = new ServerConfigLookup();
            String connURL = config.getConnectionURLFromConfig();
            _logger.warning("ConnectionUtil>>getConnectionsFromPool failed using connection URL: " + connURL + " -- returning null. Check connection pool configuration.");
            return null;
        }

        Connection internalConn = connGroup._internalConn;
        Connection externalConn = connGroup._externalConn;
        String shortAppId = null;

        String loadSql = "SELECT id, sessdata, username , ssoid, appid FROM " + blobSessionTable +
        //MERGE was
        //String loadSql = "SELECT id, sessdata FROM " + blobSessionTable +
        //" WHERE id = ?";
        " WHERE id = ? AND appid = ?";

        try {

            haErrLoad.txStart();

            while ( ! haErrLoad.isTxCompleted() ) {               
                try {               

                    preparedLoadSql = internalConn.prepareStatement(loadSql);

                    preparedLoadSql.setString(1, id);
                    preparedLoadSql.setString(2, getApplicationId());
                    rst = preparedLoadSql.executeQuery();

                    //if ( ! rst.next() ) {
                    if ( rst == null || ! rst.next() ) {
                        if (_debug > 0) {
                            debug("No persisted data found for session " + id);
                        }
                        return null;
                    }

                    session = getSession(rst);
                    String appId = rst.getString(5);
                    shortAppId = extractShortApplicationIdFromApplicationId(appId);
                    //((Connection)conn).commit();  NO COMMIT NEEDED
                    preparedLoadSql.close();
                    preparedLoadSql = null;
                    try {
                        externalConn.close();
                    } catch (java.sql.SQLException ex) {}
                    externalConn = null;

                    haErrLoad.txEnd();
                } catch (SQLException e) {
                    closeStatement(preparedLoadSql);
                    preparedLoadSql = null;
                    haErrLoad.checkError(e, internalConn);
                }                    
            }
              
        }
        catch(SQLException e) {
            //try{((Connection)conn).rollback();}catch(SQLException ee){}
            try{internalConn.rollback();}catch(SQLException ee){}
            e.printStackTrace();
            IOException ex1 =
                (IOException) new IOException("Error from HA Store load: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HA Store load " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }        
        finally {
            closeResultSet(rst);      
            if (preparedLoadSql != null) {
                try {
                  preparedLoadSql.close();
                } catch (SQLException e) {}
                preparedLoadSql = null;
            }               
            if (externalConn != null) {
                try {
                    externalConn.close();
                } catch (Exception ex) {}
            }
            //undo the foreground lock that occured during load
            StandardSession stdSess = (StandardSession) session;
            if(stdSess != null && stdSess.isForegroundLocked()) {
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("inHAStore>>load before unlockForeground:lock = " + stdSess.getSessionLock());
                }
                //reduce ref count by 1
                stdSess.unlockForeground();
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("inHAStore>>load after unlockForeground:lock = " + stdSess.getSessionLock());
                }
            }     
        }

        //FIXME for 5053485 remove after testing
        //if( !shortAppId.equals(getShortApplicationId()) ) {
        if( !getShortApplicationId().equals(shortAppId) ) {
            //debug("Loaded session does not belong in this container-shortAppId = " + shortAppId + " getShortApplicationId() = " + getShortApplicationId());
            ((HAManagerBase)manager).removeSessionFromManagerCache(session);
            return null;
        }
       
        this.putSessionInMainStoreCache(session);
        //sessions.put(session.getIdInternal(), session);
        //debug("Loaded session " + id + " from HA Store");
        return session;
    }             
 
    /**
    * Given a result set containing session data, return a session
    * object
    *
    * @param rst
    *   The result set with the session data
    *
    * @return
    *   A newly created session for the given session data, and associated
    *   with this Manager
    */
    protected Session getSession(ResultSet rst)
        throws SQLException, IOException, ClassNotFoundException
    {
        Session _session = null;
        BufferedInputStream bis = null;
        Loader loader = null;   
        ClassLoader classLoader = null;
        ObjectInputStream ois = null;
        Container container = manager.getContainer();
        java.security.Principal pal=null; //MERGE chg added
            String ssoId = null
        IOUtilsCaller utilsCaller = null;
           
        try
        {
            //bis = new BufferedInputStream(rst.getBinaryStream(2));
            String id = rst.getString(1); //MERGE was next line
            //rst.getString(1);
            Blob blob = rst.getBlob(2);

            //Get the username from database MERGE added code
            String username = rst.getString(3);
            ssoId = rst.getString(4)
            //debug("HAStore.getSession()  id="+id+"  username ="+username+";"); 
            if((username !=null) && (!username.equals(""))) {
                if (_debug > 0) {
                    debug("Username retrived from DB is "+username);
                }
                pal = ((com.sun.web.security.RealmAdapter)container.getRealm()).createFailOveredPrincipal(username);
                if (_debug > 0) {
                    debug("principal created using username  "+pal);
                }
            }
            //--SRI 

            bis = new BufferedInputStream(blob.getBinaryStream());
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.finest("loaded seasion from hastore, length = "+blob.length());
            }
            if (container != null) {
                loader = container.getLoader();
            }

            if (loader != null) {
                classLoader = loader.getClassLoader();
            }
           
            //Bug 4832603 : EJB Reference Failover
            //HERCULES FIXME: for now reverting back
            //need to look at new EJBUtils and related serialization code
            /*
          if (classLoader != null) {
            ois = new CustomObjectInputStream(bis, classLoader);
          }
          else {
            ois = new ObjectInputStream(bis);
          }
         
            //ois = EJBUtils.getInputStream(bis, classLoader, true, true);
            //end - Bug 4832603 
             */         
            if (classLoader != null) {
                if( (utilsCaller = this.getWebUtilsCaller()) != null) {
                    try {
                        ois = utilsCaller.createObjectInputStream(bis, true, classLoader);
                    } catch (Exception ex) {}
                }
            }
            if (ois == null) {
                ois = new ObjectInputStream(bis);
            }
           
            if(ois != null) {
                try {
                    _session = readSession(manager, ois);
                }
                finally {
                    if (ois != null) {
                        try {
                            ois.close();
                            bis = null;
                        }
                        catch (IOException e) {
                        }
                    }
                }
            }
        }
        catch(ClassNotFoundException e)
        {
            System.err.println("getSession :"+e.getMessage());
            throw e;
        }
        catch(IOException e)
        {
            //System.err.println("getSession IOException :"+e.getMessage());
            throw e;
        }
        _session.setNew(false);
        //FIXME removed after review
        //((StandardSession) _session).notifyHttpSessionActivationListenersSessionDidActivate();
        //MERGE added next 2 lines
        _session.setPrincipal(pal);
            //MERGE
            if((ssoId !=null) && (!ssoId.equals("")))
                    associate(ssoId, _session);
            //__MERGE
        if (_debug > 0) {
            debug("getSession principal="+pal+" was added to session="+_session);
        }
        return _session;
   
 
    protected void associate(String ssoId, Session _session) {
        if (_debug > 0) {
            debug("Inside associate() -- HAStore");
        }
        Container parent = manager.getContainer();
        SingleSignOn sso = null;
        while ((sso == null) && (parent != null)) {
            if (_debug > 0) {
                 debug("Inside associate()  while loop -- HAStore");
            }
        if (!(parent instanceof Pipeline)) {
            if (_debug > 0) {
                 debug("Inside associate()  parent instanceof Pipeline -- HAStore");
            }
            parent = parent.getParent();
            continue;
        }
        Valve valves[] = ((Pipeline) parent).getValves();
        for (int i = 0; i < valves.length; i++) {
            if (valves[i] instanceof SingleSignOn) {
                 if (_debug > 0) {
                    debug("Inside associate()  valves[i] instanceof SingleSignOn -- HAStore");
                 }
                 sso = (SingleSignOn) valves[i];
                 break;
             }
        }
        if (sso == null)
            parent = parent.getParent();
        }
        if (sso != null) {
            if (_debug > 0) {
                debug("Inside associate() sso != null");
            }
            //SingleSignOnEntry ssoEntry = ((HASingleSignOn)sso).lookup(ssoId);
            SingleSignOnEntry ssoEntry = ((HASingleSignOn)sso).lookupEntry(ssoId);
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("Inside associate() ssoEntry = "+ssoEntry);
                }
                if(ssoEntry!=null)
                    ssoEntry.addSession(sso, _session);
        }

    }
   
    //SJSAS 6406580 START
    /**
    * Remove the Session with the specified session identifier from
    * this Store, if present.  If no such Session is present, this method
    * takes no action.
    *
    * @param id Session identifier of the Session to be removed
    *
    * @exception IOException if an input/output error occurs
    */
    public void remove(String id) throws IOException  {

        if (_debug > 0) {
            debug("in remove");
        }

        if ( id == null )  {
            if (_debug > 0) {
                debug("In remove, got a null id");
            }
            return;
        }
        Manager mgr = this.getManager();
        if(mgr instanceof HAManagerBase) {
            HAManagerBase pMgr = (HAManagerBase)mgr;
            pMgr.doRemove(id);
        } else {
            this.removeSynchronized(id);
        }
    }
   
    /**
    * Remove the Session with the specified session identifier from
    * this Store, if present.  If no such Session is present, this method
    * takes no action. This is the synchronized version of the remove
    * method which must be used by the singleton store - store pool
    * elements use the doRemove method
    *
    * @param id Session identifier of the Session to be removed
    *
    * @exception IOException if an input/output error occurs
    */
    public synchronized void removeSynchronized(String id) throws IOException  {

        if (_debug > 0) {
            debug("in remove");
        }

        if ( id == null )  {
            if (_debug > 0) {
                debug("In remove, got a null id");
            }
            return;
        }
       
        HADBConnectionGroup connGroup = null;
        try {
            connGroup = this.getConnectionsFromPool(true);
        } catch (IOException ex) {
            //this means failure to obtain connection
            //we will ignore the exception log it and return null
            //from the load; protect the thread from crashing
            Object[] params = { "HAStore>>remove" };
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure1", params);
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure2", params);
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure3", params);           
        }
        if(connGroup == null) {
            if (_debug > 0) {
                debug("HAStore>>remove: Failure to obtain connection from pool");
            }
            ServerConfigLookup config = new ServerConfigLookup();
            String connURL = config.getConnectionURLFromConfig();
            _logger.warning("ConnectionUtil>>getConnectionsFromPool failed using connection URL: " + connURL + " -- returning null. Check connection pool configuration.");
            return;
        }
       
        Connection internalConn = connGroup._internalConn;
        Connection externalConn = connGroup._externalConn;
   
        // Take it out of the cache
        sessions.remove(id);

        //String removeSql = "DELETE FROM "+ blobSessionTable + " WHERE id = ?";
        String removeSql = "DELETE FROM "+ blobSessionTable
                + " WHERE id = ? AND appid = ?";

        try {

            haErrRemove.txStart();

            while ( ! haErrRemove.isTxCompleted() ) {
                try {               
                    //this is instVar but will always be re-prepared now               
                    preparedRemoveSql = internalConn.prepareStatement(removeSql);

                    preparedRemoveSql.setString(1, id);
                    preparedRemoveSql.setString(2, getApplicationId());
                    preparedRemoveSql.executeUpdate();

                    //((Connection)conn).commit();  NO COMMIT NEEDED          
                    preparedRemoveSql.close();
                    preparedRemoveSql = null;
                    try {
                        externalConn.close();
                    } catch (java.sql.SQLException ex) {}
                    externalConn = null;

                    haErrRemove.txEnd();
                } catch (SQLException e) {
                    closeStatement(preparedRemoveSql);
                    preparedRemoveSql = null;
                    haErrRemove.checkError(e, internalConn);
                }                    
            }
              
        }
        catch(SQLException e) {
            //try{((Connection)conn).rollback();}catch(SQLException ee){}
            try{internalConn.rollback();}catch(SQLException ee){}
            IOException ex1 =
                (IOException) new IOException("Error from HA Store remove: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HA Store remove " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }       
        finally {      
            if (preparedRemoveSql != null) {
                try {
                  preparedRemoveSql.close();
                } catch (SQLException e) {}
                preparedRemoveSql = null;
            }               
            if (externalConn != null) {
                try {
                    externalConn.close();
                } catch (Exception ex) {}
            }
        }                    
       
        if (_debug > 0) {
            debug("Removed session " + id + " from HA Store");
        }
    }        
       
    /**
    * Remove the Session with the specified session identifier from
    * this Store, if present.  If no such Session is present, this method
    * takes no action. (This is the non-synchronized version of remove
    * called by a store element from the pool, not the singleton store
    * which must use removeSynchronized
    *
    * @param id Session identifier of the Session to be removed
    *
    * @exception IOException if an input/output error occurs
    */
    public void doRemove(String id) throws IOException  {
       
        if (_debug > 0) {
            debug("in remove");
        }

        if ( id == null )  {
            if (_debug > 0) {
                debug("In remove, got a null id");
            }
            return;
        }
       
        HADBConnectionGroup connGroup = null;
        try {
            connGroup = this.getConnectionsFromPool(true);
        } catch (IOException ex) {
            //this means failure to obtain connection
            //we will ignore the exception log it and return null
            //from the load; protect the thread from crashing
            Object[] params = { "HAStore>>remove" };
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure1", params);
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure2", params);
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure3", params);           
        }
        if(connGroup == null) {
            if (_debug > 0) {
                debug("HAStore>>remove: Failure to obtain connection from pool");
            }
            ServerConfigLookup config = new ServerConfigLookup();
            String connURL = config.getConnectionURLFromConfig();
            _logger.warning("ConnectionUtil>>getConnectionsFromPool failed using connection URL: " + connURL + " -- returning null. Check connection pool configuration.");
            return;
        }
       
        Connection internalConn = connGroup._internalConn;
        Connection externalConn = connGroup._externalConn;
   
        // Take it out of the cache
        sessions.remove(id);

        //String removeSql = "DELETE FROM "+ blobSessionTable + " WHERE id = ?";
        String removeSql = "DELETE FROM "+ blobSessionTable
                + " WHERE id = ? AND appid = ?";

        try {

            haErrRemove.txStart();

            while ( ! haErrRemove.isTxCompleted() ) {
                try {               
                    //this is instVar but will always be re-prepared now
                    preparedRemoveSql = internalConn.prepareStatement(removeSql);

                    preparedRemoveSql.setString(1, id);
                    preparedRemoveSql.setString(2, getApplicationId());
                    preparedRemoveSql.executeUpdate();

                    //((Connection)conn).commit();  NO COMMIT NEEDED          
                    preparedRemoveSql.close();
                    preparedRemoveSql = null;
                    try {
                        externalConn.close();
                    } catch (java.sql.SQLException ex) {}
                    externalConn = null;

                    haErrRemove.txEnd();
                } catch (SQLException e) {
                    closeStatement(preparedRemoveSql);
                    preparedRemoveSql = null;                   
                    haErrRemove.checkError(e, internalConn);
                }                    
            }
              
        }
        catch(SQLException e) {
            //try{((Connection)conn).rollback();}catch(SQLException ee){}
            try{internalConn.rollback();}catch(SQLException ee){}
            IOException ex1 =
                (IOException) new IOException("Error from HA Store remove: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HA Store remove " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }       
        finally {      
            if (preparedRemoveSql != null) {
                try {
                  preparedRemoveSql.close();
                } catch (SQLException e) {}
                preparedRemoveSql = null;
            }               
            if (externalConn != null) {
                try {
                    externalConn.close();
                } catch (Exception ex) {}
            }
        }                    
       
        if (_debug > 0) {
            debug("Removed session " + id + " from HA Store");
        }
    }
    //SJSAS 6406580 END          
   
    /**
    * Remove the Session with the specified session identifier from
    * this Store, if present.  If no such Session is present, this method
    * takes no action.
    *
    * @param id Session identifier of the Session to be removed
    *
    * @exception IOException if an input/output error occurs
    */  
    public synchronized void clear() throws IOException {
        if (_debug > 0) {
            debug("in clear");
        }
        //System.out.println("IN NEW VERSION OF CLEAR");
        // Clear out the cache too
        sessions = new BaseCache();
        sessions.init(_maxBaseCacheSize, _loadFactor, null);       
       
        HADBConnectionGroup connGroup = null;
        try {
            connGroup = this.getConnectionsFromPool(true);
        } catch (IOException ex) {
            //this means failure to obtain connection
            //we will ignore the exception but return null
            //from the load; protect the thread from crashing
            Object[] params = { "HAStore>>clear" };
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure1", params);
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure2", params);
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure3", params);           
        }
        if(connGroup == null) {
            if (_debug > 0) {
                debug("HAStore>>clear: Failure to obtain connection from pool");
            }
            ServerConfigLookup config = new ServerConfigLookup();
            String connURL = config.getConnectionURLFromConfig();
            _logger.warning("ConnectionUtil>>getConnectionsFromPool failed using connection URL: " + connURL + " -- returning null. Check connection pool configuration.");
            return;
        }
       
        Connection internalConn = connGroup._internalConn;
        Connection externalConn = connGroup._externalConn;
       
        try {           
            this.removeAllSessions(internalConn, CHUNK_SIZE);
            try {
                externalConn.close();
            }
            catch (java.sql.SQLException ex) {
                ex.printStackTrace();
            }
            externalConn = null;           
        }       
        catch (IOException ex) {
            _logger.log(Level.WARNING,
                   "clear: failed to remove all the sessions for this app " +
                           this.getApplicationId());           
            ex.printStackTrace();
        }
        finally {
            if (externalConn != null) {
                try {
                    externalConn.close();
                }
                catch (java.sql.SQLException ex) {
                    ex.printStackTrace();
                }
                externalConn = null;
            }
        }        
       
        return;

    }    
   
    /** Remove all the sessions associated with the application
     * @param connection
     * @param chunk the chunk size to use for the delete operations
     */
    public void removeAllSessions(Connection connection, int chunk)
        throws IOException {
           
        if (connection == null) {
            return;
        }
        //System.out.println("IN NEW removeAllSessions");
        int result = 0;       
        ResultSet rst = null;
        PreparedStatement preparedKeysSql = null;
        //only selecting sessions  for this application       
        String keysSql = "SELECT id FROM " + blobSessionTable +
                        " WHERE appid = ? ORDER BY id";       
        //only deleting sessions  for this container
        PreparedStatement preparedDeleteSql = null;
        String deleteSql = "DELETE FROM " + blobSessionTable +
                         " WHERE id BETWEEN ? AND ? AND appid = ?";
       
        try {

            haErrClear.txStart();

            while ( ! haErrClear.isTxCompleted() ) {                
                try {
                    boolean moreLeft = true;
                    while (moreLeft) {
                        preparedKeysSql = connection.prepareStatement(keysSql);
                        preparedKeysSql.setString(1, this.getApplicationId());
                        rst = preparedKeysSql.executeQuery();
                       
                        //test if set is empty
                        if (!rst.isBeforeFirst()) {
                            //the set was empty
                            rst.close();
                            moreLeft = false;
                            break;
                        }                       
                       
                        int rowno = 0;
                        String keyLow = null;
                        String keyHigh = null;
                        boolean chunkSizeReached = false;
                        while (rst.next()) {
                            if (rowno == 0) {
                                keyLow = rst.getString(1);
                            }
                            keyHigh = rst.getString(1);
                            if(++rowno >= chunk) {
                                chunkSizeReached = true;
                                break;
                            }                           
                        }
                        if(!chunkSizeReached) {
                            moreLeft = false;
                        }
                        rst.close();
                       
                        preparedDeleteSql = connection.prepareStatement(deleteSql);
                        preparedDeleteSql.setString(1, keyLow);
                        preparedDeleteSql.setString(2, keyHigh);
                        preparedDeleteSql.setString(3, this.getApplicationId());
                        int cnt = preparedDeleteSql.executeUpdate();
                        result += cnt;                       
                        connection.commit();
                    }

                    connection.commit();
                    closeStatement(preparedKeysSql);
                    closeStatement(preparedDeleteSql);

                    haErrClear.txEnd();
                    _logger.finest("HAStore>>removeAllSessions - successfully removed " + result + " sessions");                 
                    return;
                } catch (SQLException e) {
                    closeStatement(preparedKeysSql);
                    closeStatement(preparedDeleteSql);
                    preparedKeysSql = null;
                    preparedDeleteSql = null;
                    haErrClear.checkError(e, connection);
                }                    
            }               
                              
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                connection.rollback();
                closeStatement(preparedKeysSql);
                closeStatement(preparedDeleteSql);
            }
            catch (SQLException ee) {
                ee.printStackTrace();
            }
        } catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HAStore-removeAllSessions: " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }       
        _logger.finest("HAStore>removeAllSessions - successfully removed " + result + " sessions");
        return;       
    }    
   
    /**
     * Save the specified Session into this Store.  Any previously saved
     * information for the associated session identifier is replaced.
     *
     * @param session Session to be saved
     *
     * @exception IOException if an input/output error occurs
     */
    public void save(Session session) throws IOException {
     
        if(_logger.isLoggable(Level.FINEST)) {
            _logger.finest("XXXXXXX In save, id is " + session.getIdInternal());
        }
       
        if( !EEHADBHealthChecker.isOkToProceed() ) {
            return;
        }       
        // begin 6470831 do not save if session is not valid
        if( !((StandardSession)session).getIsValid() ) {
            return;
        }
        // end 6470831         
       
        boolean isMonitoringEnabled = ServerConfigReader.isMonitoringEnabled();
        long startTime = 0L;
        //long endTime = 0L;

        //added for monitoring
        HAManagerBase mgr = (HAManagerBase) this.getManager();
        WebModuleStatistics stats = mgr.getWebModuleStatistics();
        if(isMonitoringEnabled) {
            startTime = System.currentTimeMillis();
        }
        //added for monitoring

        HASession sess = (HASession) session;
        boolean previousDirtyFlag = sess.isDirty();
        if (_debug > 0) {
            debug("in save");
        }

        //Connection conn = getConnection(false);

        //IntHolder length = new IntHolder();
        //BufferedInputStream in = getInputStream(session, length);
        //moving this getByteArray call in the dirty update and insert case
        //and leaving it out of the non-dirty update -- performance improvement
        //byte[] in = getByteArray(session);
        byte[] in = null;
       
        boolean sessionIsPersistent = false;
        boolean sessionInStoreOk = false;
        try {
            sessionIsPersistent = sessionInStore(session);
            sessionInStoreOk = true;
        } catch (IOException ex) {
            sessionInStoreOk = false;
        }

        if(!sessionInStoreOk) {
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST,
                            "HAStore-save: sessionInStore failed: aborting save ");
            }           
            return;
        }
       
        try  {
            if(sessionIsPersistent) {
            //if ( sessionInStore(session) ) {
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("Session is in store");
                }
                if (sess.isDirty()) {
                    if(_logger.isLoggable(Level.FINEST)) {
                        _logger.finest("Session IS Dirty");
                    }
                    in = getByteArray(session);
                    updateSessionBlob(session, in);
                } else {
                    if(_logger.isLoggable(Level.FINEST)) {
                        _logger.finest("Session is NOT Dirty");
                    }
                    updateSessionNoDataBlob(session, in);
                }
            }       
            else {
                in = getByteArray(session);
                insertSessionBlob(session, in);
            }
            sess.setDirty(false);
            if(isMonitoringEnabled) {
                long endTime = System.currentTimeMillis();
                stats.processBackgroundSave(endTime - startTime);
            }
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.finest("session class= " + sess.getClass().getName());
                _logger.finest("after save: session dirty= " + sess.isDirty());
            }
        }
        catch ( IOException e ) {
            sess.setDirty(previousDirtyFlag);               
            // Calling routines don't print the stack trace :(
            e.printStackTrace();
            throw e;
        }
        finally {
            /*
            if (in != null) {
                in.close();
            }
             */
        }
        if (_debug > 0) {
            debug("Saved session " + session.getIdInternal() + " into HA Store");
        }

        // Put it in the cache
        this.putSessionInMainStoreCache(session);
        //sessions.put(session.getIdInternal(), session);
   
    }       
          
    /**
     * Save the specified Session into this Store.  Any previously saved
     * information for the associated session identifier is replaced.
     *
     * @param session Session to be saved
     *
     * @exception IOException if an input/output error occurs
     */
    public void valveSave(Session session) throws IOException {
        if(_logger.isLoggable(Level.FINEST)) {
            _logger.finest("XXXXXXX In valveSave, id is " + session.getIdInternal());
        }
        if( !EEHADBHealthChecker.isOkToProceed() ) {
            return;
        }
        // begin 6470831 do not save if session is not valid
        if( !((StandardSession)session).getIsValid() ) {
            return;
        }
        // end 6470831       
        boolean isMonitoringEnabled = ServerConfigReader.isMonitoringEnabled();
        HASession sess = (HASession) session;      
        boolean previousDirtyFlag = sess.isDirty();
        if (_debug > 0) {
            debug("in valveSave");
        }
     
        //added for monitoring
        HAManagerBase mgr = (HAManagerBase) this.getManager();
        WebModuleStatistics stats = mgr.getWebModuleStatistics();
        long getConnStartTime = 0L;
        if(isMonitoringEnabled) {
            getConnStartTime = System.currentTimeMillis();
        }
        //end added for monitoring
        HADBConnectionGroup connGroup = null;
        try {
            connGroup = this.getConnectionsFromPool(true);
        } catch (IOException ex) {
            //this means failure to obtain connection
            //we will ignore the exception log it but return
            //from the valveSave without storing the session
            Object[] params = { "HAStore>>valveSave" };
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure1", params);
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure2", params);
            _logger.log(Level.SEVERE, "hastore.hadbConnectionFailure3", params);           
        }
        //added for monitoring     
        if(isMonitoringEnabled) {
            long getConnEndTime = System.currentTimeMillis();
            stats.processGetConnectionFromPool(getConnEndTime - getConnStartTime);
        }
        //end added for monitoring
     
        //if we cannot get a connection then quit
        if (connGroup == null) {
            return;
        }
        Connection internalConn = connGroup._internalConn;
        Connection externalConn = connGroup._externalConn;
        //IntHolder length = new IntHolder();
        //BufferedInputStream in = getInputStream(session, length);
        //moving this getByteArray call in the dirty update and insert case
        //and leaving it out of the non-dirty update -- performance improvement       
        //byte[] in = getByteArray(session);
        byte[] in = null;
        boolean sessionIsPersistent = false;
        boolean sessionInStoreOk = false;
        try {
            sessionIsPersistent = sessionInStore(session, internalConn);
            sessionInStoreOk = true;
        } catch (IOException ex) {
            sessionInStoreOk = false;
            if (externalConn != null) {
                try {
                    externalConn.close();
                } catch (Exception ex2) {}
            }           
        }    
        if(!sessionInStoreOk) {
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST,
                    "HAStore-valveSave: sessionInStore failed: aborting save ");
            }           
            return;
        }
        try {
            //if ( sessionInStore(session, internalConn) ) {
            if(sessionIsPersistent) {
                //_logger.finest("Session is in store");
                if (sess.isDirty()) {
                    //_logger.finest("Session IS Dirty");
                    in = getByteArray(session);
                    updateSessionNewBlob(session, in, internalConn);
                } else {
                    //_logger.finest("Session is NOT Dirty");
                    updateSessionNoDataNewBlob(session, in, internalConn);
                }
            }
            else {
                //_logger.finest("Session NOT in store");
                in = getByteArray(session);
                insertSessionNewBlob(session, in, internalConn);
            }
            sess.setDirty(false);
            long getConnCloseStartTime = 0L;
            if(isMonitoringEnabled) {
                getConnCloseStartTime = System.currentTimeMillis();
            }           
            try {
                externalConn.close();
            } catch (java.sql.SQLException ex) {}
            externalConn = null;
            if(isMonitoringEnabled) {
                long getConnCloseEndTime = System.currentTimeMillis();
                stats.processPutConnectionIntoPool(getConnCloseEndTime - getConnCloseStartTime);
            }                       
        }
        catch ( IOException e ) {
            sess.setDirty(previousDirtyFlag);
            // Calling routines don't print the stack trace :(
            e.printStackTrace();
            throw e;
        }
        finally {
            if (externalConn != null) {
                try {
                    externalConn.close();
                } catch (Exception ex) {}
            }
            /*
            if (in != null) {
              in.close();
            }
             */
        }

        //debug("Saved session " + session.getIdInternal() + " into HA Store");

        // Put it in the cache
        //not for valveSave
        //sessions.put(session.getIdInternal(), session);
        this.putSessionInMainStoreCache(session);
       
    }   
   
    /**
    * Insert a session into the HA store
    *
    * @param session
    *   The session to store
    *
    * @param in
    *   The stream of serialized data from the session
    *
    * @param length
    *   The length of the stream 
    */
    private void insertSessionNewBlob(Session session, byte[] in,
        Connection connection) throws IOException {
        if(_logger.isLoggable(Level.FINEST)) {
            _logger.finest("IN insertSessionNewBlob");
        }
        //note: appid is newly added column
        String insertSql = "INSERT INTO " + blobSessionTable + " ("+
              "id, sessdata, valid, maxinactive, lastaccess, appid, username, ssoid) " +
              //MERGE was next line
              //"id, sessdata, valid, maxinactive, lastaccess, appid) " +
              "VALUES (?, ?, ?, ?, ?, ?, ?, ?)";

        try {

            haErr.txStart();

            while ( ! haErr.isTxCompleted() ) {               
                try {               
                    preparedInsertSql = connection.prepareStatement(insertSql);
                    preparedInsertSql.setString(1, session.getIdInternal());
                    //preparedInsertSql.setBinaryStream(2, in, buflength);
                    preparedInsertSql.setBytes(2, in);
                    preparedInsertSql.setString(3, ((StandardSession)session).getIsValid()?"1":"0");
                    preparedInsertSql.setInt(4, session.getMaxInactiveInterval());
                    preparedInsertSql.setLong(5, ((StandardSession)session).getLastAccessedTimeInternal());
                    //added column
                    preparedInsertSql.setString(6, getApplicationId());
                    //end added column     
                    //added column for userName --SRI  MERGE
                    if(session.getPrincipal() !=null){
                        if (_debug > 0) {
                            debug(" session.getPrincipal().getName() ="+session.getPrincipal().getName());
                        }
                        preparedInsertSql.setString(7, session.getPrincipal().getName()); //null shpould be replaced with the username from session
                    } else {
                        preparedInsertSql.setString(7, ""); //FIXME: it should be SQL NULL
                        if (_debug > 0) {
                            debug(" session.getPrincipal() ="+session.getPrincipal());
                        }
                    }
                    //end added column       --SRI     
                    //MERGE
                    String ssoId = ((HASession)session).getSsoId();
                    if (ssoId == null
                        ssoId = "";
                    preparedInsertSql.setString(8, ssoId);
                    //__MERGE
                    preparedInsertSql.executeUpdate();
                    //((Connection)lobConn).commit(); DO NOT NEED COMMIT
                    if(_logger.isLoggable(Level.FINEST)) {
                        _logger.finest("inserted session, length = "+ in.length);
                    }
                    preparedInsertSql.close();
                    preparedInsertSql = null;

                    haErr.txEnd();
                } catch (SQLException e) {
                    closeStatement(preparedInsertSql);
                    preparedInsertSql = null;                   
                    haErr.checkError(e, connection);
                }                    
            }
              
        }
        catch ( SQLException e ) {
            //try{((Connection)lobConn).rollback();}catch(SQLException ee){}
            try{connection.rollback();}catch(SQLException ee){}

            if(haErr.isPrimaryKeyViolation(e)) {
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("Redirecting primary key violation from HA Store insertSessionNewBlob to update: " + e.getMessage());
                }
                this.updateSessionNewBlob(session, in, connection);
                return;
            }

            IOException ex1 =
                (IOException) new IOException("Error from HA Store insertSessionNewBlob: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HA Store insertSessionNewBlob " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }        
        finally {
            if (preparedInsertSql != null) {
                try {
                    preparedInsertSql.close();
                } catch (Exception ex) {}
            }
        }
    }
   
    /**
    * Update  a session into the HA store
    *
    * @param session
    *   The session to store
    *
    * @param in
    *   The stream of serialized data from the session
    *
    * @param length
    *   The length of the stream 
    */
    private void updateSessionNewBlob(Session session, byte[] in,
        Connection connection) throws IOException {
        if(_logger.isLoggable(Level.FINEST)) {
            _logger.finest("IN updateSessionNewBlob");
        }
        HAManagerBase mgr = (HAManagerBase) this.getManager();
        WebModuleStatistics stats = mgr.getWebModuleStatistics();     
        boolean isMonitoringEnabled = ServerConfigReader.isMonitoringEnabled();
        //note: appid is newly added column     
        String updateSql = "UPDATE " + blobSessionTable +
              //" SET sessdata = ?, valid = ?, maxinactive = ?, lastaccess = ? , appid = ? , username = ?, ssoid=?" +
              " SET sessdata = ?, valid = ?, maxinactive = ?, lastaccess = ? , username = ?, ssoid=?" +
              //MERGE was next line
              //" SET sessdata = ?, valid = ?, maxinactive = ?, lastaccess = ? , appid = ? " +
              //"WHERE id = ?";
              "WHERE id = ? AND appid = ?";

        long startPrepTime = 0L;
        try {
            haErr.txStart();

            while ( ! haErr.isTxCompleted() ) {
                try {                   
                    if(isMonitoringEnabled) {
                        startPrepTime = System.currentTimeMillis();
                    }                   
                    preparedUpdateSql = connection.prepareStatement(updateSql);
                    //preparedUpdateSql.setBinaryStream(1, in, buflength);
                    preparedUpdateSql.setBytes(1, in);
                    preparedUpdateSql.setString(2, ((StandardSession)session).getIsValid()?"1":"0");
                    preparedUpdateSql.setInt(3, session.getMaxInactiveInterval());
                    preparedUpdateSql.setLong(4, ((StandardSession)session).getLastAccessedTimeInternal());
                    //added column
                    //preparedUpdateSql.setString(5, getApplicationId());
                    //end added column

                    //added column for userName --sri  MERGE
                    if(session.getPrincipal() !=null){
                        if (_debug > 0) {
                            debug(" session.getPrincipal().getName() ="+session.getPrincipal().getName());
                        }
                        preparedUpdateSql.setString(5, session.getPrincipal().getName()); //null shpould be replaced with the username from session
                    } else {
                        //   preparedUpdateSql.setNull(6, java.sql.Types.VARCHAR);
                        preparedUpdateSql.setString(5, ""); //FIXME Its hould be  SQL NULL
                        if (_debug > 0) {
                            debug(" session.getPrincipal() ="+session.getPrincipal());
                        }
                    }
                    //end added column       --sri   
                    //MERGE
                    String ssoId = ((HASession)session).getSsoId();
                    if (ssoId == null
                        ssoId = "";
                    preparedUpdateSql.setString(6, ssoId);
                    //__MERGE
                    preparedUpdateSql.setString(7, session.getIdInternal());
                    preparedUpdateSql.setString(8, getApplicationId());
                    if(isMonitoringEnabled) {
                        long endPrepTime = System.currentTimeMillis();
                        stats.processStatementPrepBlock(endPrepTime - startPrepTime);
                    }

                    long startTime = 0L;   
                    if(isMonitoringEnabled) {
                        startTime = System.currentTimeMillis();
                    }
                    preparedUpdateSql.executeUpdate();
                    if(isMonitoringEnabled) {
                        long endTime = System.currentTimeMillis();
                        stats.processExecuteStatement(endTime - startTime);         
                    }
                    long commitStartTime = 0L;   
                    if(isMonitoringEnabled) {
                        commitStartTime = System.currentTimeMillis();
                    }
                    /* DO NOT HAVE TO COMMIT
                    ((Connection)lobConn).commit();
                    if(isMonitoringEnabled) {
                        long commitEndTime = System.currentTimeMillis();
                        stats.processCommit(commitEndTime - commitStartTime);         
                    }
                     */
                    if(_logger.isLoggable(Level.FINEST)) {
                        _logger.finest("updated session, length = "+ in.length);
                    }
                    preparedUpdateSql.close();
                    preparedUpdateSql = null;

                    haErr.txEnd();
                } catch (SQLException e) {
                    closeStatement(preparedUpdateSql);
                    preparedUpdateSql = null;                   
                    haErr.checkError(e, connection);
                }                   
            }

        }
        catch ( SQLException e ) {
            //try{((Connection)lobConn).rollback();}catch(SQLException ee){}
            try{connection.rollback();}catch(SQLException ee){}
            IOException ex1 =
                (IOException) new IOException("Error from HA Store updateSessionNewBlob: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HA Store updateSessionNewBlob: " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }       
        finally {
            if (preparedUpdateSql != null) {
                try {
                    preparedUpdateSql.close();
                } catch (Exception ex) {}
            }
        }   
    }
                      
    /**
    * Update  a session into the HA store
    * leave out the data; just update other fields
    *
    * @param session
    *   The session to store
    *
    * @param in
    *   The stream of serialized data from the session
    *
    * @param length
    *   The length of the stream 
    */
    private void updateSessionNoDataNewBlob(Session session, byte[] in,
        Connection connection) throws IOException {
        
        //note: appid is newly added column        
        String updateSql = "UPDATE " + blobSessionTable +
              //" SET valid = ?, maxinactive = ?, lastaccess = ? , appid = ? ,username = ? , ssoid = ?" +
              " SET valid = ?, maxinactive = ?, lastaccess = ? , username = ? , ssoid = ?" +
              //MERGE was next line
              //" SET valid = ?, maxinactive = ?, lastaccess = ? , appid = ? " +
              //"WHERE id = ?";
              "WHERE id = ? AND appid = ?";

        try {
           
            haErr.txStart();

            while ( ! haErr.isTxCompleted() ) {                
                try {
                    preparedUpdateNoSessionSql = connection.prepareStatement(updateSql);
                    //leave out this column
                    //preparedUpdateNoSessionSql.setBinaryStream(1, in, buflength);
                    preparedUpdateNoSessionSql.setString(1, ((StandardSession)session).getIsValid()?"1":"0");
                    preparedUpdateNoSessionSql.setInt(2, session.getMaxInactiveInterval());
                    preparedUpdateNoSessionSql.setLong(3, ((StandardSession)session).getLastAccessedTimeInternal());
                    //added column
                    //preparedUpdateNoSessionSql.setString(4, getApplicationId());
                    //end added column

                    //added column for userName --sri
                    if(session.getPrincipal() !=null){
                        if (_debug > 0) {
                            debug(" session.getPrincipal().getName() ="+session.getPrincipal().getName());
                        }
                        preparedUpdateNoSessionSql.setString(4, session.getPrincipal().getName());
                    } else
                        preparedUpdateNoSessionSql.setString(4,""); //null shpould be replaced with the username from session
                    //end added column       --sri     

                    //MERGE
                    String ssoId = ((HASession)session).getSsoId();
                    if (ssoId == null)
                        ssoId = "";
                    preparedUpdateNoSessionSql.setString(5, ssoId)
                    //__MERGE

                    preparedUpdateNoSessionSql.setString(6, session.getIdInternal());
                    preparedUpdateNoSessionSql.setString(7, getApplicationId());

                    preparedUpdateNoSessionSql.executeUpdate();
                    //connection.commit(); DO NOT NEED COMMIT
                    preparedUpdateNoSessionSql.close();
                    preparedUpdateNoSessionSql = null;

                    haErr.txEnd();
                } catch (SQLException e) {
                    closeStatement(preparedUpdateNoSessionSql);
                    preparedUpdateNoSessionSql = null;                   
                    haErr.checkError(e, connection);
                }                   
            }

        }
        catch ( SQLException e ) {
            try { connection.rollback(); } catch (Exception e1) {};
            IOException ex1 =
                (IOException) new IOException("Error from HA Store updateSessionNoDataNewBlob: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HA Store updateSessionNoDataNewBlob: " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }
        finally {
            if (preparedUpdateNoSessionSql != null) {
                try {
                    preparedUpdateNoSessionSql.close();
                } catch (Exception ex) {}
            }
        }    
    }   
 
    /**
    * Determine whether a session exists in the HA Store
    * @param session
    */
    public boolean sessionInStore(Session session) throws IOException 
        return sessionInStore(session, blobSessionTable);
    }
       
 
    /**
    * Determine whether a session exists in the HA Store
    * @param session
    * @param storeTable    
    */
    public boolean sessionInStore(Session session, String storeTable) throws IOException 
        //if HADB Health check fails then abort by throwing IOException
        if( !EEHADBHealthChecker.isOkToProceed() ) {
            throw new IOException("Error from HA Store-sessionInStore: HADBHealthCheck reports HADB down");
        }       
        // Check the cache first.  Since we write every session to disk,
        // if it's in cache, it's in the store
        //FIXME after testing - next line replaces one following
        Session sess = this.getSessionFromMainStoreCache(session.getIdInternal());
        //Session sess = (Session)sessions.get(session.getIdInternal());
        if ( sess != null ) {
            return true;
        }

        Connection conn = getConnection(false);

        //String existsSql = "SELECT id FROM " + storeTable + " WHERE id = ?";
        String existsSql = "SELECT id FROM " + storeTable
                + " WHERE id = ? AND appid = ?";
        ResultSet rs = null;
        boolean found = false;

        try {
            haErrExists.txStart();
            while ( ! haErrExists.isTxCompleted() ) {       
       
                try {
                    if (preparedExistsSql == null) {
                        preparedExistsSql = conn.prepareStatement(existsSql);
                    }

                    preparedExistsSql.setString(1, session.getIdInternal());
                    preparedExistsSql.setString(2, getApplicationId());
                    rs = preparedExistsSql.executeQuery();

                    if ( rs == null || ! rs.next() )  {
                        found = false;
                    }
                    else {
                        found = true;
                    }
                    ((Connection)conn).commit();
                    haErrExists.txEnd();
                } catch (SQLException e) {
                    //check for re-tryables
                    haErrExists.checkError(e, ((Connection)conn) );
                }
            }
        } catch (SQLException e) {
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST,
                            "HAStore-sessionInStore: EXCEPTION HERE  " +
                            existsSql);
            }           
            try{((Connection)conn).rollback();}catch(SQLException ee){} 
            IOException ex1 =
                (IOException) new IOException("Error from HA Store-sessionInStore: " + e.getMessage()).initCause(e);
            throw ex1;           
        } catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HAStore-sessionInStore: " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }        
        finally  {
            closeResultSet(rs);
        }

        return found;
    }  
 
    /**
    * Determine whether a session exists in the HA Store
    * @param session
    * @param conn
    */
    public boolean sessionInStore(Session session, Connection conn) throws IOException 
        return sessionInStore(session, conn, blobSessionTable);
   
 
    /**
    * Determine whether a session exists in the HA Store
    * called by valveSave
    * @param session
    * @param conn
    * @param storeTable
    */
    public boolean sessionInStore(Session session, Connection conn, String storeTable) throws IOException 
        //if HADB Health check fails then abort by throwing IOException
        if( !EEHADBHealthChecker.isOkToProceed() ) {
            throw new IOException("Error from HA Store-sessionInStore: HADBHealthCheck reports HADB down");
        }       
        // Check the cache first.  Since we write every session to disk,
        // if it's in cache, it's in the store

        //get from the cache in the main store instance
        HAManagerBase mgr = (HAManagerBase)this.getManager();
        HAStore backgroundStore = (HAStore) mgr.getStore();
        BaseCache sesstbl = backgroundStore.getSessions();
        Session sess = (Session)sesstbl.get(session.getIdInternal());
        if ( sess != null ) {
          return true;
       

        //String existsSql = "SELECT id FROM " + storeTable + " WHERE id = ?";
        String existsSql = "SELECT id FROM " + storeTable
                + " WHERE id = ? AND appid = ?";
        ResultSet rs = null;
        boolean found = false;
       
        try {
            haErrExists2.txStart();
            while ( ! haErrExists2.isTxCompleted() ) {               
                try {      
                    preparedExistsSql2 = conn.prepareStatement(existsSql);
                    preparedExistsSql2.setString(1, session.getIdInternal());
                    preparedExistsSql2.setString(2, getApplicationId());
                    //rs = executeStatement(preparedExistsSql2, true);
                    rs = preparedExistsSql2.executeQuery();                   

                    if ( rs == null || ! rs.next() )  {
                        found = false;
                    }
                    else {
                        found = true;
                    }
                    ((Connection)conn).commit();
                    preparedExistsSql2.close();
                    preparedExistsSql2 = null;
                    haErrExists2.txEnd();               
                } catch (SQLException e) {
                    closeStatement(preparedExistsSql2);
                    preparedExistsSql2 = null;                   
                    //check for re-tryables
                    haErrExists2.checkError(e, ((Connection)conn) );
                }
            }
        } catch (SQLException e) {
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST,
                            "HAStore-sessionInStore: EXCEPTION HERE  " +
                            existsSql);
            }           
            try{((Connection)conn).rollback();}catch(SQLException ee){} 
            IOException ex1 =
                (IOException) new IOException("Error from HA Store-sessionInStore: " + e.getMessage()).initCause(e);
            throw ex1;           
        } catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HAStore-sessionInStore: " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }       
        finally  {
            closeResultSet(rs);
            if (preparedExistsSql2 != null) {
                try {
                    preparedExistsSql2.close();
                } catch (SQLException e) {}
                preparedExistsSql2 = null;
            }
        }

        return found;
    }     
   
    /**
    * Insert a session into the HA store
    *
    * @param session
    *   The session to store
    *
    * @param in
    *   The stream of serialized data from the session
    *
    * @param length
    *   The length of the stream 
    */
    private void insertSessionBlob(Session session, byte[] in)
        throws IOException {
        //note: appid is newly added column
        String insertSql = "INSERT INTO " + blobSessionTable + " ("+
              "id, sessdata, valid, maxinactive, lastaccess, appid, username, ssoid) " +
              "VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
              //MERGE was next 2 lines
              //"id, sessdata, valid, maxinactive, lastaccess, appid) " +
              //"VALUES (?, ?, ?, ?, ?, ?)";

        try {

            haErr.txStart();

            while ( ! haErr.isTxCompleted() ) {               
                try {               
                    if (preparedInsertSql == null) {
                        preparedInsertSql = conn.prepareStatement(insertSql);
                    }
                    preparedInsertSql.setString(1, session.getIdInternal());
                    preparedInsertSql.setBytes(2, in);
                    preparedInsertSql.setString(3, ((StandardSession)session).getIsValid()?"1":"0");
                    preparedInsertSql.setInt(4, session.getMaxInactiveInterval());
                    preparedInsertSql.setLong(5, ((StandardSession)session).getLastAccessedTimeInternal());
                    //added column
                    preparedInsertSql.setString(6, getApplicationId());
                    //end added column     
                    //added column for userName --sri MERGE
                    if(session.getPrincipal() !=null){
                        if (_debug > 0) {
                            debug(" session.getPrincipal().getName() ="+session.getPrincipal().getName());
                        }
                        preparedInsertSql.setString(7, session.getPrincipal().getName());
                    } else
                        preparedInsertSql.setString(7, ""); //null shpould be replaced with the username from session
                    //end added column       --sri     
                                    //MERGE
                    String ssoId = ((HASession)session).getSsoId();
                    if (ssoId == null
                        ssoId = "";
                    preparedInsertSql.setString(8, ssoId);
                    //__MERGE 

                    preparedInsertSql.executeUpdate();
                    //((Connection)lobConn).commit();  NO COMMIT NEEDED
                    if(_logger.isLoggable(Level.FINEST)) {
                        _logger.finest("inserted session, length = "+ in.length);
                    }

                    haErr.txEnd();
                } catch (SQLException e) {
                    haErr.checkError(e, conn);
                }                   
            }
                 
        }
        catch ( SQLException e ) {
            //try{((Connection)lobConn).rollback();}catch(SQLException ee){}
            try{conn.rollback();}catch(SQLException ee){}

            if(haErr.isPrimaryKeyViolation(e)) {
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("Redirecting primary key violation from HA Store insertSessionNewBlob to update: " + e.getMessage());
                }
                this.updateSessionBlob(session, in);
                return;
            }
          
            IOException ex1 =
                (IOException) new IOException("Error from HA Store insertSessionBlob: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HA Store insertSessionBlob: " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }        
    }    
   
    /**
    * Update  a session into the HA store
    *
    * @param session
    *   The session to store
    *
    * @param in
    *   The stream of serialized data from the session
    *
    * @param length
    *   The length of the stream 
    */
    private void updateSessionBlob(Session session, byte[] in)
        throws IOException {
        //note: appid is newly added column     
        String updateSql = "UPDATE " + blobSessionTable +
              //" SET sessdata = ?, valid = ?, maxinactive = ?, lastaccess = ? , appid = ? , username=?, ssoid=?" +
              " SET sessdata = ?, valid = ?, maxinactive = ?, lastaccess = ? , username=?, ssoid=?" +             
              //MERGE was next line
              //" SET sessdata = ?, valid = ?, maxinactive = ?, lastaccess = ? , appid = ? " +
              //"WHERE id = ?";
              "WHERE id = ? AND appid = ?";

        try {
            haErr.txStart();

            while ( ! haErr.isTxCompleted() ) {
                try {               
                    if (preparedUpdateSql == null) {
                        preparedUpdateSql = conn.prepareStatement(updateSql);
                    }
                    //preparedUpdateSql.setBinaryStream(1, in, buflength);
                    preparedUpdateSql.setBytes(1, in);
                    preparedUpdateSql.setString(2, ((StandardSession)session).getIsValid()?"1":"0");
                    preparedUpdateSql.setInt(3, session.getMaxInactiveInterval());
                    preparedUpdateSql.setLong(4, ((StandardSession)session).getLastAccessedTimeInternal());
                    //added column
                    //preparedUpdateSql.setString(5, getApplicationId());
                    //end added column     
                   //added column for userName --sri MERGE
                    if(session.getPrincipal() !=null){
                        if (_debug > 0) {
                            debug(" session.getPrincipal().getName() ="+session.getPrincipal().getName());
                        }
                        preparedUpdateSql.setString(5, session.getPrincipal().getName());
                    } else
                        preparedUpdateSql.setString(5, ""); //FIXME: Should be SQL NULL
                   //end added column       --sri    
                    //MERGE
                    String ssoId = ((HASession)session).getSsoId();
                    if (ssoId == null
                        ssoId = "";
                    preparedUpdateSql.setString(6, ssoId);
                    //__MERGE
                    preparedUpdateSql.setString(7, session.getIdInternal());
                    preparedUpdateSql.setString(8, getApplicationId());

                    preparedUpdateSql.executeUpdate();
                    //((Connection)lobConn).commit(); COMMIT NOT NEEDED
                    if(_logger.isLoggable(Level.FINEST)) {
                        _logger.finest("updated session, length = "+ in.length);
                    }

                    haErr.txEnd();
                } catch (SQLException e) {
                    haErr.checkError(e, conn);
                }                    
            }
              
        }
        catch ( SQLException e ) {
            //try{((Connection)lobConn).rollback();}catch(SQLException ee){}
            try{conn.rollback();}catch(SQLException ee){}
            IOException ex1 =
                (IOException) new IOException("Error from HA Store updateSessionBlob: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HA Store updateSessionBlob: " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }        
    }             
   
    /**
    * Update  a session into the HA store
    * leave out the data; just update other fields
    *
    * @param session
    *   The session to store
    *
    * @param in
    *   The stream of serialized data from the session
    *
    * @param length
    *   The length of the stream 
    */
    private void updateSessionNoDataBlob(Session session, byte[] in)
        throws IOException {
        if(_logger.isLoggable(Level.FINEST)) {
            _logger.finest("IN updateSessionNoDataBlob");
        }

        //note: appid is newly added column
        String updateSql = "UPDATE " + blobSessionTable +
              //" SET valid = ?, maxinactive = ?, lastaccess = ? , appid = ? , username= ? , ssoid=?" +
              " SET valid = ?, maxinactive = ?, lastaccess = ? , username= ? , ssoid=?" +
              //MERGE was next line
              //" SET valid = ?, maxinactive = ?, lastaccess = ? , appid = ? " +         
              //"WHERE id = ?";
              "WHERE id = ? AND appid = ?";

        try {
            haErr.txStart();

            while ( ! haErr.isTxCompleted() ) {               
                try {
                    if (preparedUpdateNoSessionSql == null) {
                        preparedUpdateNoSessionSql = conn.prepareStatement(updateSql);                       
                    }
                    //leave out this column
                    //preparedUpdateNoSessionSql.setBinaryStream(1, in, buflength);
                    preparedUpdateNoSessionSql.setString(1, ((StandardSession)session).getIsValid()?"1":"0");
                    preparedUpdateNoSessionSql.setInt(2, session.getMaxInactiveInterval());
                    preparedUpdateNoSessionSql.setLong(3, ((StandardSession)session).getLastAccessedTimeInternal());
                    //added column
                    //preparedUpdateNoSessionSql.setString(4, getApplicationId());
                    //end added column      
                    //added column for userName --sri MERGE
                    if(session.getPrincipal() !=null){
                        if (_debug > 0) {
                            debug(" session.getPrincipal().getName() ="+session.getPrincipal().getName());
                        }
                        preparedUpdateNoSessionSql.setString(4, session.getPrincipal().getName());
                    } else
                        preparedUpdateNoSessionSql.setString(4, ""); //FIXME: should be sql null
                    //end added column       --sri           
                                    //MERGE
                    String ssoId = ((HASession)session).getSsoId();
                    if (ssoId == null
                        ssoId = "";
                    preparedUpdateNoSessionSql.setString(5, ssoId);
                    //__MERGE
                    preparedUpdateNoSessionSql.setString(6, session.getIdInternal());
                    preparedUpdateNoSessionSql.setString(7, getApplicationId());

                    preparedUpdateNoSessionSql.executeUpdate();
                    //conn.commit(); COMMIT NOT NEEDED

                    haErr.txEnd();
                } catch (SQLException e) {
                    haErr.checkError(e, conn);
                }                    
            }
              
        }
        catch ( SQLException e ) {
            try{conn.rollback();}catch(SQLException ee){}
            IOException ex1 =
                (IOException) new IOException("Error from HA Store updateSessionNoDataBlob: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch (HATimeoutException tex) {
            IOException ex2 =
                (IOException) new IOException("Timeout from HA Store updateSessionNoDataBlob: " + tex.getMessage()).initCause(tex);
            throw ex2;           
        }       
    }  

    /**
    * Create an input stream for the session that we can then pass to
    * the HA Store.
    *
    * @param session
    *   The session we are streaming
    *
    * @param length
    *   Will be set to the length of the input stream.
    *
    */
    protected BufferedInputStream getInputStream(Session session, IntHolder length)
      throws IOException {
        ByteArrayOutputStream bos = null;
        ByteArrayInputStream bis = null;
        ObjectOutputStream oos = null;
        BufferedInputStream in = null;
        //FIXME removed after review
        //((StandardSession) session).notifyHttpSessionActivationListenersSessionWillPassivate();

        IOUtilsCaller utilsCaller = null;
        try {
            bos = new ByteArrayOutputStream();
            //HERCULES FIXME - for now reverting back
            //need to re-examine EJBUtils and related serialization classes
            //Bug 4832603 : EJB Reference Failover
            /*  was this
            oos = new ObjectOutputStream(new BufferedOutputStream(bos));
             end was this */
              //oos = EJBUtils.getOutputStream(new BufferedOutputStream(bos), true); 
            //end - Bug 4832603
           
            if( (utilsCaller = this.getWebUtilsCaller()) != null) {
                try {
                    oos = utilsCaller.createObjectOutputStream(new BufferedOutputStream(bos), true);
                } catch (Exception ex) {}
            }
            //use normal ObjectOutputStream if there is a failure during stream creation
            if(oos == null) {
                oos = new ObjectOutputStream(new BufferedOutputStream(bos));
            }           

            writeSession(session, oos);
            oos.close();
            oos = null;

            byte[] obs = bos.toByteArray();
            //for monitoring
            boolean isMonitoringEnabled = ServerConfigReader.isMonitoringEnabled();
            if(isMonitoringEnabled) {
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("IN HAStore>>getInputStream for monitoring");
                }
                HAManagerBase mgr = (HAManagerBase)this.getManager();
                WebModuleStatistics stats = mgr.getWebModuleStatistics();
                stats.processSessionSize(obs.length);
            }
            //end for monitoring
            bis = new ByteArrayInputStream(obs, 0, obs.length);
            in = new BufferedInputStream(bis, obs.length);
            length.value = obs.length;
        }
        finally {
            if ( oos != null )  {
                oos.close();
            }

            if (bis != null) {
                bis.close();
            }
        }

        return in;
    }
   
    /**
    * Create an input stream for the session that we can then pass to
    * the HA Store.
    *
    * @param session
    *   The session we are streaming
    *
    * @param length
    *   Will be set to the length of the input stream.
    *
    */
    protected byte[] getByteArray(Session session)
      throws IOException {
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        //FIXME removed after review
        //((StandardSession) session).notifyHttpSessionActivationListenersSessionWillPassivate();

        IOUtilsCaller utilsCaller = null;
        byte[] obs;
        try {
            bos = new ByteArrayOutputStream();
            //HERCULES FIXME - for now reverting back
            //need to re-examine EJBUtils and related serialization classes
            //Bug 4832603 : EJB Reference Failover
            /*  was this
            oos = new ObjectOutputStream(new BufferedOutputStream(bos));
             end was this */
              //oos = EJBUtils.getOutputStream(new BufferedOutputStream(bos), true); 
            //end - Bug 4832603
           
            if( (utilsCaller = this.getWebUtilsCaller()) != null) {
                try {
                    oos = utilsCaller.createObjectOutputStream(new BufferedOutputStream(bos), true);
                } catch (Exception ex) {}
            }
            //use normal ObjectOutputStream if there is a failure during stream creation
            if(oos == null) {
                oos = new ObjectOutputStream(new BufferedOutputStream(bos));
            }           

            writeSession(session, oos);
            oos.close();
            oos = null;

            obs = bos.toByteArray();
            //for monitoring
            boolean isMonitoringEnabled = ServerConfigReader.isMonitoringEnabled();
            if(isMonitoringEnabled) {
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("IN HAStore>>getInputStream for monitoring");
                }
                HAManagerBase mgr = (HAManagerBase)this.getManager();
                WebModuleStatistics stats = mgr.getWebModuleStatistics();
                stats.processSessionSize(obs.length);
            }
            //end for monitoring
        }
        finally {
            if ( oos != null )  {
                oos.close();
            }
        }

        return obs;
    }    
   
    /**
    * Execute a query that returns results.  This takes care of all the retry
    * logic needed to work against the Clustra HA Store
    *
    * @param stmt
    *   The statement you want to execute
    *
    * @param isQuery
    *   Set this to true if this is a query which returns a result set.
    *   Set this to false if this is a statement which has no results.
    *
    * @param errorMgr
    *   the instance of HAErrorManager to use
    *
    * @return
    *   The result set returned from executing this query
    *
    * @exception
    *    IOException if there was a problem executing the query
    */ 
    protected ResultSet executeStatement(PreparedStatement stmt, boolean isQuery, HAErrorManager errorMgr)
     throws IOException {
        ResultSet rst = null;

        try {
            errorMgr.txStart();
            while ( ! errorMgr.isTxCompleted() ) {
                try {
                    if ( isQuery ) {
                        rst = stmt.executeQuery();
                    }
                    else  {
                        stmt.executeUpdate();
                    }
                    errorMgr.txEnd();
                }
                catch ( SQLException e ) {
                    errorMgr.checkError(e, conn);
                    if (_debug > 0) {
                        debug("Got a retryable exception from HA Store: " + e.getMessage());
                    }
                }
            }
        }
        catch(SQLException e) {
            IOException ex1 =
                (IOException) new IOException("Error from HA Store: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch ( HATimeoutException e ) {
            IOException ex1 =
                (IOException) new IOException("Timeout from HA Store " + e.getMessage()).initCause(e);
            throw ex1;           
        }

        return rst;   
    }   

    /**
    * Execute a query that returns results.  This takes care of all the retry
    * logic needed to work against the Clustra HA Store
    *
    * @param stmt
    *   The statement you want to execute
    *
    * @param isQuery
    *   Set this to true if this is a query which returns a result set.
    *   Set this to false if tihs is a statement which has no results.
    *
    * @return
    *   The result set returned from executing this query
    *
    * @exception
    *    IOException if there was a problem executing the query
    */ 
    protected ResultSet executeStatement(PreparedStatement stmt, boolean isQuery)
     throws IOException {
        ResultSet rst = null;

        try {
            haErr.txStart();
            while ( ! haErr.isTxCompleted() ) {
                try {
                    if ( isQuery ) {
                        rst = stmt.executeQuery();
                    }
                    else  {
                        stmt.executeUpdate();
                    }
                    haErr.txEnd();
                }
                catch ( SQLException e ) {
                    haErr.checkError(e, conn);
                    if (_debug > 0) {
                        debug("Got a retryable exception from HA Store: " + e.getMessage());
                    }
                }
            }
        }
        catch(SQLException e) {
            IOException ex1 =
                (IOException) new IOException("Error from HA Store: " + e.getMessage()).initCause(e);
            throw ex1;           
        }
        catch ( HATimeoutException e ) {
            IOException ex1 =
                (IOException) new IOException("Timeout from HA Store " + e.getMessage()).initCause(e);
            throw ex1;           
        }

        return rst;   
    }
   
    /**
    * Helper routine that closes a result set
    */
    protected void closeResultSet(ResultSet rst) {
        try {
            if (rst != null) {
                rst.close();
            }
        }
        catch(SQLException e) {
        }
    }

    /**
    * Helper routine that cleans up statements and cached connection
    * and resets sessions cache
    */   
    public void cleanup() {
        closeStatements();
        closeConnection();
        //this.setSessions(new Hashtable());
        this.setSessions(new BaseCache());
        sessions.init(_maxBaseCacheSize, _loadFactor, null);
    }
 
    /**
     * Check the connection associated with this store, if it's not
     * <code>null</code> or open try to close it.
     *
     */ 
    protected void closeConnection() {
        try {
            if ( conn != null && (! conn.isClosed()) ) {
                conn.close();
                conn = null;
            }
        } catch (java.sql.SQLException ex) {}
        conn = null;
        ConnectionUtil util = this.getConnectionUtil();
        if(util != null) {
            util.clearCachedConnection();
        }
    }
 
    protected void closeStatements() {
        PreparedStatement[] statements =
           {preparedKeysSql, preparedExpiredKeysSql, preparedRemoveExpiredKeysSql, preparedSizeSql, preparedDualSql,
           preparedLoadSql, preparedInsertSql, preparedRemoveSql, preparedClearSql,
           preparedUpdateSql, preparedExistsSql, preparedExistsSql2, preparedUpdateNoSessionSql};
        for(int i=0; i<statements.length; i++) {
            PreparedStatement nextStatement =
                (PreparedStatement) statements[i];
            closeStatement(nextStatement);
        }
        this.clearStatementReferences();
    }
   
    protected void clearStatementReferences() {
        preparedKeysSql = null;
        preparedExpiredKeysSql = null;
        preparedRemoveExpiredKeysSql = null;
        preparedSizeSql = null;
        preparedDualSql = null;
        preparedLoadSql = null;
        preparedInsertSql = null;
        preparedRemoveSql = null;
        preparedClearSql = null;
        preparedUpdateSql = null;
        preparedExistsSql = null;
        preparedExistsSql2 = null;
        preparedUpdateNoSessionSql = null;        
    }
 
    protected void closeStatement(PreparedStatement stmt) {
        if (stmt != null) {
            try
            {
              stmt.close();
            } catch (java.sql.SQLException ex) {}
        }
    }
 
    //FIXME this is for junit test
    //probably remove it
    public void privateForTestSetConnection(Connection connection) {
        conn = connection;
    }
 
    public Connection privateGetConnection(boolean autocommit) throws IOException {
        return this.getConnection(autocommit);
    }
 
    /**
    * return a HADBConnectionGroup from the pool
    */   
    protected HADBConnectionGroup getConnectionsFromPool() throws IOException {
        ConnectionUtil util = this.getConnectionUtil();
        return util.getConnectionsFromPool();
    }
   
    /**
    * return a HADBConnectionGroup from the pool
    * @param autoCommit
    */   
    protected HADBConnectionGroup getConnectionsFromPool(boolean autoCommit) throws IOException {
        ConnectionUtil util = this.getConnectionUtil();
        return util.getConnectionsFromPool(autoCommit);
    }   
 
    /**
     * Get a connection that has been validated
     * Returns <code>null</code> if the connection could not be established.
     *
     * @return <code>Connection</code> if the connection suceeded
     */
    protected Connection getConnectionValidated(boolean autoCommit) throws IOException {
        Connection connection = null;
        boolean keepTrying = true;
        int numRetries = 3;
        int count = 1;
        while(keepTrying) {
            //do the attempt
            connection = this.getConnection(autoCommit);
            boolean connectionValid = this.validateConnection(connection);
            if(connectionValid) {
                keepTrying = false;
            } else {
                try {
                    this.cleanupConnectionCaches();
                } catch (Exception ex) {}
                //this forces getting a new connection
                //conn is an instVar
                conn = null;
                this.threadSleep(100L);
            }
            count++;
            if(count == numRetries)
                keepTrying = false;
        }
        if(conn == null) {
            throw new IOException("Could not obtain viable connection");
        }
        try {
            conn.setAutoCommit(autoCommit);
        } catch ( SQLException ex ) {
        }
        return conn;
    }
 
    protected void cleanupConnectionCaches() {
        this.closeConnection();
        /*
        if(conn != null) {
            try {
                conn.close();
            } catch (Exception ex) {}
        }
         */
  this.closeStatements();
        //this.clearStatementReferences();       
        //done in closeConnection()
        conn = null;       
    }
 
    /**
     * this method runs an sql query against the connection
     * to test its viability
     */   
    protected boolean validateConnection(Connection connection) {
        boolean result = true;
        try {
            //this.getSizeForConnValidation(connection);
            this.testQueryForConnValidation(connection);
        } catch (IOException ex) {
            result = false;
        } catch (java.lang.NullPointerException ex1) {
            result = false;
        }
        return result;
    }
   
    /**
     * Return the number of Sessions present in this Store.
     *
     * This method is used simply to validate a connection
     *
     * @exception IOException if an input/output error occurs
     */
    public int getSizeForConnValidation(Connection connection) throws IOException {
        if (_debug > 0) {
            debug("in getSizeForConnValidation");
        }

        int size = 0;
        //only want count for sessions for this app
        String sizeSql = "SELECT COUNT(id) FROM " + blobSessionTable
            + " WHERE appid = ?";
        ResultSet rst = null;

        try {
            if (preparedSizeSql == null) {
                preparedSizeSql = connection.prepareStatement(sizeSql);
            }
            preparedSizeSql.setString(1, getApplicationId());
            rst = executeStatement(preparedSizeSql, true);

            if (rst.next()) {
                size = rst.getInt(1);
            }
            ((Connection)connection).commit();
        }
        catch(SQLException e) {
            try{((Connection)connection).rollback();}catch(SQLException ee){} 
            IOException ex1 =
                (IOException) new IOException("Error from HA Store: " + e.getMessage()).initCause(e);
            throw ex1;             
           
        }
        finally {
            closeResultSet(rst);
        }

        return size;
    }
   
    public int testQueryForConnValidation(Connection connection) throws IOException {
        try {
            connection.getMetaData();
            return 1;
        }
        catch(SQLException ex) {
            IOException ex1 =
                (IOException) new IOException("Error from HA Store Connection Validation: " + ex.getMessage()).initCause(ex);
            throw ex1;
        }
    }
   
    protected void threadSleep(long sleepTime) {

        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            ;
        }

    }     
 
    /**
     * Check the connection associated with this store, if it's
     * <code>null</code> or closed try to reopen it.
     * Returns <code>null</code> if the connection could not be established.
     *
     * @return <code>Connection</code> if the connection suceeded
     */
    protected Connection getConnection() throws IOException {
        return getConnection(true);
    }
 
    /**
     * Check the connection associated with this store, if it's
     * <code>null</code> or closed try to reopen it.
     * set autoCommit to autoCommit
     * Returns <code>null</code> if the connection could not be established.
     *
     * @return <code>Connection</code> if the connection suceeded
     */ 
    protected Connection getConnection(boolean autoCommit) throws IOException {
        ConnectionUtil util = this.getConnectionUtil();
        //get returned connection into cached connection conn
        conn = util.getConnection(autoCommit);
        return conn;
    }
   
    /**
     * not intended for public use
     * close the cached connection
     */
    public void privateCloseCachedConnection() {
        if(conn != null) {
            try {
                conn.close();
            } catch (Exception e) {}
        }
    }
   
}
TOP

Related Classes of com.sun.enterprise.ee.web.sessmgmt.HAStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.