Package org.jvnet.glassfish.comms.replication.sessmgmt

Source Code of org.jvnet.glassfish.comms.replication.sessmgmt.SipTransactionPersistentManager$PrivilegedStoreLoadSipSession

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. 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.
*/
package org.jvnet.glassfish.comms.replication.sessmgmt;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.sip.*;
import javax.servlet.sip.Address;
import javax.servlet.sip.TimerListener;
import com.ericsson.ssa.sip.DialogSet;
import com.ericsson.ssa.sip.PathNode.Type;
import com.ericsson.ssa.sip.RemoteLockException;
import com.ericsson.ssa.sip.PersistentSipSessionManagerBase;
import com.ericsson.ssa.sip.SipApplicationSessionImpl;
import com.ericsson.ssa.sip.SipApplicationSessionUtil;
import com.ericsson.ssa.sip.SipSessionDialogImpl;
import com.ericsson.ssa.sip.timer.ServletTimerImpl;
import com.sun.appserv.ha.spi.BackingStore;
import com.sun.appserv.ha.spi.BackingStoreException;
import com.sun.appserv.ha.spi.BackingStoreFactory;
import com.sun.appserv.ha.spi.BackingStoreRegistry;
import com.sun.appserv.ha.util.SimpleMetadata;
import com.sun.appserv.ha.uow.ReplicableEntity;
import com.sun.appserv.util.cache.BaseCache;
import com.sun.enterprise.ee.web.sessmgmt.*;

import com.sun.enterprise.web.ServerConfigLookup;
import org.apache.catalina.Globals;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.security.SecurityUtil;
import org.jvnet.glassfish.comms.util.LogUtil;
import org.jvnet.glassfish.comms.replication.dialogmgmt.ReplicationDialogFragmentManager;
import org.jvnet.glassfish.comms.deployment.backend.SipApplication;
import org.jvnet.glassfish.comms.deployment.backend.SipBundleDescriptor;

public class SipTransactionPersistentManager
        extends PersistentSipSessionManagerBase
        implements ReplicationManager, DynamicOwnershipManager, PurgeCapable {

    private static final Logger _logger = LogUtil.SSR_LOGGER.getLogger();

    protected static final String MODE_SIP = ReplicationState.MODE_SIP;
    protected static java.util.concurrent.atomic.AtomicLong unique =
        new AtomicLong(0);
    final static String DUPLICATE_IDS_SEMANTICS_PROPERTY
        = ReplicationState.DUPLICATE_IDS_SEMANTICS_PROPERTY;
    final static String COMMAND_MAP = "commandmap";
    final static String SUPPRESS_LOAD_ACK_PROPERTY
        = ReplicationState.SUPPRESS_LOAD_ACK_PROPERTY;
    final static String REPLICATION_COMPRESSION_PROPERTY
        = ReplicationState.REPLICATION_COMPRESSION_PROPERTY;   
    final static String SESSION_MANAGER_PROPERTY =
            ReplicationState.SESSION_MANAGER_PROPERTY; // used during jxtabackingstore creation to store a reference to this session manager in jxtabackingstore.
    final static String SIP_TYPE_SAS = "sip_type_sas";
    final static String SIP_TYPE_SS = "sip_type_ss";
    final static String SIP_TYPE_ST = "sip_type_st";
    private static final Level TRACE_LEVEL = Level.FINE;
    protected static int _maxBaseCacheSize = 4096;
    protected static float _loadFactor = 0.75f;
    protected static final int _concurrencyLevel = 100;
    private static final long SLEEP_TIME = 30L * 1000L; //30 seconds
    public final static String BEKEY
        = ReplicationState.BEKEY;
    private static boolean useReplicationUnicastLoadResponseBatching = false;
   
    private static final Map sipApplicationSessionCommandMap = new HashMap();
    private static final Map sipSessionCommandMap = new HashMap();
    private static final Map servletTimerCommandMap = new HashMap();
   
    public final static String SAVE_COMMAND
        = ReplicationState.SAVE_COMMAND;
    public final static String VALVE_SAVE_COMMAND
        = ReplicationState.VALVE_SAVE_COMMAND;   
    public final static String REMOVE_COMMAND
        = ReplicationState.REMOVE_COMMAND;   
    public final static String UNDEPLOY_COMMAND
        = ReplicationState.UNDEPLOY_COMMAND;
    public final static String REMOVE_EXPIRED_COMMAND
        = ReplicationState.REMOVE_EXPIRED_COMMAND;
    public final static String UPDATE_LAST_ACCESS_TIME_COMMAND
        = ReplicationState.UPDATE_LAST_ACCESS_TIME_COMMAND;
    public final static String MESSAGE_BROADCAST_QUERY
        = ReplicationState.MESSAGE_BROADCAST_QUERY;
    public final static String MESSAGE_BROADCAST_LOAD_RECEIVED
        = ReplicationState.MESSAGE_BROADCAST_LOAD_RECEIVED;
    public final static String MESSAGE_BROADCAST_LOAD_ADVISORY
        = ReplicationState.MESSAGE_BROADCAST_LOAD_ADVISORY;
    public final static String MESSAGE_BROADCAST_PURGE_ADVISORY
        = ReplicationState.MESSAGE_BROADCAST_PURGE_ADVISORY;
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_ADVISORY
        = "rollingupgradeadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_REPLICA_RECONCILIATION_COMPLETE_ADVISORY
        = "rollingupgradereplicareconciliationcompleteadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RESTORATION_ADVISORY
        = "rollingupgradesipapplicationsessionactivecacherestorationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RESTORATION_RESPONSE
        = "rollingupgradesipapplicationsessionactivecacherestorationresponse";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_ACTIVE_CACHE_RESTORATION_ADVISORY
        = "rollingupgradesipsessionactivecacherestorationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_ACTIVE_CACHE_RESTORATION_RESPONSE
        = "rollingupgradesipsessionactivecacherestorationresponse";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_ACTIVE_CACHE_RESTORATION_ADVISORY
        = "rollingupgradeservlettimeractivecacherestorationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_ACTIVE_CACHE_RESTORATION_RESPONSE
        = "rollingupgradeservlettimeractivecacherestorationresponse";

    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_REPLICA_CACHE_RESTORATION_ADVISORY
        = "rollingupgradesipapplicationsessionreplicacacherestorationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_REPLICA_CACHE_RESTORATION_RESPONSE
        = "rollingupgradesipapplicationsessionreplicacacherestorationresponse";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_REPLICA_CACHE_RESTORATION_ADVISORY
        = "rollingupgradesipsessionreplicacacherestorationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_REPLICA_CACHE_RESTORATION_RESPONSE
        = "rollingupgradesipsessionreplicacacherestorationresponse";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_REPLICA_CACHE_RESTORATION_ADVISORY
        = "rollingupgradeservlettimerreplicacacherestorationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_REPLICA_CACHE_RESTORATION_RESPONSE
        = "rollingupgradeservlettimerreplicacacherestorationresponse";

    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RECONCILIATION_ADVISORY
        = "rollingupgradegetidsforsipapplicationsessionactivecachereconciliationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RECONCILIATION_RESPONSE
        = "rollingupgradegetidsforsipapplicationsessionactivecachereconciliationresponse";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_ACTIVE_CACHE_RECONCILIATION_ADVISORY
        = "rollingupgradegetidsforsipsessionactivecachereconciliationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_ACTIVE_CACHE_RECONCILIATION_RESPONSE
        = "rollingupgradegetidsforsipsessionactivecachereconciliationresponse";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_ACTIVE_CACHE_RECONCILIATION_ADVISORY
        = "rollingupgradegetidsforservlettimeractivecachereconciliationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_ACTIVE_CACHE_RECONCILIATION_RESPONSE
        = "rollingupgradegetidsforservlettimeractivecachereconciliationresponse";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_REPLICA_CACHE_RECONCILIATION_ADVISORY
        = "rollingupgradegetidsforsipapplicationsessionreplicacachereconciliationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_REPLICA_CACHE_RECONCILIATION_RESPONSE
        = "rollingupgradegetidsforsipapplicationsessionreplicacachereconciliationresponse";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_REPLICA_CACHE_RECONCILIATION_ADVISORY
        = "rollingupgradegetidsforsipsessionreplicacachereconciliationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_REPLICA_CACHE_RECONCILIATION_RESPONSE
        = "rollingupgradegetidsforsipsessionreplicacachereconciliationresponse";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_REPLICA_CACHE_RECONCILIATION_ADVISORY
        = "rollingupgradegetidsforservlettimerreplicacachereconciliationadvisory";
    public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_REPLICA_CACHE_RECONCILIATION_RESPONSE
        = "rollingupgradegetidsforservlettimerreplicacachereconciliationresponse";   
   
    public final static String SAVE_SAS_COMMAND = "savesas";
    public final static String REMOVE_SAS_COMMAND = "removesas";
    public final static String LOAD_SAS_COMMAND = "loadsas";
    public final static String UPDATE_LAST_ACCESS_TIME_SAS_COMMAND
        = "updatelastaccesstimesas";
    public final static String MESSAGE_BROADCAST_QUERY_SAS
        = "broadcastfindsas";
    public final static String MESSAGE_BROADCAST_LOAD_RECEIVED_SAS
        = "broadcastloadreceivedsas";
    public final static String MESSAGE_LOAD_ADVISORY_SAS
        = "loadadvisorysas";
    public final static String MESSAGE_BROADCAST_EXPAT_QUERY_SAS
        = "broadcastfindsasexpatids";
    public final static String MESSAGE_BROADCAST_EXPAT_QUERY_SAS_REPLICA
        = "broadcastfindsasreplicaexpatids";
    public final static String MESSAGE_BROADCAST_EXPAT_RECEIVE_SAS
        = "broadcastreceivesasexpatids";
    public final static String MESSAGE_BROADCAST_EXPAT_RECEIVE_SAS_REPLICA
        = "broadcastreceivesasreplicaexpatids";
   
    public final static String SAVE_SIP_SESSION_COMMAND = "savesipsession";
    public final static String REMOVE_SIP_SESSION_COMMAND = "removesipsession";
    public final static String LOAD_SIP_SESSION_COMMAND = "loadsipsession";
    public final static String UPDATE_LAST_ACCESS_TIME_SIP_SESSION_COMMAND
        = "updatelastaccesstimesipsession";
    public final static String MESSAGE_BROADCAST_QUERY_SIP_SESSION
        = "broadcastfindsipsession";
    public final static String MESSAGE_BROADCAST_LOAD_RECEIVED_SIP_SESSION
        = "broadcastloadreceivedsipsession";
    public final static String MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION
        = "broadcastfindsipsessionexpatids";
    public final static String MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION_REPLICA
        = "broadcastfindsipsessionreplicaexpatids";
    public final static String MESSAGE_BROADCAST_EXPAT_RECEIVE_SIP_SESSION
        = "broadcastreceivesipsessionexpatids";   
    public final static String MESSAGE_BROADCAST_EXPAT_RECEIVE_SIP_SESSION_REPLICA
        = "broadcastreceivesipsessionreplicaexpatids";   
   
    public final static String SAVE_SERVLET_TIMER_COMMAND
        = "saveservlettimer";
    public final static String REMOVE_SERVLET_TIMER_COMMAND
        = "removeservlettimer";
    public final static String LOAD_SERVLET_TIMER_COMMAND
        = "loadservlettimer";
    public final static String UPDATE_LAST_ACCESS_TIME_SERVLET_TIMER_COMMAND
        = "updatelastaccesstimeservlettimer";
    public final static String MESSAGE_BROADCAST_QUERY_SERVLET_TIMER
        = "broadcastfindservlettimer";
    public final static String MESSAGE_BROADCAST_LOAD_RECEIVED_SERVLET_TIMER
        = "broadcastloadreceivedservlettimer";
    public final static String MESSAGE_LOAD_ADVISORY_SERVLET_TIMER
        = "loadadvisoryservlettimer";
    public final static String MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER
        = "broadcastfindservlettimerexpatids";
    public final static String MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER_REPLICA
        = "broadcastfindservlettimerreplicaexpatids";
    public final static String MESSAGE_BROADCAST_EXPAT_RECEIVE_SERVLET_TIMER
        = "broadcastreceiveservlettimerexpatids";
    public final static String MESSAGE_BROADCAST_EXPAT_RECEIVE_SERVLET_TIMER_REPLICA
        = "broadcastreceiveservlettimerreplicaexpatids";

    private ReplicationUtil replicationUtil = null;
   
    /**
     * the list of method names that are broadcasts or unicasts
     */
    private static List broadcastMethods
        = Arrays.asList(
            MESSAGE_BROADCAST_QUERY_SAS,
            LOAD_SAS_COMMAND,
            MESSAGE_BROADCAST_LOAD_RECEIVED_SAS,
            MESSAGE_LOAD_ADVISORY_SAS,
            MESSAGE_BROADCAST_EXPAT_QUERY_SAS,
            MESSAGE_BROADCAST_EXPAT_QUERY_SAS_REPLICA,
            MESSAGE_BROADCAST_EXPAT_RECEIVE_SAS,
            MESSAGE_BROADCAST_EXPAT_RECEIVE_SAS_REPLICA,
            MESSAGE_BROADCAST_QUERY_SIP_SESSION,
            LOAD_SIP_SESSION_COMMAND,
            MESSAGE_BROADCAST_LOAD_RECEIVED_SIP_SESSION,
            MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION,
            MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION_REPLICA,
            MESSAGE_BROADCAST_EXPAT_RECEIVE_SIP_SESSION,
            MESSAGE_BROADCAST_EXPAT_RECEIVE_SIP_SESSION_REPLICA,
            MESSAGE_BROADCAST_QUERY_SERVLET_TIMER,
            LOAD_SERVLET_TIMER_COMMAND,
            MESSAGE_BROADCAST_LOAD_RECEIVED_SERVLET_TIMER,
            MESSAGE_LOAD_ADVISORY_SERVLET_TIMER,
            MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER,
            MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER_REPLICA,
            MESSAGE_BROADCAST_EXPAT_RECEIVE_SERVLET_TIMER,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RESTORATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RESTORATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_ACTIVE_CACHE_RESTORATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_ACTIVE_CACHE_RESTORATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_ACTIVE_CACHE_RESTORATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_ACTIVE_CACHE_RESTORATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_REPLICA_CACHE_RESTORATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_REPLICA_CACHE_RESTORATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_REPLICA_CACHE_RESTORATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_REPLICA_CACHE_RESTORATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_REPLICA_CACHE_RESTORATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_REPLICA_CACHE_RESTORATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RECONCILIATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RECONCILIATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_ACTIVE_CACHE_RECONCILIATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_ACTIVE_CACHE_RECONCILIATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_ACTIVE_CACHE_RECONCILIATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_ACTIVE_CACHE_RECONCILIATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_REPLICA_CACHE_RECONCILIATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_REPLICA_CACHE_RECONCILIATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_REPLICA_CACHE_RECONCILIATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_REPLICA_CACHE_RECONCILIATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_REPLICA_CACHE_RECONCILIATION_ADVISORY,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_REPLICA_CACHE_RECONCILIATION_RESPONSE,
            MESSAGE_BROADCAST_ROLLING_UPGRADE_REPLICA_RECONCILIATION_COMPLETE_ADVISORY);

    /**
     * the list of method names that are expensive
     * i.e. should not run on single receiving thread
     * e.g. load advisories when received trigger loads
     * which should not occur on the same receiving thread
     */
    private static List expensiveMethods
        = Arrays.asList(
            MESSAGE_LOAD_ADVISORY_SAS,
            MESSAGE_BROADCAST_EXPAT_QUERY_SAS,
            MESSAGE_BROADCAST_EXPAT_QUERY_SAS_REPLICA,
            MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION,
            MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION_REPLICA,
            MESSAGE_LOAD_ADVISORY_SERVLET_TIMER,
            MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER,
            MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER_REPLICA,
            MESSAGE_BROADCAST_EXPAT_RECEIVE_SAS,
            MESSAGE_BROADCAST_EXPAT_RECEIVE_SAS_REPLICA,
            MESSAGE_BROADCAST_EXPAT_RECEIVE_SIP_SESSION,
            MESSAGE_BROADCAST_EXPAT_RECEIVE_SIP_SESSION_REPLICA,
            MESSAGE_BROADCAST_EXPAT_RECEIVE_SERVLET_TIMER
            );

    /**
     * the list of method names that are expensive
     * i.e. should not run on single receiving thread
     * e.g. load advisories when received trigger loads
     * which should not occur on the same receiving thread
     */
    private static List removeMethods
        = Arrays.asList(
            REMOVE_SAS_COMMAND,
            REMOVE_SIP_SESSION_COMMAND,
            REMOVE_SERVLET_TIMER_COMMAND);

    private static List saveMethods
        = Arrays.asList(
      SAVE_SAS_COMMAND,
      SAVE_SIP_SESSION_COMMAND,
      SAVE_SERVLET_TIMER_COMMAND);
   
    static {
        checkSessionCacheProperties();
        initializeCommandMaps();
        registerBroadcastMethods();
        registerExpensiveMethods();
        registerRemoveMethods();
  registerSaveMethods();
        ServerConfigLookup lookup = new ServerConfigLookup();
        useReplicationUnicastLoadResponseBatching
            = lookup.isReplicationUnicastLoadResponseBatchingEnabled();       
    }

    private SessionFactory sessionFactory;
    private StorePool sipApplicationSessionStorePool;
    private StorePool sipSessionStorePool;
    private StorePool servletTimerStorePool;
    private final String instanceName;
    private ReplicationMessageRouter router;
    protected AtomicBoolean _activeCacheReconciliationOngoing
        = new AtomicBoolean(false);
    protected ConcurrentHashMap stillOwnedSipApplicationSessionIdsForActiveCacheReconciliation = null;
    protected ConcurrentHashMap stillOwnedSipSessionIdsForActiveCacheReconciliation = null;
    protected ConcurrentHashMap stillOwnedServletTimerIdsForActiveCacheReconciliation = null;
   
    private ReentrantReadWriteLock sasExpatReadWriteLock
        = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock sipSessionExpatReadWriteLock
        = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock servletTimerExpatReadWriteLock
        = new ReentrantReadWriteLock();

    protected String _rollingUpgradeBackupDirectory = null;
    protected boolean _skipRollingUpgradeBackupRestore = false;

    protected ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForSipApplicationSessionActiveCacheRestoration = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForSipSessionActiveCacheRestoration = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForServletTimerActiveCacheRestoration = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForSipApplicationSessionReplicaCacheRestoration = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForSipSessionReplicaCacheRestoration = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForServletTimerReplicaCacheRestoration = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedIdsForSipApplicationSessionActiveCacheReconciliation = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedIdsForSipSessionActiveCacheReconciliation = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedIdsForServletTimerActiveCacheReconciliation = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedIdsForSipApplicationSessionReplicaCacheReconciliation = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedIdsForSipSessionReplicaCacheReconciliation = null;
    protected ConcurrentHashMap<String, ReplicationState> ownedIdsForServletTimerReplicaCacheReconciliation = null;
   
    /**
     * get the rollingUpgradeBackupDirectory
     */
    public String getRollingUpgradeBackupDirectory() {
        return _rollingUpgradeBackupDirectory;
    }

    /**
     * set the rollingUpgradeBackupDirectory
     * @param value
     */
    public void setRollingUpgradeBackupDirectory(String value) {
        _rollingUpgradeBackupDirectory = value;
    }

    /** should skip backup and restore step for rolling upgrade */
    boolean isSkipRollingUpgradeBackupRestore() {
        return _skipRollingUpgradeBackupRestore;
    }

    /**
     * set the skipRollingUpgradeBackupRestore
     * @param value
     */
    public void setSkipRollingUpgradeBackupRestore(boolean value) {
        _skipRollingUpgradeBackupRestore = value;
    }

    /**
    * Our ReplicaCache - the receiving side for SipApplicationSession replicas
    */
    protected ReplicaCache sipApplicationSessionReplicaCache = null;

    /**
    * Our ReplicaCache - the receiving side for SipSession replicas
    */
    protected ReplicaCache sipSessionReplicaCache = null;

    /**
    * Our ReplicaCache - the receiving side for ServletTimer replicas
    */
    protected ReplicaCache servletTimerReplicaCache = null;   
   
    /**
    * Our cache of monitor objects
    * keyed by id
    */
    protected ReplicationSessionMonitors replicatedSessionMonitors = null;
   
    /**
    * Our Replicator instance for SipApplicationSessions (for SimpleMetadata)
    */
    protected BackingStore sipApplicationSessionBackingStore = null;
   
    /**
    * Our Replicator instance SipSessions (for SimpleMetadata)
    */
    protected BackingStore sipSessionBackingStore = null;
   
    /**
    * Our Replicator instance for ServletTimers (for SimpleMetadata)
    */
    protected BackingStore servletTimerBackingStore = null;    
   
    protected String _passedInPersistenceType = null;
    protected boolean _duplicateIdsSemanticsAllowed = false;    

    private ActivationHelper activationHelper;
   
    private volatile HashMap<String, ExpatListElement> sasExpatIdsMap =
        new HashMap<String, ExpatListElement>();
    private volatile HashMap<String, ExpatListElement> sipSessionExpatIdsMap =
        new HashMap<String, ExpatListElement>();
    private volatile HashMap<String, ExpatListElement> servletTimerExpatIdsMap =
        new HashMap<String, ExpatListElement>();
    private boolean hasCheckedIfReady = false;
    ExpatListHandler sasExpatListHandler;
    ExpatListHandler sipSessionExpatListHandler;
    ExpatListHandler servletTimerExpatListHandler;
    ExpatListHandler sasReplicaExpatHandler;
    ExpatListHandler ssReplicaExpatHandler;
    ExpatListHandler stReplicaExpatHandler;

    private HashMap<String,String> lastSasExpatQueryId
        = new HashMap<String,String>();
    private HashMap<String,String> lastSipSessionExpatQueryId
        = new HashMap<String,String>();
    private HashMap<String,String> lastServletTimerExpatQueryId
        = new HashMap<String,String>();

    private volatile CountDownLatch reconcileReplicaCacheDoneSignal = null;

    private volatile CountDownLatch restoreSipApplicationSessionActiveCacheDoneSignal = null;
    private volatile CountDownLatch restoreSipSessionActiveCacheDoneSignal = null;
    private volatile CountDownLatch restoreServletTimerActiveCacheDoneSignal = null;
    private volatile CountDownLatch restoreSipApplicationSessionReplicaCacheDoneSignal = null;
    private volatile CountDownLatch restoreSipSessionReplicaCacheDoneSignal = null;
    private volatile CountDownLatch restoreServletTimerReplicaCacheDoneSignal = null;
    private volatile CountDownLatch getIdsForSipApplicationSessionActiveCacheReconciliationDoneSignal = null;
    private volatile CountDownLatch getIdsForSipSessionActiveCacheReconciliationDoneSignal = null;
    private volatile CountDownLatch getIdsForServletTimerActiveCacheReconciliationDoneSignal = null;
    private volatile CountDownLatch getIdsForSipApplicationSessionReplicaCacheReconciliationDoneSignal = null;
    private volatile CountDownLatch getIdsForSipSessionReplicaCacheReconciliationDoneSignal = null;
    private volatile CountDownLatch getIdsForServletTimerReplicaCacheReconciliationDoneSignal = null;

    /**
     * There are 3 request/responses for each artifact :
     *
     * (a) active reconciliation
     * (b) replica reconciliation
     * (c) post active reconciliation.
     *
     * These are separated instead of one because, only (a) is applicable for
     * third party backing stores. Whereas, in-memory needs all 3 steps.
     */
    public static final String RECONCILE_SAS_REQUEST =
            "reconcilesasrequest";
    public static final String RECONCILE_SAS_RESPONSE =
            "reconcilesasresponse";
    public static final String RECONCILE_SAS_REPLICA_REQUEST =
            "reconcilesasreplicarequest";
    public static final String RECONCILE_SAS_REPLICA_RESPONSE =
            "reconcilesasreplicaresponse";
    public static final String POST_RECONCILE_SAS_REQUEST =
            "postreconcilesasrequest";
    public static final String POST_RECONCILE_SAS_RESPONSE =
            "postreconcilesasresponse";

    public static final String RECONCILE_SIPSESSION_REQUEST =
            "reconcilesipsessionrequest";
    public static final String RECONCILE_SIPSESSION_RESPONSE =
            "reconcilesipsessionresponse";
    public static final String RECONCILE_SIPSESSION_REPLICA_REQUEST =
            "reconcilesipsessionreplicarequest";
    public static final String RECONCILE_SIPSESSION_REPLICA_RESPONSE =
            "reconcilesipsessionreplicaresponse";
    public static final String POST_RECONCILE_SIPSESSION_REQUEST =
            "postreconcilesipsessionrequest";
    public static final String POST_RECONCILE_SIPSESSION_RESPONSE =
            "postreconcilesipsessionresponse";

    public static final String RECONCILE_SERVLETTIMER_REQUEST =
            "reconcileservlettimerrequest";
    public static final String RECONCILE_SERVLETTIMER_RESPONSE =
            "reconcileservlettimerresponse";
    public static final String RECONCILE_SERVLETTIMER_REPLICA_REQUEST =
            "reconcileservlettimerreplicarequest";
    public static final String RECONCILE_SERVLETTIMER_REPLICA_RESPONSE =
            "reconcileservlettimerreplicaresponse";
    public static final String POST_RECONCILE_SERVLETTIMER_REQUEST =
            "postreconcileservlettimerrequest";
    public static final String POST_RECONCILE_SERVLETTIMER_RESPONSE =
            "postreconcileservlettimerresponse";

    /**
     * similary there are 3 countdownlatches for each artifact, and 2 responses
     * for each artifact. (c) does not have a response, but only signals the
     * completion of the (c) in all other instances.
     */
    private volatile AtomicReference<CountDownLatch> activeSasReconcileSignal =
            new AtomicReference<CountDownLatch>();
    private volatile AtomicReference<CountDownLatch> replicaSasReconcileSignal =
            new AtomicReference<CountDownLatch>();
    private volatile AtomicReference<CountDownLatch> postSasReconcileSignal =
            new AtomicReference<CountDownLatch>();
    private volatile Map<String, ReplicationState> reconciledActiveSases =
            new HashMap<String, ReplicationState>();
    private volatile Map<String, ReplicationState> reconciledReplicaSases =
            new HashMap<String, ReplicationState>();
    private volatile Map<String, ReplicationState> remotelyLockedSases =
            new HashMap<String, ReplicationState>();

    private volatile AtomicReference<CountDownLatch> activeSipSessionReconcileSignal =
            new AtomicReference<CountDownLatch>();
    private volatile AtomicReference<CountDownLatch> replicaSipSessionReconcileSignal =
            new AtomicReference<CountDownLatch>();
    private volatile AtomicReference<CountDownLatch> postSipSessionReconcileSignal =
            new AtomicReference<CountDownLatch>();
    private volatile Map<String, ReplicationState> reconciledActiveSipSessions =
            new HashMap<String, ReplicationState>();
    private volatile Map<String, ReplicationState> reconciledReplicaSipSessions =
            new HashMap<String, ReplicationState>();
    private volatile Map<String, ReplicationState> remotelyLockedSipSessions =
            new HashMap<String, ReplicationState>();


    private volatile AtomicReference<CountDownLatch> activeServletTimerReconcileSignal =
            new AtomicReference<CountDownLatch>();
    private volatile AtomicReference<CountDownLatch> replicaServletTimerReconcileSignal =
            new AtomicReference<CountDownLatch>();
    private volatile AtomicReference<CountDownLatch> postServletTimerReconcileSignal =
            new AtomicReference<CountDownLatch>();
    private volatile Map<String, ReplicationState> reconciledActiveServletTimers =
            new HashMap<String, ReplicationState>();
    private volatile Map<String, ReplicationState> reconciledReplicaServletTimers =
            new HashMap<String, ReplicationState>();
    private volatile Map<String, ReplicationState> remotelyLockedServletTimers =
            new HashMap<String, ReplicationState>();

    private boolean appContainsHttpServlets;

    /** Creates a new instance of ReplicationManagerBase */
    public SipTransactionPersistentManager() {
        super();
        replicatedSessionMonitors = new ReplicationSessionMonitors(_logger, _maxBaseCacheSize, _loadFactor);
        instanceName = ReplicationUtil.getInstanceName();

        activationHelper = new ActivationHelper(this);
        if (Globals.IS_SECURITY_ENABLED) {
            router = (ReplicationMessageRouter)
                AccessController.doPrivileged(
                    new PrivilegedGetReplicationMessageRouter());
        } else {
            router = ReplicationMessageRouter.createInstance();
        }
        ServerConfigLookup lookup = new ServerConfigLookup();
        replicationCompressionEnabled = lookup.isReplicationCompression();
        replicationUtil = ReplicationUtil.createReplicationUtil();
   

    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());
            }
        } catch (Exception e) {
            //do nothing accept defaults
        }

        return result;
    }
   
    protected static void initializeCommandMaps() {
        sipApplicationSessionCommandMap.put(SAVE_COMMAND, SAVE_SAS_COMMAND);
        sipSessionCommandMap.put(SAVE_COMMAND, SAVE_SIP_SESSION_COMMAND);
        servletTimerCommandMap.put(SAVE_COMMAND, SAVE_SERVLET_TIMER_COMMAND);

        sipApplicationSessionCommandMap.put(VALVE_SAVE_COMMAND, SAVE_SAS_COMMAND);
        sipSessionCommandMap.put(VALVE_SAVE_COMMAND, SAVE_SIP_SESSION_COMMAND);
        servletTimerCommandMap.put(VALVE_SAVE_COMMAND, SAVE_SERVLET_TIMER_COMMAND);       
       
        sipApplicationSessionCommandMap.put(REMOVE_COMMAND, REMOVE_SAS_COMMAND);
        sipSessionCommandMap.put(REMOVE_COMMAND, REMOVE_SIP_SESSION_COMMAND);
        servletTimerCommandMap.put(REMOVE_COMMAND, REMOVE_SERVLET_TIMER_COMMAND)
       
        sipApplicationSessionCommandMap.put(UPDATE_LAST_ACCESS_TIME_COMMAND, UPDATE_LAST_ACCESS_TIME_SAS_COMMAND);
        sipSessionCommandMap.put(UPDATE_LAST_ACCESS_TIME_COMMAND, UPDATE_LAST_ACCESS_TIME_SIP_SESSION_COMMAND);
        servletTimerCommandMap.put(UPDATE_LAST_ACCESS_TIME_COMMAND, UPDATE_LAST_ACCESS_TIME_SERVLET_TIMER_COMMAND);
       
        sipApplicationSessionCommandMap.put(MESSAGE_BROADCAST_QUERY, MESSAGE_BROADCAST_QUERY_SAS);
        sipSessionCommandMap.put(MESSAGE_BROADCAST_QUERY, MESSAGE_BROADCAST_QUERY_SIP_SESSION);
        servletTimerCommandMap.put(MESSAGE_BROADCAST_QUERY, MESSAGE_BROADCAST_QUERY_SERVLET_TIMER);
       
        sipApplicationSessionCommandMap.put(MESSAGE_BROADCAST_LOAD_RECEIVED, MESSAGE_BROADCAST_LOAD_RECEIVED_SAS);
        sipSessionCommandMap.put(MESSAGE_BROADCAST_LOAD_RECEIVED, MESSAGE_BROADCAST_LOAD_RECEIVED_SIP_SESSION);
        servletTimerCommandMap.put(MESSAGE_BROADCAST_LOAD_RECEIVED, MESSAGE_BROADCAST_LOAD_RECEIVED_SERVLET_TIMER);       
    }

    private static ReplicationMessageRouter getRouter() {
        ReplicationMessageRouter receiver = null;
        if (Globals.IS_SECURITY_ENABLED) {
            receiver = (ReplicationMessageRouter)
                AccessController.doPrivileged(
                    new PrivilegedGetReplicationMessageRouter());
        } else {
            receiver = ReplicationMessageRouter.createInstance();
        }
        return receiver;
    }
   
    protected static void registerBroadcastMethods() {
        ReplicationMessageRouter router = getRouter();
        router.registerBroadcastMethodList(broadcastMethods);
    }

    protected static void registerExpensiveMethods() {
        ReplicationMessageRouter router = getRouter();
        router.registerExpensiveMethodList(expensiveMethods);
    }

    protected static void registerRemoveMethods() {
        ReplicationMessageRouter router = getRouter();
        router.registerRemoveMethodList(removeMethods);
    }

    protected static void registerSaveMethods() {
        ReplicationMessageRouter router = getRouter();
        router.registerSaveMethodList(saveMethods);
    }
   
    /**
     * Checks if this manager is ready to perform its tasks.
     */
    public void checkIfReady() {
        if (!hasCheckedIfReady) {
            checkIsInstanceStarted();
            checkAppDeployment(this.getApplicationId());
            hasCheckedIfReady = true;
        }
    }
   
    public void checkIsInstanceStarted() {
        long startTime = System.currentTimeMillis();
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        long sleepTime = 100L;
        boolean shouldContinue = true;
        while(shouldContinue) {
            if((System.currentTimeMillis() - startTime) > 60000) {
                _logger.warning("checkIsInstanceStarted: Timed out");
                shouldContinue = false;
                break;
            }
            boolean startStatus = healthChecker.isInstanceStarted();
            if(_logger.isLoggable(Level.FINE)) {
                _logger.fine("instance started: " + startStatus);
            }
            if(startStatus) {
                shouldContinue = false;
            } else {
                try {
                    Thread.currentThread().sleep(sleepTime);
                } catch (InterruptedException ex) {
                    ;
                }
            }
            sleepTime *= 2;
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("checkIsInstanceStarted for took " + (System.currentTimeMillis() - startTime) + "ms");
        }
    }
   
    public void checkAppDeployment(String applicationId) {
        long startTime = System.currentTimeMillis();
        ApplicationStatusChecker appStatusChecker
            = new ApplicationStatusChecker();
        long sleepTime = 100L;
        boolean shouldContinue = true;
        while(shouldContinue) {
            if((System.currentTimeMillis() - startTime) > 60000) {
                _logger.warning("checkAppDeployment: Timed out waiting for replicas application" + applicationId + " to finished deploying");
                shouldContinue = false;
                break;
            }
            boolean appStatus = appStatusChecker.isApplicationDeployed(applicationId, "WEB");
            if(_logger.isLoggable(Level.FINE)) {
                _logger.fine("app:" + applicationId + " isDeployed: " + appStatus);
            }
            if(appStatus) {
                shouldContinue = false;
            } else {
                try {
                    Thread.currentThread().sleep(sleepTime);
                } catch (InterruptedException ex) {
                    ;
                }
            }
            sleepTime *= 2;
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("checkAppDeployment for application " + applicationId + "took " + (System.currentTimeMillis() - startTime) + "ms");
        }
    }
   
    boolean replicationCompressionEnabled = false;
   
    boolean isReplicationCompressionEnabled() {
        return replicationCompressionEnabled;
    }   

    private void getBackingStores() {
        // create backing stores so that the replica expat handlers get created
        // well in advance. Otherwise the expat pushed by remote instances
        // might get missed out. That can happen in the restarted instance.
        try {
            getSipApplicationSessionBackingStore();
            getSipSessionBackingStore();
            getServletTimerBackingStore();
            ((ReplicationDialogFragmentManager) com.ericsson.ssa.sip.DialogFragmentManager.getInstance()).
                    getDialogFragmentBackingStore();

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Starts this SipTransactionPersistentManager.
     */   
    public void start() throws LifecycleException {
        super.start();
        sasExpatListHandler = ExpatListHandler.getExpatListHandler(this, getApplicationId(),
                MESSAGE_BROADCAST_EXPAT_QUERY_SAS, MODE_SIP, "SASActive");
        sipSessionExpatListHandler = ExpatListHandler.getExpatListHandler(this, getApplicationId(),
                MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION, MODE_SIP, "SipSessionActive");
        servletTimerExpatListHandler = ExpatListHandler.getExpatListHandler(this, getApplicationId(),
                MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER, MODE_SIP, "ServletTimerActive");
        router.addReplicationManager(this.getApplicationId(), this);
        getBackingStores();
        checkIfReady();
        //FIXME: this is for testing
        //will eventually be triggered by separate admin command
        //if(ReplicationUtil.isRollingUpgradeEnabled()) {
            //CountDownLatch doneSignal = new CountDownLatch(1);
            //doRollingUpgradePostStartupProcessing(System.currentTimeMillis(), doneSignal);
        //}
        appContainsHttpServlets = convergedContext.containsHttpServlets();
    }  

    /**
     * Stops this SipTransactionPersistentManager.
     */
    public void stop() throws LifecycleException {
        activationHelper.cancelAllMigrationTasks();
        router.removeReplicationManager(this.getApplicationId());
        super.stop();
    }  

    /**
     * Releases any resources held by this SipSessionManager.during
     * undeployment.
     */
    public void release() {

        super.release();

        if (stillOwnedSipApplicationSessionIdsForActiveCacheReconciliation != null) {
            stillOwnedSipApplicationSessionIdsForActiveCacheReconciliation.clear();
            stillOwnedSipApplicationSessionIdsForActiveCacheReconciliation = null;
        }
        if (stillOwnedSipSessionIdsForActiveCacheReconciliation != null) {
            stillOwnedSipSessionIdsForActiveCacheReconciliation.clear();
            stillOwnedSipSessionIdsForActiveCacheReconciliation = null;
        }
        if (stillOwnedServletTimerIdsForActiveCacheReconciliation != null) {
            stillOwnedServletTimerIdsForActiveCacheReconciliation.clear();
            stillOwnedServletTimerIdsForActiveCacheReconciliation = null;
        }
        if (sipApplicationSessionReplicaCache != null) {
            sipApplicationSessionReplicaCache.release();
        }
        if (sipSessionReplicaCache != null) {
            sipSessionReplicaCache.release();
        }
        if (servletTimerReplicaCache != null) {
            servletTimerReplicaCache.release();
        }
        if (sipApplicationSessionStorePool != null) {
            sipApplicationSessionStorePool.clear();
            sipApplicationSessionStorePool = null;
        }
        if (sipSessionStorePool != null) {
            sipSessionStorePool.clear();
            sipSessionStorePool = null;
        }
        if (servletTimerStorePool != null) {
            servletTimerStorePool.clear();
            servletTimerStorePool = null;
        }

        destroyBackingStores();
    }

    private void destroyBackingStores() {
        try {
            if(sipApplicationSessionBackingStore != null) {
                sipApplicationSessionBackingStore.destroy();
            }
            if(sipSessionBackingStore != null) {
                sipSessionBackingStore.destroy();
            }
            if(servletTimerBackingStore != null) {
                servletTimerBackingStore.destroy();
            }
        } catch(Exception ex) {

        }
    }

    /**
     * get the backingStore for SipApplicationSession
     */
    public BackingStore getSipApplicationSessionBackingStore() {
        if(sipApplicationSessionBackingStore == null) {
            sipApplicationSessionBackingStore = this.createBackingStore(sipApplicationSessionCommandMap, SIP_TYPE_SAS);
        }
        return sipApplicationSessionBackingStore;
    }
   
    /**
     * get the backingStore for SipSession
     */
    public BackingStore getSipSessionBackingStore() {
        if(sipSessionBackingStore == null) {
            sipSessionBackingStore = this.createBackingStore(sipSessionCommandMap, SIP_TYPE_SS);          
        }
        return sipSessionBackingStore;
    }
   
    /**
     * get the backingStore for ServletTimer
     */
    public BackingStore getServletTimerBackingStore() {
        if(servletTimerBackingStore == null) {
            servletTimerBackingStore = this.createBackingStore(servletTimerCommandMap, SIP_TYPE_ST);           
        }
        return servletTimerBackingStore;
    }
   
    /**
     * create and set the backing store
     * @param commandMap map used to translate commands
     */    
    BackingStore createBackingStore(Map commandMap, String sipType) {
        BackingStoreFactory storeFactory = new JxtaBackingStoreFactory();
        BackingStoreRegistry backingStoreRegistry
            = BackingStoreRegistry.getInstance();
        Properties inputEnv
            = backingStoreRegistry.getFactoryClassEnv(getPassedInPersistenceType());
        Properties env = (Properties)inputEnv.clone();       
        //does this manager & backing store support duplicate id semantics
        //for batch replication usage
        env.put(DUPLICATE_IDS_SEMANTICS_PROPERTY, Boolean.valueOf(this.isDuplicateIdsSemanticsAllowed()));
        env.put(COMMAND_MAP, commandMap);
        if(sipType != null && (sipType.equals(SIP_TYPE_SAS) || sipType.equals(SIP_TYPE_SS) || sipType.equals(SIP_TYPE_ST))) {
            env.put(SUPPRESS_LOAD_ACK_PROPERTY, Boolean.TRUE);
        }
        //does this manager & backing store support replication compression
        env.put(REPLICATION_COMPRESSION_PROPERTY, Boolean.valueOf(this.isReplicationCompressionEnabled()));
        env.put(SESSION_MANAGER_PROPERTY, this);
        BackingStore backingStore = null;
        try {
            backingStore = storeFactory.createBackingStore(
                        this.getApplicationId(), //appid
                        String.class,
                        SimpleMetadata.class,     //type
                        env);
        } catch (BackingStoreException ex) {
            //deliberate no-op
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("backingStore: " + backingStore);
        }        
        if(backingStore != null) {
            if(backingStore instanceof JxtaBackingStoreImpl) {
                ((JxtaBackingStoreImpl)backingStore).setMode(MODE_SIP);
            }       
        }
        return backingStore;
    }       
   
    public void __createStoreExpatHandler(JxtaBackingStoreImpl jxtaBackingStore) {
        // this method is called from JxtaBackingStoreImpl's constructor, so never
        // use this : if(jxtaBackingStore == sipApplicationSessionBackingStore)
        if (SAVE_SAS_COMMAND.equals(jxtaBackingStore.getCommand(SAVE_COMMAND))) {
            if (sasReplicaExpatHandler == null) {
                sasReplicaExpatHandler = ExpatListHandler.getExpatListHandler(
                        this, getApplicationId(),
                        MESSAGE_BROADCAST_EXPAT_QUERY_SAS_REPLICA, MODE_SIP, "SASReplica");
            }

        } else
        if (SAVE_SIP_SESSION_COMMAND.equals(jxtaBackingStore.getCommand(SAVE_COMMAND))) {
            // initialize ssReplicaExpatHandler for the first time.
            if (ssReplicaExpatHandler == null) {
                ssReplicaExpatHandler = ExpatListHandler.getExpatListHandler(
                        this, getApplicationId(),
                        MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION_REPLICA, MODE_SIP,
                        "SipSessionReplica");

            }
        } else
        if (SAVE_SERVLET_TIMER_COMMAND.equals(jxtaBackingStore.getCommand(SAVE_COMMAND))) {
            // initialize stReplicaExpatHandler for the first time.
            stReplicaExpatHandler = ExpatListHandler.getExpatListHandler(
                    this, getApplicationId(),
                    MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER_REPLICA, MODE_SIP,
                    "ServletTimerReplica");
        }
    }
   
    public boolean isDuplicateIdsSemanticsAllowed() {
        return _duplicateIdsSemanticsAllowed;
    }   
   
    public void setDuplicateIdsSemanticsAllowed(boolean value) {
        _duplicateIdsSemanticsAllowed = value;
    }  
   
    public String getPassedInPersistenceType() {
        return _passedInPersistenceType;
    }   
   
    public void setPassedInPersistenceType(String persistenceType) {
        _passedInPersistenceType = persistenceType;
    }

    public void setSipApplicationSessionReplicaCache(ReplicaCache sasReplicaCache) {
        sipApplicationSessionReplicaCache = sasReplicaCache;
    }

    public void setSipSessionReplicaCache(ReplicaCache ssReplicaCache) {
        sipSessionReplicaCache = ssReplicaCache;
    }

    public void setServletTimerReplicaCache(ReplicaCache stReplicaCache) {
        servletTimerReplicaCache = stReplicaCache;
    }
   
    public boolean isActiveCacheReconciliationOngoing() {
        return _activeCacheReconciliationOngoing.get();
    }   
   
    public void setActiveCacheReconciliationOngoing(boolean value) {
        _activeCacheReconciliationOngoing.set(value);
    }   
   
    //SAS cache methods
   
    public Object getReplicationSessionMonitor(String id) {
        return replicatedSessionMonitors.get(id);
    }
   
    /**
     * Purges any expired SIP artifacts from this manager's active caches and
     * persistent stores as a periodic task.
     */
    public void backgroundProcess() {
        super.backgroundProcess();
        replicatedSessionMonitors.processExpired();
        sipApplicationSessionReplicaCache.processExpiredReplicaRemovals();
        sipSessionReplicaCache.processExpiredReplicaRemovals();
        servletTimerReplicaCache.processExpiredReplicaRemovals();
    }   

    /**
     * get the replicated SipApplicationSessions cache
     */
    public BaseCache getReplicatedSipApplicationSessions() {
        return sipApplicationSessionReplicaCache.getReplicatedSessions();
    }
   
    /**
     * Put session State in SipApplicationSession replica cache
     * @param sessionState
     */   
    protected void putInSipApplicationSessionReplicationCache(ReplicationState sessionState) {
        sipApplicationSessionReplicaCache.putInReplicationCache(sessionState);
    }
   
    /**
     * get SipApplicationSession State from replica cache based on the id
     * @param id
     */   
    protected ReplicationState getFromSipApplicationSessionReplicationCache(String id) {
        return sipApplicationSessionReplicaCache.getFromReplicationCache(id);
    }
   
    /**
     * remove session State from replica cache based on the id
     * @param id
     */   
    protected ReplicationState removeFromSipApplicationSessionReplicationCache(String id) {
        return sipApplicationSessionReplicaCache.removeFromReplicationCache(id);
    }
   
    //SS cache methods
   
    /**
    * get the replicated SipSessions cache
    */
    public BaseCache getReplicatedSipSessions() {
        return sipSessionReplicaCache.getReplicatedSessions();
    }
   
    /**
     * Put session State in SipApplicationSession replica cache
     * @param sessionState
     */   
    protected void putInSipSessionReplicationCache(ReplicationState sessionState) {
        sipSessionReplicaCache.putInReplicationCache(sessionState);
    }
   
    /**
     * get SipSession State from replica cache based on the id
     * @param id
     */   
    protected ReplicationState getFromSipSessionReplicationCache(String id) {
        return sipSessionReplicaCache.getFromReplicationCache(id);
    }
   
    /**
     * remove session State from replica cache based on the id
     * @param id
     */   
    protected ReplicationState removeFromSipSessionReplicationCache(String id) {
        return sipSessionReplicaCache.removeFromReplicationCache(id);
    }   
   
//ServletTimer cache methods
   
    /**
    * get the replicated ServletTimers cache
    */
    public BaseCache getReplicatedServletTimers() {
        return servletTimerReplicaCache.getReplicatedSessions();
    }
   
    /**
     * Put session timer State in ServletTimers replica cache
     * @param sessionState
     */   
    protected void putInServletTimerReplicationCache(ReplicationState sessionState) {
        servletTimerReplicaCache.putInReplicationCache(sessionState);
    }
   
    /**
     * get ServletTimer State from replica cache based on the id
     * @param id
     */   
    protected ReplicationState getFromServletTimerReplicationCache(String id) {
        return servletTimerReplicaCache.getFromReplicationCache(id);
    }
   
    /**
     * remove servlet timer State from replica cache based on the id
     * @param id
     */   
    protected ReplicationState removeFromServletTimerReplicationCache(String id) {
        return servletTimerReplicaCache.removeFromReplicationCache(id);
    }
   
    //end cache methods
   
    //start receiver side process methods
   
    //SipApplicationSession process methods

    /**
     * process the save of a SipApplicationSession
     * @param sessionState - contains the save command
     */    
    public void processSavesas(ReplicationState sessionState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() + ">>processSavesas");
        }       
        this.putInSipApplicationSessionReplicationCache(sessionState);
    }
   
    private void doLoadAdvisoryTest(ReplicationState sessionState) {
        //start load advisory test
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        String partnerInstanceName
            = healthChecker.getReshapeReplicateToInstanceName(null, 3000L);
        try {
            sendLoadAdvisorySipApplicationSession((String)sessionState.getId(), partnerInstanceName);
        } catch (Throwable th) {
            _logger.log(Level.INFO, "error during load advisory test to " + partnerInstanceName, th);
        }
        //end load advisory test
    }

    private ReplicationState doUnicastLoadTest(HASipApplicationSession sas) {
        //start unicast load test
        ReplicationState resultState = null;
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        String partnerInstanceName
            = healthChecker.getReshapeReplicateToInstanceName(null, 3000L);
        SipApplicationSessionStoreImpl sasStore = this.getSingletonSipApplicationSessionStore();
        try {
            resultState = sasStore.sendUnicastLoadQuery((String)sas.getId(), "" + sas.getVersion(), partnerInstanceName);
        } catch (Throwable th) {
            _logger.log(Level.INFO, "error during unicast load test to " + partnerInstanceName, th);
        }
        return resultState;
        //end unicast load test
    }

    private ReplicationState doUnicastLoadTest(HASipSession ss) {
        //start unicast load test
        ReplicationState resultState = null;
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        String partnerInstanceName
            = healthChecker.getReshapeReplicateToInstanceName(null, 3000L);
        SipSessionStoreImpl ssStore = this.getSingletonSipSessionStore();
        try {
            resultState = ssStore.sendUnicastLoadQuery((String)ss.getId(), "" + ss.getVersion(), partnerInstanceName);
        } catch (Throwable th) {
            _logger.log(Level.INFO, "error during unicast load test to " + partnerInstanceName, th);
        }
        return resultState;
        //end unicast load test
    }   

    /**
     * process the removal of a SipApplicationSession
     * @param sessionState - contains the remove command
     */    
    public void processRemovesas(ReplicationState sessionState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() + ">>processRemovesas");
        }
        if(sessionState == null) {
            return;
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() + ">>processRemovesas - originating instanceName = " + sessionState.getInstanceName());
        }

        if (sessionState.getState() != null) {
            processBulkRemoveSAS(sessionState);
            return;
        }

        String id = (String)sessionState.getId();
        activationHelper.unregisterSasTimerMigrationTask(id);
        //keep track of recent removals
        sipApplicationSessionReplicaCache.removeFromReplicationCache(id);
        //do the cyclical remove if not fronted by CLB
        if (!SipReplicationUtil.isInstanceLoadBalancedByCLB()) {
            int cycleCount = 0;
            String cycleCountString = sessionState.getExtraParam();
            if(cycleCountString != null) {
                try {
                    cycleCount = Integer.parseInt(cycleCountString);
                } catch (Exception ex) {
                    //ignore
                }
            }
            cycleRemoveSipApplicationSession(id, sessionState.getInstanceName(), (cycleCount + 1));
        }
    }

    public void processBulkRemoveSipSession(ReplicationState replicationState) {
        sipSessionReplicaCache.removeFromReplicationCache(
                replicationState.getState());
    }

    public void processBulkRemoveSAS(ReplicationState replicationState) {
        sipApplicationSessionReplicaCache.removeFromReplicationCache(
                replicationState.getState());
    }

    /**
     * process the update of a SipApplicationSession
     * @param sessionState - contains the updatelastaccesstime command
     */   
    public void processUpdatelastaccesstimesas(ReplicationState sessionState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() +
                ">>processUpdatelastaccesstimesas:id: " +
                sessionState.getId() + ", version: " +
                sessionState.getVersion());
        }
        sipApplicationSessionReplicaCache.processUpdatelastaccesstime(sessionState);
    }
   
    /**
     * Find the SAS in the active cache, and passivate it. Passivation will
     * remove the SAS from the active cache.
     * @param id sip application session id
     * @param cachedSASIsLocal whether the SAS still maps to this instance.
     * @return SAS found in the active cache, null otherwise.
     */
    public ReplicableEntity findSasAndPassivate(String id,
                                                        AtomicBoolean cachedSASIsLocal) {
        cachedSASIsLocal.set(false);
        HASipApplicationSession haSipApplicationSession = null;
        SipApplicationSessionImpl sipApplicationSession
                = findSipApplicationSessionFromCacheOnly(id);
        if (sipApplicationSession instanceof HASipApplicationSession) {
            haSipApplicationSession = (HASipApplicationSession) sipApplicationSession;
            if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
                    SipReplicationUtil.isLocal(haSipApplicationSession.getId())) {
                cachedSASIsLocal.set(true);
            } else {
                // We have active SAS, but we no longer are its rightful
                // owner, i.e., it is ok for us to let go of the active SAS
                // and let it migrate to its new rightful owner.
                try {
                    boolean foregroundLocked =
                            haSipApplicationSession.isForegroundLocked();
                    // Give
                    // passivation listeners "last-minute" opportunity to make
                    // any changes to the SAS before it is migrated
                    haSipApplicationSession.notifyWillPassivate();
                    // If we weren't foreground locked, then safe to remove
                    // from our active cache
                    if (!foregroundLocked)
                        processLoadReceivedSas(haSipApplicationSession.getId());
                } catch (Throwable t) {
                    // Catch any Throwable (e.g., IllegalStateException if
                    // SAS is no longer valid, see IT 1484).
                    if (_logger.isLoggable(Level.FINE)) {
                        _logger.log(Level.FINE,
                                "Exception seen during passivation of " +
                                        "SipApplicationSession with id: " +
                                        haSipApplicationSession.getId(),
                                t);
                    }
                }
            }
        }
        return haSipApplicationSession;
    }

    public Map getActiveApplicationSessions() {
        return applicationSessions;
    }

    public Map getActiveSipSessions() {
        return sipSessions;
    }
   
    public Map getActiveServletTimers() {
        return servletTimers;
    }
   
    /**
     * process the Findsas for SipApplicationSession
     * @param queryState
     * @param useUnicast
     */    
    public ReplicationState processFindSas(ReplicationState queryState, boolean useUnicast) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processFindSas:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processFindSas:id=" + queryState.getId());
            _logger.fine("in " + this.getClass().getName() + ">>processFindSas:useUnicast=" + useUnicast);
        }
       
        //look in active cache
        AtomicBoolean cachedSASIsLocal = new AtomicBoolean();
        HASipApplicationSession haSipApplicationSession = (HASipApplicationSession)
                findSasAndPassivate((String)queryState.getId(), cachedSASIsLocal);

        //look in replica cache
        ReplicationState replicaState
            = getFromSipApplicationSessionReplicationCache((String)queryState.getId());
        //following code checks if cached SAS isLocal and if so
        //foreground locks it just for the time to generate the query response
        //indicating wasRemoteLocked and then restore the lock to it's previous state
        boolean wasCachedSASForegroundLocked = false;
        if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
                cachedSASIsLocal.get()) {
            wasCachedSASForegroundLocked = haSipApplicationSession.isForegroundLocked();
            if(!wasCachedSASForegroundLocked) {
                haSipApplicationSession.lockForeground();
            }
        }       
        ReplicationState returnState
            = getBestSipApplicationSession(haSipApplicationSession, replicaState, queryState, useUnicast);
        if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
                cachedSASIsLocal.get()) {
            if(!wasCachedSASForegroundLocked) {
                haSipApplicationSession.unlockForeground();
            }
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processFindSas:returnState=" + returnState);
        }       
        return returnState;
    }   
   
    /**
     * process the broadcastfindsas for SipApplicationSession
     * @param queryState
     */    
    public ReplicationState processBroadcastfindsas(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsas:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsas:id=" + queryState.getId());                       
        }
        return processFindSas(queryState, false);
    }
   
    public void processBroadcastloadreceivedsas(ReplicationState queryState) {
        //load is acknowledged safe to remove replica now
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processbroadcastloadreceivedsas:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processbroadcastloadreceivedsas:id=" + queryState.getId());                       
        }
        if(queryState == null || queryState.getId() == null) {
            return;
        }
        if (queryState.getState() != null) {
            processBulkLoadReceivedSAS(queryState);
            return;
        }
        String id = (String)queryState.getId();
  processLoadReceivedSas(id);
        String ignoreInstance = (String) queryState.getProperty(ReplicationState.IGNORE_REMOVE_INSTANCE_NAME);
        //only safe to remove replica if we are not the replica partner
        //now determined by passed property
        if(ignoreInstance != null && !ignoreInstance.equals(getInstanceName())) {
            ReplicationState removed =
                removeFromSipApplicationSessionReplicationCache(id);
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("in " + this.getClass().getName() +
                    ">>processbroadcastloadreceivedsas: Removed replica=" +
                    removed);
            }           
        }
    }

    public void processBulkLoadReceivedSAS(ReplicationState queryState) {
        String from = queryState.getInstanceName();
        try {
            HashSet<String> ids = (HashSet<String>) ReplicationState.getObjectValue(queryState.getState());
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("Processing bulk load-acks for sas from " +
                        from + ", number of ids = " + ids.size());
            }
            for (String sasId : ids) {
                processLoadReceivedSas(sasId);
                ReplicationState replica = getFromSipApplicationSessionReplicationCache(sasId);
                if (replica != null) {
                    removeFromSipApplicationSessionReplicationCache(sasId);
                }
            }
        } catch (Exception ex) {
            _logger.log(Level.WARNING, ex.getMessage(), ex);
        }
    }

    // Presently, we short-circuit this and always call it directly.
    // But I have left it as a normal process* method in case at some
    // point it should be a unicast load received acknowledgement.
    public void processLoadReceivedSas(String id) {
        activationHelper.unregisterSasTimerMigrationTask(id);
        //remove active sip application session if present and not locked
        SipApplicationSessionImpl sipApplicationSession
            = findSipApplicationSessionFromCacheOnly(id);
        if(sipApplicationSession != null
                && !sipApplicationSession.isForegroundLocked()) {
            sipApplicationSession.passivate();
        }
    }

    /**
     * process the load of a SipApplicationSession
     * @param queryState - contains the load command
     */
    public ReplicationState processLoadsas(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processLoadsas:queryState = " + queryState);
            _logger.fine("in " + this.getClass().getName() + ">>processLoadsas:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processLoadsas:id=" + queryState.getId());
        }
        return processFindSas(queryState, true);
    }
   
    /**
     * process the loadAdvisory of a SipApplicationSession
     * this should trigger a load call for the SipApplicationSession
     * @param extraParams
     */    
    public void processLoadadvisorysas(SipApplicationSessionExtraParams extraParams) {
        if(extraParams == null) {
            return;
        }
        String id = extraParams.getId();
        HASipApplicationSession sas = processLoadadvisorysas(id);
        if (sas != null) {
            ReplicationState loadReceivedState = ReplicationState.createBroadcastLoadReceivedState(
                    MODE_SIP, id, this.getApplicationId(), sas.getVersion(),
                    instanceName, MESSAGE_BROADCAST_LOAD_RECEIVED_SAS);
            this.sendLoadAcknowledgement(loadReceivedState, sas.getBeKey());
        }
    }

    public void processLoadadvisorysas(ReplicationState replicationState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() + ">>processLoadadvisorysas");
        }
        if(replicationState == null) {
            return;
        }

        if(isSASExpatInProgress()) {
            return;
        }
       
        if (replicationState.getState() != null) {
            processBulkLoadAdvSAS(replicationState);
            return;
        }

        //try to load from local cache first
        String id = (String)replicationState.getId();
        String from = replicationState.getInstanceName();
        HASipApplicationSession sas = processLoadadvisorysas(id);
        if (sas != null) {
            sendUnicastLoadAcknowledgementSAS(id, from, sas.getBeKey());
        }
    }
   
    private boolean isSASExpatInProgress() {
        return isExpatInProgress(sasExpatListHandler, sasReplicaExpatHandler);
    }

    private boolean isExpatInProgress(ExpatListHandler... expatHandlers) {
        for (ExpatListHandler expatHandler : expatHandlers) {
            if (expatHandler != null && expatHandler.isAwaitingExpatList()) {
                return true;
            }
        }
        return false;
    }

    // ensure that this method is called only when the SAS expat is not in progress.
    void processBulkLoadAdvSAS(ReplicationState replicationState) {
        String from = replicationState.getInstanceName();

        byte[] bytes = replicationState.getState();
        if (bytes != null) {
            try {
                HashSet<String> staleIds = new HashSet<String>();
                HashSet<String> expiredIds =
                        (HashSet<String>) ReplicationState.getObjectValue(bytes);
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("Processing bulk load-advisories for sas from " +
                            from + ", number of ids = " + expiredIds.size());
                }
                for (String expiredId : expiredIds) {
                    if (getSipApplicationSessionExpatListElement(expiredId) == null) {
                        staleIds.add(expiredId);
                    } else {
                        HASipApplicationSession sas = processLoadadvisorysas(expiredId);
                        if (sas != null && !from.equalsIgnoreCase(
                                SipApplicationSessionUtil.getFailoverServerInstanceForBeKey(sas.getBeKey()))) {
                            staleIds.add(expiredId);
                        }
                    }
                }
                sendSasLoadAcks(from, staleIds);
            } catch (Exception ex) {
                logger.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
   
    public HASipApplicationSession processLoadadvisorysas(String id) {
        HASipApplicationSession sipApplicationSession = (HASipApplicationSession)
                this.findSipApplicationSessionFromCacheOnly(id);
        if (sipApplicationSession != null) {
            sipApplicationSession.touchAndSave();
            sipApplicationSession.activateGraph();
        } else {
            //load and activate SipApplicationSession
            try {
                sipApplicationSession = (HASipApplicationSession) swapInSipApplicationSession(id, false);
                if (sipApplicationSession != null) {
                    sipApplicationSession.activateGraph();
                }
            } catch (Exception ex) {
                _logger.log(Level.WARNING, "sas_unable_to_load_in_response_to_loadadvisory", id);
                _logger.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
        return sipApplicationSession;
    }  

    public void handleDynamicOwnershipChanges(Event event,
                                              String triggeringInstance,
                boolean isLbChange) {
        if (isBeingReleased) {
            return;
        }
  if (!isLbChange) {
      return;
  }
        if(!SipReplicationUtil.isInstanceLoadBalancedByCLB()) {
            return;
        }
  sasExpatListHandler.eventReceived(event, triggeringInstance);
  sipSessionExpatListHandler.eventReceived(event, triggeringInstance);
  servletTimerExpatListHandler.eventReceived(event, triggeringInstance);
        if(!sasExpatListHandler.shouldCalculateExpatList()) {
            return; // expat calculation is already in progress.
        }
        long startTime = System.currentTimeMillis();
        ExpatListHandler.expatCalculationStarted();
       
        currentEvent = event;
        currentTriggeringInstance = triggeringInstance;
        synchronizeKeys();
       
        CountDownLatch doneSignal = new CountDownLatch(3);       
        sasExpatListHandler.preInvoke(event, triggeringInstance);
        sipSessionExpatListHandler.preInvoke(event, triggeringInstance);
        servletTimerExpatListHandler.preInvoke(event, triggeringInstance);
        boolean isExpatListLocked = false;
        if (sasExpatListHandler.isAwaitingExpatList()) { // IMP :: do preInvoke before doing this check.
            // if we need to await for any list to be pushed to us from
            // remote instance, then only lock the list, otherwise allow
            // read on the expat list.
            sasExpatReadWriteLock.writeLock().lock();
            sipSessionExpatReadWriteLock.writeLock().lock();
            servletTimerExpatReadWriteLock.writeLock().lock();
            isExpatListLocked = true;
        }
        ExpatListQueryTask sasExpatListQueryTask
            = getExpatListAsync(sasExpatListHandler, doneSignal);
        ExpatListQueryTask sipSessionExpatListQueryTask
            = getExpatListAsync(sipSessionExpatListHandler, doneSignal);
        ExpatListQueryTask servletTimerExpatListQueryTask
            = getExpatListAsync(servletTimerExpatListHandler, doneSignal);       
        try {
            doneSignal.await(ExpatListHandler.EXPAT_LIST_QUERY_TIMEOUT * 2, TimeUnit.MILLISECONDS);
        } catch(InterruptedException ex) {}       
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("SipTransactionPersistentManager>>handleDynamicOwnershipChanges after a wait: wait time = " + (System.currentTimeMillis() - startTime));
        }
        try {
            HashMap sasResult = sasExpatListQueryTask.getExpatList();
            if(sasResult != null) {                                   
                sasExpatIdsMap = sasResult;
            }
            HashMap sipSessionResult = sipSessionExpatListQueryTask.getExpatList();         
            if(sipSessionResult != null) {
                sipSessionExpatIdsMap = sipSessionResult;
            }
            HashMap servletTimerResult = servletTimerExpatListQueryTask.getExpatList();
            if(servletTimerResult != null) {
                servletTimerExpatIdsMap = servletTimerResult;
            }
        } finally {
            sasExpatIdsMap = mergeWithReplicaExpats(
                    sasExpatIdsMap, sasReplicaExpatHandler);
            sipSessionExpatIdsMap = mergeWithReplicaExpats(
                    sipSessionExpatIdsMap, ssReplicaExpatHandler);
            servletTimerExpatIdsMap = mergeWithReplicaExpats(
                    servletTimerExpatIdsMap, stReplicaExpatHandler);
            sasExpatListHandler.postInvoke();
            sipSessionExpatListHandler.postInvoke();
            servletTimerExpatListHandler.postInvoke();
            if (isExpatListLocked) {
                sasExpatReadWriteLock.writeLock().unlock();
                sipSessionExpatReadWriteLock.writeLock().unlock();
                servletTimerExpatReadWriteLock.writeLock().unlock();
            }
            currentEvent = null;
            currentTriggeringInstance = null;
            // Print the final map after the merge to check if everything is fine.
            ReplicationUtil.printExpatList(sasExpatIdsMap, "SAS(final)", startTime);
            ReplicationUtil.printExpatList(sipSessionExpatIdsMap, "SipSession(final)", startTime);
            ReplicationUtil.printExpatList(servletTimerExpatIdsMap, "ServletTimer(final)", startTime);
        }
        ExpatListHandler.expatCalculationEnded();
    }
   
    private Event currentEvent;
    private String currentTriggeringInstance;

    /**
     * Invoke the synchronizeKeys method simultaneously on all the stores.
     * Note that this method is common to all stores (in-house or third party)
     */
    private void synchronizeKeys() {
        // TODO :: For the third party implementation to work,
        // TODO :: we need to revisit the parameters.
        new SynchronizeKeysTask(getSipApplicationSessionBackingStore(), null, null, false);
        new SynchronizeKeysTask(getSipSessionBackingStore(), null, null, false);
        new SynchronizeKeysTask(getServletTimerBackingStore(), null, null, false);
    }

    /**
     * JxtaBackingStoreImpl will call back this method. Hence, this is a
     * in-memory implementation specific method.
     */
    public void __synchronizeKeys(JxtaBackingStoreImpl jxtaBackingStore) {
        ExpatListHandler expatHandler = null;
        if (jxtaBackingStore == sipApplicationSessionBackingStore) {
            expatHandler = sasReplicaExpatHandler;
        } else if(jxtaBackingStore == sipSessionBackingStore) {
            expatHandler = ssReplicaExpatHandler;
        } else if(jxtaBackingStore == servletTimerBackingStore) {
            expatHandler = stReplicaExpatHandler;
        }
        if(expatHandler != null) {
            expatHandler.preInvoke(currentEvent, currentTriggeringInstance);
            expatHandler.call();
            // NOTE :: Since the result of the above call needs to be retained
            // until the results are merged with activeExpat, hence the invocation of
            // postInvoke is delayed until then. mergeWithReplicaExpats method
            // calls postInvoke after merging the replica expat with active expat.
        }
    }

    /**
     * For the third party backing store implementations,
     * this method will be a no-op.
     */
    private HashMap mergeWithReplicaExpats(HashMap activeExpat,
                                           ExpatListHandler replicaExpatHandler) {
        HashMap result = activeExpat;
        if(replicaExpatHandler != null) {
            try {
                HashMap replicaExpat = replicaExpatHandler.awaitAndGetResult();
                if(replicaExpat != null && !replicaExpat.isEmpty()) {
                    if(activeExpat != null) {
                        replicaExpat.putAll(activeExpat);
                    }
                    result = replicaExpat;
                }
            } finally {
                // since we have the results now, we can call postInvoke() and
                // clear the memory references.
                replicaExpatHandler.postInvoke();
            }
        }
        return result;
    }

   
    boolean isExpectingExpatIdsMap() {
        return sasExpatListHandler.isAwaitingExpatList() ||
    sipSessionExpatListHandler.isAwaitingExpatList() ||
    servletTimerExpatListHandler.isAwaitingExpatList();
    }   
   
    boolean canTrustReplicaDuringExpat(String replicaSource) {
        if(replicaSource == null) {
            return false;
        }
        DynamicOwnershipManager.Event event = currentEvent;
        String instance = currentTriggeringInstance;
        if(DynamicOwnershipManager.Event.FAILURE.equals(event) &&
                replicaSource.equalsIgnoreCase(instance)) {
            return true;
        }
        return false;
    }

    private ExpatListQueryTask getExpatListAsync(ExpatListHandler expatListHandler,
            CountDownLatch doneSignal) {
        ExpatListQueryTask expatListQueryTask
            = new ExpatListQueryTask(expatListHandler, doneSignal);
        return expatListQueryTask;
    }   

    //Begin Expat List for SAS 
   
    /**
     * process the broadcastfindsasexpatids for SipApplicationSession
     * @param queryState
     */    
    public ReplicationState processBroadcastfindsasexpatids(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsasexpatids:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsasexpatids:owningInstance=" + queryState.getExtraParam());
        }
        if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
    !ReplicationHealthChecker.isServerLbEnabled(
      getInstanceName())) {
      // Don't respond if the CLB is running but we are not CLB enabled
      return null;
  }
        sasExpatListHandler.sendExpatQueryResponse(queryState);
        return null;
    }

    public ReplicationState processBroadcastfindsasreplicaexpatids(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsasreplicaexpatids:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsasreplicaexpatids:owningInstance=" + queryState.getExtraParam());
        }
        if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
    !ReplicationHealthChecker.isServerLbEnabled(
      getInstanceName())) {
      // Don't respond if the CLB is running but we are not CLB enabled
      return null;
  }
        if(sasReplicaExpatHandler != null) {
            sasReplicaExpatHandler.sendExpatQueryResponse(queryState);
        }
        return null;
    }

    public int removeExpiredSessions() {
        //Deliberate no op
        return 0;
    }
   
    //End Expat List for SAS

    //Begin Expat List for SipSessions   

/*
    HashSet<ExpatListElement> getSipSessionExpatIds(
            String requestingInstance, boolean consultActiveCache) {
        //using set to avoid dups
        HashSet expatIds = new HashSet();
        //iterate over sip session replicas
        BaseCache replicatedSipSessionsCache = getReplicatedSipSessions();
        Iterator it = replicatedSipSessionsCache.values();
        long version = -1L;
        while (it.hasNext()) {
            ReplicationState state = (ReplicationState) it.next();
            String ssId = (String) state.getId();
            //use bekey for mapping instance ownership
            String beKey = (String) state.getProperty(BEKEY);
            if (beKey != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstanceForBeKey(beKey);
                if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                    version = state.getVersion();
                    expatIds.add(new ExpatListElement(ssId, version, instanceName));
                }
            }
        }
        if (consultActiveCache) {
            try {
                //iterate over active sip session cache
                Iterator it2 = sipSessions.values().iterator();
                while (it2.hasNext()) {
                    HASipSession ss = (HASipSession) it2.next();
                    String ssId = (String) ss.getId();
                    String sasId = ss.getParentSASId();
                    if (sasId != null) {
                        //use parent sas id for mapping to owning instance
                        String rightfulOwner = SipApplicationSessionUtil.
                                getActualServerInstance(sasId);
                        if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                            version = ss.getVersion();
                            expatIds.add(new ExpatListElement(
                                    ssId, version, instanceName, true));
                        }
                    }
                }
            } catch (NoSuchFieldError e) {
                ;
            }
        }
        return expatIds;
    }
*/

    /**
     * Get the SipSession' expat list from the active cache for a given instance.
     */
    HashSet<ExpatListElement> getSipSessionExpatIdsFromActive(String requestingInstance) {
        //using set to avoid dups
        HashSet expatIds = new HashSet();
        long version = -1L;
        try {
            //iterate over active sip session cache
            Iterator it2 = sipSessions.values().iterator();
            while (it2.hasNext()) {
                HASipSession ss = (HASipSession) it2.next();
                String ssId = (String) ss.getId();
                String sasId = ss.getParentSASId();
                if (sasId != null) {
                    //use parent sas id for mapping to owning instance
                    String rightfulOwner = SipApplicationSessionUtil.
                            getActualServerInstance(sasId);
                    if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                        version = ss.getVersion();
                        expatIds.add(new ExpatListElement(
                                ssId, version, instanceName, true));
                    }
                }
            }
        } catch (NoSuchFieldError e) {
            ;
        }
        return expatIds;
    }

    /**
     * Get the SipSession' expat list from the replica cache for a given instance.
     */
    HashSet<ExpatListElement> getSipSessionExpatIdsFromReplica(String requestingInstance) {
        //using set to avoid dups
        HashSet expatIds = new HashSet();
        //iterate over sip session replicas
        BaseCache replicatedSipSessionsCache = getReplicatedSipSessions();
        Iterator it = replicatedSipSessionsCache.values();
        long version = -1L;
        while (it.hasNext()) {
            ReplicationState state = (ReplicationState) it.next();
            String ssId = (String) state.getId();
            //use bekey for mapping instance ownership
            String beKey = (String) state.getProperty(BEKEY);
            if (beKey != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstanceForBeKey(beKey);
                if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                    version = state.getVersion();
                    expatIds.add(new ExpatListElement(ssId, version, instanceName));
                }
            }
        }
        return expatIds;
    }

    /**
     * Get the SipSession' expat list from the active cache for all the surviving instances.
     */
    private void getSipSessionExpatIdsFromActive(ExpatListQueryResults results) {
        //iterate over active sip session cache
        long version = -1L;
        Iterator it2 = sipSessions.values().iterator();
        while (it2.hasNext()) {
            HASipSession ss = (HASipSession) it2.next();
            String ssId = (String) ss.getId();
            String sasId = ss.getParentSASId();
            //use parent sas id for mapping to owning instance
            if (sasId != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstance(sasId);
                if (rightfulOwner != null
                        && !rightfulOwner.equalsIgnoreCase(instanceName)) {
                    version = ss.getVersion();
                    ExpatListElement expatElement = new ExpatListElement(ssId,
                            version, instanceName, true);
                    results.addQueryResultFor(rightfulOwner, expatElement);
                }
            }
        }
    }

    /**
     * Get the SipSession' expat list from the replica cache for all the surviving instances.
     */
    private void getSipSessionExpatIdsFromReplica(ExpatListQueryResults results) {
        //iterate over sip session replicas
        BaseCache replicatedSipSessionsCache = getReplicatedSipSessions();
        Iterator it = replicatedSipSessionsCache.values();
        long version = -1L;
        while (it.hasNext()) {
            ReplicationState state = (ReplicationState) it.next();
            String ssId = (String) state.getId();
            //use bekey for mapping instance ownership
            String beKey = (String) state.getProperty(BEKEY);
            if (beKey != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstanceForBeKey(beKey);
                version = state.getVersion();
                ExpatListElement expatElement = new ExpatListElement(ssId,
                        version, instanceName);
                results.addQueryResultFor(rightfulOwner, expatElement);
            }
        }
    }
   
/*
    private void getAllSipSessionExpatIds(ExpatListQueryResults results) {
        //iterate over sip session replicas
        BaseCache replicatedSipSessionsCache = getReplicatedSipSessions();
        Iterator it = replicatedSipSessionsCache.values();
        long version = -1L;
        while (it.hasNext()) {
            ReplicationState state = (ReplicationState) it.next();
            String ssId = (String) state.getId();
            //use bekey for mapping instance ownership
            String beKey = (String) state.getProperty(BEKEY);
            if (beKey != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstanceForBeKey(beKey);
                version = state.getVersion();
                ExpatListElement expatElement = new ExpatListElement(ssId,
                        version, instanceName);
                results.addQueryResultFor(rightfulOwner, expatElement);
            }
        }
        //iterate over active sip session cache
        Iterator it2 = sipSessions.values().iterator();
        while (it2.hasNext()) {
            HASipSession ss = (HASipSession) it2.next();
            String ssId = (String) ss.getId();
            String sasId = ss.getParentSASId();
            //use parent sas id for mapping to owning instance
            if (sasId != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstance(sasId);
                if (rightfulOwner != null
                        && !rightfulOwner.equalsIgnoreCase(instanceName)) {
                    version = ss.getVersion();
                    ExpatListElement expatElement = new ExpatListElement(ssId,
                            version, instanceName, true);
                    results.addQueryResultFor(rightfulOwner, expatElement);
                }
            }
        }
    }
*/

/*
    List getSipSessionExpatIdsThirdPartySPI(String owningInstanceName) {
        BackingStore sipSessionBackingStore
            = this.getSipSessionBackingStore();
        SipSessionExtraParams ssExtraParamCriteria
            = SipSessionExtraParams.createSearchCriteria(
                getApplicationId(), owningInstanceName);
        Collection<SipSessionExtraParams> ssColl
            = sipSessionBackingStore.findByCriteria(ssExtraParamCriteria);

        List expatIds = new ArrayList();
        //using set to avoid dups
        HashSet expatIdsSet = new HashSet();
        Iterator<SipSessionExtraParams> ssResults =
            (Iterator<SipSessionExtraParams>) ssColl.iterator();
        while (ssResults.hasNext()) {
            SipSessionExtraParams eParam = ssResults.next();
            if (owningInstanceName.equals(eParam.getCurrentOwnerInstanceName())) {
                expatIdsSet.add(new ExpatListElement((String)eParam.getId(), -1L, null));
            }
        }
        //iterate over active sas cache
        long nextVersion = -1L;
        Iterator it2 = sipSessions.values().iterator();
        while(it2.hasNext()) {
            HASipSession nextSipSession
                = (HASipSession)it2.next();
            String nextSipSessionId
                = (String)nextSipSession.getId();
            String nextSipApplicationSessionId = null;
            if(nextSipSession.getExtraParameters() != null) {
                //use parent sas id for mapping to owning instance
                nextSipApplicationSessionId
                    = nextSipSession.getExtraParameters().getParentSasId();
                String nextRightfulOwnerInstanceName
                    = SipApplicationSessionUtil.getActualServerInstance(nextSipApplicationSessionId);
                if(nextRightfulOwnerInstanceName != null
                    && nextRightfulOwnerInstanceName.equalsIgnoreCase(owningInstanceName)) {
                    nextVersion = nextSipSession.getVersion();
                    expatIdsSet.add(new ExpatListElement(nextSipSessionId, nextVersion, getInstanceName(), true));
                }
            }
        }
        expatIds.addAll(expatIdsSet);
        return expatIds;
    }
*/

    /**
     * process the processBroadcastfindsipsessionexpatids for SipSession
     * @param queryState
     */
    public ReplicationState processBroadcastfindsipsessionexpatids(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsipsessionexpatids:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsipsessionexpatids:owningInstance=" + queryState.getExtraParam());
        }
        if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
    !ReplicationHealthChecker.isServerLbEnabled(
      getInstanceName())) {
      // Don't respond if the CLB is running but we are not CLB enabled
      return null;
  }
        sipSessionExpatListHandler.sendExpatQueryResponse(queryState);
        return null;
    }

    public ReplicationState processBroadcastfindsipsessionreplicaexpatids(
            ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsipsessionreplicaexpatids:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsipsessionreplicaexpatids:owningInstance=" + queryState.getExtraParam());
        }
        if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
    !ReplicationHealthChecker.isServerLbEnabled(
      getInstanceName())) {
      // Don't respond if the CLB is running but we are not CLB enabled
      return null;
  }
        if(ssReplicaExpatHandler != null) {
            ssReplicaExpatHandler.sendExpatQueryResponse(queryState);
        }
        return null;
    }

    //End Expat List for SipSession

    //Begin Expat List for ServletTimer      

/*
    HashSet<ExpatListElement> getServletTimerExpatIds(
            String requestingInstance, boolean consultActiveCache) {
        //using set to avoid dups
        HashSet expatIds = new HashSet();
        //iterate over servlet timer replicas
        BaseCache replicatedServletTimersCache = getReplicatedServletTimers();
        Iterator it = replicatedServletTimersCache.values();
        long version = -1L;
        while (it.hasNext()) {
            ReplicationState state = (ReplicationState) it.next();
            String stId = (String) state.getId();
            //use bekey for mapping instance ownership
            String beKey = (String) state.getProperty(BEKEY);
            if (beKey != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstanceForBeKey(beKey);
                if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                    version = state.getVersion();
                    expatIds.add(new ExpatListElement(stId, version, instanceName));
                }
            }
        }
        if (consultActiveCache) {
            try {
                //iterate over active servlet timer cache
                Iterator it2 = servletTimers.values().iterator();
                while (it2.hasNext()) {
                    HAServletTimer st = (HAServletTimer) it2.next();
                    String stId = (String) st.getId();
                    String sasId = st.getParentSASId();
                    if (sasId != null) {
                        //use parent sas id for mapping to owning instance
                        String rightfulOwner = SipApplicationSessionUtil.
                                getActualServerInstance(sasId);
                        if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                            version = st.getVersion();
                            expatIds.add(new ExpatListElement(stId,
                                    version, instanceName, true));
                        }
                    }
                }
            } catch (NoSuchFieldError e) {
                ;
            }
        }
        return expatIds;
    }
*/

    /**
     * Get the ServletTimer' expat list from the active cache for a given instance.
     */
    HashSet<ExpatListElement> getServletTimerExpatIdsFromActive(
            String requestingInstance) {
        //using set to avoid dups
        HashSet expatIds = new HashSet();
        //iterate over servlet timer replicas
        long version = -1L;
        try {
            //iterate over active servlet timer cache
            Iterator it2 = servletTimers.values().iterator();
            while (it2.hasNext()) {
                HAServletTimer st = (HAServletTimer) it2.next();
                String stId = (String) st.getId();
                String sasId = st.getParentSASId();
                if (sasId != null) {
                    //use parent sas id for mapping to owning instance
                    String rightfulOwner = SipApplicationSessionUtil.
                            getActualServerInstance(sasId);
                    if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                        version = st.getVersion();
                        expatIds.add(new ExpatListElement(stId,
                                version, instanceName, true));
                    }
                }
            }
        } catch (NoSuchFieldError e) {
            ;
        }
        return expatIds;
    }

    /**
     * Get the ServletTimer' expat list from the replica cache for a given instance.
     */
    HashSet<ExpatListElement> getServletTimerExpatIdsFromReplica(
            String requestingInstance) {
        //using set to avoid dups
        HashSet expatIds = new HashSet();
        //iterate over servlet timer replicas
        BaseCache replicatedServletTimersCache = getReplicatedServletTimers();
        Iterator it = replicatedServletTimersCache.values();
        long version = -1L;
        while (it.hasNext()) {
            ReplicationState state = (ReplicationState) it.next();
            String stId = (String) state.getId();
            //use bekey for mapping instance ownership
            String beKey = (String) state.getProperty(BEKEY);
            if (beKey != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstanceForBeKey(beKey);
                if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                    version = state.getVersion();
                    expatIds.add(new ExpatListElement(stId, version, instanceName));
                }
            }
        }
        return expatIds;
    }

    /**
     * Get the ServletTimer' expat list from the active cache for all the surviving instances.
     */
    private void getServletTimerExpatIdsFromActive(ExpatListQueryResults results) {
        long version = -1L;
        //iterate over active servlet timer cache
        Iterator it2 = servletTimers.values().iterator();
        while (it2.hasNext()) {
            HAServletTimer st = (HAServletTimer) it2.next();
            String stId = (String) st.getId();
            String sasId = st.getParentSASId();
            //use parent sas id for mapping to owning instance
            if (sasId != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstance(sasId);
                if (rightfulOwner != null
                        && !rightfulOwner.equalsIgnoreCase(instanceName)) {
                    version = st.getVersion();
                    ExpatListElement expatElement = new ExpatListElement(stId,
                            version, instanceName, true);
                    results.addQueryResultFor(rightfulOwner, expatElement);
                }
            }
        }
    }

    /**
     * Get the ServletTimer' expat list from the replica cache for all the surviving instances.
     */
    private void getServletTimerExpatIdsFromReplica(ExpatListQueryResults results) {
        //iterate over servlet timer replicas
        BaseCache replicatedServletTimersCache = getReplicatedServletTimers();
        Iterator it = replicatedServletTimersCache.values();
        long version = -1L;
        while(it.hasNext()) {
            ReplicationState state = (ReplicationState)it.next();
            String stId = (String)state.getId();
            //use bekey for mapping instance ownership
            String beKey = (String) state.getProperty(BEKEY);
            if(beKey != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstanceForBeKey(beKey);
                version = state.getVersion();
                ExpatListElement expatElement = new ExpatListElement(stId,
                        version, instanceName);
                results.addQueryResultFor(rightfulOwner, expatElement);
            }
        }
    }
   
/*
    private void getAllServletTimerExpatIds(ExpatListQueryResults results) {
        //iterate over servlet timer replicas
        BaseCache replicatedServletTimersCache = getReplicatedServletTimers();
        Iterator it = replicatedServletTimersCache.values();
        long version = -1L;
        while(it.hasNext()) {
            ReplicationState state = (ReplicationState)it.next();
            String stId = (String)state.getId();
            //use bekey for mapping instance ownership
            String beKey = (String) state.getProperty(BEKEY);
            if(beKey != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstanceForBeKey(beKey);
                version = state.getVersion();
                ExpatListElement expatElement = new ExpatListElement(stId,
                        version, instanceName);               
                results.addQueryResultFor(rightfulOwner, expatElement);
            }
        }
        //iterate over active servlet timer cache
        Iterator it2 = servletTimers.values().iterator();
        while (it2.hasNext()) {
            HAServletTimer st = (HAServletTimer) it2.next();
            String stId = (String) st.getId();
            String sasId = st.getParentSASId();
            //use parent sas id for mapping to owning instance
            if (sasId != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstance(sasId);
                if (rightfulOwner != null
                        && !rightfulOwner.equalsIgnoreCase(instanceName)) {
                    version = st.getVersion();
                    ExpatListElement expatElement = new ExpatListElement(stId,
                            version, instanceName, true);
                    results.addQueryResultFor(rightfulOwner, expatElement);
                }
            }
        }
    }       
*/

/*
    List getServletTimerExpatIdsThirdPartySPI(String owningInstanceName) {
        BackingStore servletTimerBackingStore
            = this.getServletTimerBackingStore();
        ServletTimerExtraParams stExtraParamCriteria
            = ServletTimerExtraParams.createSearchCriteria(
                getApplicationId(), owningInstanceName);
        Collection<ServletTimerExtraParams> stColl
            = servletTimerBackingStore.findByCriteria(stExtraParamCriteria);

        List expatIds = new ArrayList();
        //using set to avoid dups
        HashSet expatIdsSet = new HashSet();
        Iterator<ServletTimerExtraParams> stResults =
            (Iterator<ServletTimerExtraParams>) stColl.iterator();
        while (stResults.hasNext()) {
            ServletTimerExtraParams eParam = stResults.next();
            if (owningInstanceName.equals(eParam.getCurrentOwnerInstanceName())) {
                expatIdsSet.add(new ExpatListElement((String)eParam.getId(), -1L, null));
            }
        }
        //iterate over active sas cache
        long nextVersion = -1L;
        Iterator it2 = servletTimers.values().iterator();
        while(it2.hasNext()) {
            HAServletTimer nextServletTimer
                = (HAServletTimer)it2.next();
            String nextServletTimerId
                = (String)nextServletTimer.getId();
            String nextSipApplicationSessionId = null;
            if(nextServletTimer.getExtraParameters() != null) {
                //use parent sas id for mapping to owning instance
                nextSipApplicationSessionId
                    = nextServletTimer.getExtraParameters().getParentSasId();
                String nextRightfulOwnerInstanceName
                    = SipApplicationSessionUtil.getActualServerInstance(nextSipApplicationSessionId);
                if(nextRightfulOwnerInstanceName != null
                    && nextRightfulOwnerInstanceName.equalsIgnoreCase(owningInstanceName)) {
                    nextVersion = nextServletTimer.getVersion();
                    expatIdsSet.add(new ExpatListElement(nextServletTimerId, nextVersion, getInstanceName(), true));
                }
            }
        }
        expatIds.addAll(expatIdsSet);
        return expatIds;
    }
*/

    /**
     * process the processBroadcastfindservlettimerexpatids for SipSession
     * @param queryState
     */
    public ReplicationState processBroadcastfindservlettimerexpatids(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindservlettimerexpatids:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindservlettimerexpatids:owningInstance=" + queryState.getExtraParam());
        }
        if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
    !ReplicationHealthChecker.isServerLbEnabled(
      getInstanceName())) {
      // Don't respond if the CLB is running but we are not CLB enabled
      return null;
  }
        servletTimerExpatListHandler.sendExpatQueryResponse(queryState);
        return null;
    }

    public ReplicationState processBroadcastfindservlettimerreplicaexpatids(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindservlettimerreplicaexpatids:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindservlettimerreplicaexpatids:owningInstance=" + queryState.getExtraParam());
        }
        if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
    !ReplicationHealthChecker.isServerLbEnabled(
      getInstanceName())) {
      // Don't respond if the CLB is running but we are not CLB enabled
      return null;
  }
        if(stReplicaExpatHandler != null) {
            stReplicaExpatHandler.sendExpatQueryResponse(queryState);
        }
        return null;
    }

    //End Expat List for ServletTimer
   
    /**
     * find the best version of SipApplicationSession
     * removing any stale versions and return query result
     * @param activeSipApplicationSession SipApplicationSession
     *      from active cache
     * @param replicaSipApplicationSession SipApplicationSession
     *      from replica cache
     * @param queryState version requested in query (-1 means
     *      version unaware
     * @param useUnicast is this for unicast or broadcast
     */    
    private ReplicationState getBestSipApplicationSession(HASipApplicationSession activeSipApplicationSession,
        ReplicationState replicaSipApplicationSession, ReplicationState queryState, boolean useUnicast) {
        ReplicationState bestResult = null;
        long queryVersion = queryState.getVersion();
       
        //first check for none found in either active or replica caches
        if(replicaSipApplicationSession == null && activeSipApplicationSession == null) {
            //return nack
            if(useUnicast) {
                return ReplicationState.createUnicastQueryResponseFrom(queryState, true);
            } else {
                return ReplicationState.createQueryResponseFrom(queryState, true);
            }
        }
       
        //next check for artifacts found in both active and replica caches
        if(replicaSipApplicationSession != null && activeSipApplicationSession != null) {
            //compare and remove the lesser version
            //keeping the higher version as (tentative) best
            if(replicaSipApplicationSession.getVersion() <= activeSipApplicationSession.getVersion()) {
                //remove stale replica - work with active
                removeFromSipApplicationSessionReplicationCache((String)replicaSipApplicationSession.getId());
                //create appropriate response from active
                bestResult
                    = createSipApplicationSessionResponseFrom(activeSipApplicationSession, queryState, useUnicast);
                // START IT 1550
                if (activeSipApplicationSession.isForegroundLocked()) {
                    bestResult.setVersion(Integer.MAX_VALUE);
                }
                // END IT 1550               
            } else {
                //remove stale active - work with replica
                clearFromSipApplicationSessionManagerCache(activeSipApplicationSession.getId());              
                //create appropriate response from replica
                bestResult
                    = createSipApplicationSessionResponseFrom(replicaSipApplicationSession, queryState, useUnicast);
            }
        } else {
            //either replica or active is null and other is non-null
            //replica is null and active is not null
            if(replicaSipApplicationSession == null) {               
                //create appropriate response from active
                bestResult
                    = createSipApplicationSessionResponseFrom(activeSipApplicationSession, queryState, useUnicast);
                // START IT 1550
                if (activeSipApplicationSession.isForegroundLocked()) {
                    bestResult.setVersion(Integer.MAX_VALUE);
                }
                // END IT 1550               
            } else {
                //active is null & replica is not null
                //create appropriate response from replica
                bestResult
                    = createSipApplicationSessionResponseFrom(replicaSipApplicationSession, queryState, useUnicast);
            }
        }
        return bestResult;
    }
   
    private ReplicationState createSipApplicationSessionResponseFrom(ReplicationState replicaSipApplicationSession,
            ReplicationState queryState, boolean useUnicast) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("createSipApplicationSessionResponseFromReplicaAndReplica:useUnicast = " + useUnicast
                + " queryState = " + queryState + " replicaSipApplicationSession = " + replicaSipApplicationSession);
        }
        //create appropriate response from replica
        ReplicationState result = null;
        long queryVersion = queryState.getVersion();       
        if(queryVersion != -1 && replicaSipApplicationSession.getVersion() < queryVersion) {
            //return nack & clear stale replica
            removeFromSipApplicationSessionReplicationCache((String)replicaSipApplicationSession.getId());
            if(useUnicast) {
                result = ReplicationState.createUnicastQueryResponseFrom(queryState, true);
            } else {
                result = ReplicationState.createQueryResponseFrom(queryState, true);
            }
        } else {
            //return real response based on replica
            if(useUnicast) {
                result = ReplicationState.createUnicastQueryResponseFrom(replicaSipApplicationSession, queryState.getCommand());
            } else {
                result = ReplicationState.createQueryResponseFrom(replicaSipApplicationSession);
            }
        }
        return result;
    }

    private ReplicationState createSipApplicationSessionResponseFrom(HASipApplicationSession activeSipApplicationSession,
            ReplicationState queryState, boolean useUnicast) {
        //create appropriate response from active
        ReplicationState result = null;
        long queryVersion = queryState.getVersion();       
        if(queryVersion != -1 && activeSipApplicationSession.getVersion() < queryVersion) {
            //return nack & clear stale active
            clearFromSipApplicationSessionManagerCache(activeSipApplicationSession.getId());
            if(useUnicast) {
                result = ReplicationState.createUnicastQueryResponseFrom(queryState, true);
            } else {
                result = ReplicationState.createQueryResponseFrom(queryState, true);
            }
        } else {
            //return real response based on active SAS
            try {
                result = createQueryResponseFrom(activeSipApplicationSession, useUnicast);
            } catch (IOException ioe) {
                _logger.log(Level.WARNING,
                    "Failed load: Unable to serialize " +
                    activeSipApplicationSession, ioe);
                // We've been unable to serialize the given active
                // SipApplicationSession.
                // Clear it from the active cache and return a nack instead
                clearFromSipApplicationSessionManagerCache(
                    activeSipApplicationSession.getId());
                if(useUnicast) {
                    result = ReplicationState.createUnicastQueryResponseFrom(queryState, true);
                } else {
                    result = ReplicationState.createQueryResponseFrom(queryState, true);
                }
            }
        }

        return result;
    }
   
    /**
     * Converts the given SipApplicationSession to a ReplicationState.
     *
     * @param sas The SipApplicationSession to be converted
     *
     * @return The ReplicationState corresponding to the given
     * SipApplicationSession
     */
    private ReplicationState createQueryResponseFrom(
            HASipApplicationSession sas, boolean useUnicast) throws IOException {
        byte[] containerExtraParamState = null;
        SipApplicationSessionExtraParams containerExtraParams
            = sas.getExtraParameters();
        if(containerExtraParams != null) {
            try {
                containerExtraParamState
                    = ReplicationUtil.getByteArray(containerExtraParams, isReplicationCompressionEnabled());
            } catch (IOException ex) {
                ; //deliberate no-op
            }
        }
        if(!useUnicast) {
            return new ReplicationState(
                    MODE_SIP,
                    sas.getId(),
                    getApplicationId(),
                    sas.getVersion(),
                    0L,
                    0L,
                    null,
                    null,
                    null,
                    ReplicationState.RETURN_BROADCAST_MSG_COMMAND,
                    ReplicationUtil.getByteArray(sas, isReplicationCompressionEnabled()),
                    null,
                    containerExtraParamState);
        } else {
            return new ReplicationState(
                    MODE_SIP,
                    sas.getId(),
                    getApplicationId(),
                    sas.getVersion(),
                    0L,
                    0L,
                    LOAD_SAS_COMMAND, //put original command in extraParam slot
                    null,
                    null,
                    ReplicationState.RETURN_UNICAST_MSG_COMMAND,
                    ReplicationUtil.getByteArray(sas, isReplicationCompressionEnabled()),
                    null,
                    containerExtraParamState);
        }
    }
   
    /**
     * Gets the SipApplicationSession with the given id
     * from the active cache only
     *
     * @return The SipApplicationSession with the given id, or null if not
     * found
     */
    public SipApplicationSessionImpl findSipApplicationSessionFromCacheOnly(String id) {
        if (id == null)
            return (null);
        Object monitor = getReplicationSessionMonitor(id);
        synchronized(monitor) {
            HASipApplicationSession result
                = (HASipApplicationSession)super.findSipApplicationSessionFromCacheOnly(id);
            if(!this.isActiveCacheReconciliationOngoing()) {
                return result;
            } else {
                if(result == null || !result.isSuspect()) {
                    //if null just return it
                    //if not suspect it has already been checked
                    return result;
                }
                if(RollingUpgradeUtil.canUseSuspectSession(result,
                        sasExpatIdsMap, sasExpatReadWriteLock)) {
                    //if it passes the check return it
                    return result;
                } else {
                    removeSipApplicationSessionFromCache(result);
                    return null;
                }
            }
        }
    }

    protected void clearFromSipApplicationSessionManagerCache(String id) {
        SipApplicationSessionImpl sess
            = super.findSipApplicationSessionFromCacheOnly(id);
        if(sess != null) {                              
            this.removeSipApplicationSessionFromCache(sess);
        }
    }   
   
    //SipSession process methods
   
    /**
     * process the save of a SipSession
     * @param sessionState - contains the save command
     */    
    public void processSavesipsession(ReplicationState sessionState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() + ">>processSavess");
        }       
        this.putInSipSessionReplicationCache(sessionState);
    }   
   
    /**
     * process the removal of a Sip Session
     * @param sessionState - contains the remove command
     */    
    public void processRemovesipsession(ReplicationState sessionState) {
        if (sessionState.getState() != null) {
            processBulkRemoveSipSession(sessionState);
            return;
        }
        sipSessionReplicaCache.processRemove(sessionState);
    }
   
    /**
     * process the update of a SipSession
     * @param sessionState - contains the updatelastaccesstime command
     */   
    public void processUpdatelastaccesstimesipsession(ReplicationState sessionState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() +
                ">>processUpdatelastaccesstimess:id: " +
                sessionState.getId() + ", version: " +
                sessionState.getVersion());
        }
        sipSessionReplicaCache.processUpdatelastaccesstime(sessionState);
    }
   
    public ReplicableEntity findSipSessionAndPassivate(String id,
                                                       AtomicBoolean cachedSipSessionIsLocal) {
        HASipSession haSipSession = null;
        SipSessionDialogImpl sipSession
                = findSipSessionFromCacheOnly(id);
        //SipSession is considered belonging on this instance (isLocal)
        //if its parent sasId isLocal
        cachedSipSessionIsLocal.set(false);
        if (sipSession instanceof HASipSession) {
            haSipSession = (HASipSession) sipSession;
            if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
                    SipReplicationUtil.isLocal(haSipSession.getParentSASId())) {
                cachedSipSessionIsLocal.set(true);
            } else {
                if (!haSipSession.isForegroundLocked()) {
                    processLoadReceivedSipSession(haSipSession.getId());
                }
            }
        }
        return haSipSession;
    }

    /**
     * process the broadcastfindsipsession for SipSession
     * @param queryState
     * @param useUnicast
     */    
    public ReplicationState processFindSipSession(ReplicationState queryState, boolean useUnicast) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processFindSipSession:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processFindSipSession:id=" + queryState.getId());
            _logger.fine("in " + this.getClass().getName() + ">>processFindSipSession:useUnicast=" + useUnicast);
        }
       
        //look in active cache
        AtomicBoolean cachedSipSessionIsLocal = new AtomicBoolean();
        HASipSession haSipSession = (HASipSession)
                findSipSessionAndPassivate((String)queryState.getId(), cachedSipSessionIsLocal);

        //look in replica cache
        ReplicationState replicaState
            = getFromSipSessionReplicationCache((String)queryState.getId());
        //following code checks if cached SipSession isLocal and if so
        //foreground locks it just for the time to generate the query response
        //indicating wasRemoteLocked and then restore the lock to it's previous state
        boolean wasCachedSipSessionForegroundLocked = false;
        if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
                cachedSipSessionIsLocal.get()) {
            wasCachedSipSessionForegroundLocked = haSipSession.isForegroundLocked();
            if(!wasCachedSipSessionForegroundLocked) {
                haSipSession.lockForeground();
            }
        }        
        ReplicationState returnState
            = getBestSipSession(haSipSession, replicaState, queryState, useUnicast);
        if (SipReplicationUtil.isInstanceLoadBalancedByCLB() &&
                cachedSipSessionIsLocal.get()) {
            if(!wasCachedSipSessionForegroundLocked) {
                haSipSession.unlockForeground();
            }
        }       
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processFindSipSession:returnState=" + returnState);
        }
        return returnState;
    }   

    /**
     * process the broadcastfindsipsession for SipSession
     * @param queryState
     */    
    public ReplicationState processBroadcastfindsipsession(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsipsession:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsipsession:id=" + queryState.getId());                       
        }
        return processFindSipSession(queryState, false);
    }

    /**
     * process the load of a SipSession
     * @param queryState - contains the load command
     */
    public ReplicationState processLoadsipsession(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processLoadsipsesson:queryState = " + queryState);
            _logger.fine("in " + this.getClass().getName() + ">>processLoadsipsession:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processLoadsipsession:id=" + queryState.getId());
        }
        return processFindSipSession(queryState, true);
    }
   
    public void processBroadcastloadreceivedsipsession(ReplicationState queryState) {
        //load is acknowledged safe to remove replica now
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processbroadcastloadreceivedsipsession:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processbroadcastloadreceivedsipsession:id=" + queryState.getId());                       
        }
        if(queryState == null || queryState.getId() == null) {
            return;
        }
        String id = (String)queryState.getId();
  processLoadReceivedSipSession(id);
        String ignoreInstance = (String) queryState.getProperty(ReplicationState.IGNORE_REMOVE_INSTANCE_NAME);
        //only safe to remove replica if we are not the replica partner
        //now determined by passed property
        if(ignoreInstance != null && !ignoreInstance.equals(getInstanceName())) {
            ReplicationState removed =
                removeFromSipSessionReplicationCache(id);
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("in " + this.getClass().getName() +
                    ">>processbroadcastloadreceivedsipsession: Removed replica=" +
                    removed);
            }
        }
    }

    public void processLoadReceivedSipSession(String id) {
        //remove active sip session if present and is not locked
        SipSessionDialogImpl sipSession = findSipSessionFromCacheOnly(id);
        if(sipSession != null
                && !sipSession.isForegroundLocked()) {
            sipSession.passivate();
        }
    }
   
    /**
     * find the best version of SipSession
     * removing any stale versions and return query result
     * @param activeSipSession SipSession from active cache
     * @param replicaSipSession replica SipSession from replica cache
     * @param queryState version requested in query (-1 means
     *      version unaware
     * @param useUnicast
     */    
    private ReplicationState getBestSipSession(HASipSession activeSipSession,
        ReplicationState replicaSipSession, ReplicationState queryState, boolean useUnicast) {
        ReplicationState bestResult = null;
        long queryVersion = queryState.getVersion();
       
        //first check for none found in either active or replica caches
        if(replicaSipSession == null && activeSipSession == null) {
            //return nack
            if(useUnicast) {
                return ReplicationState.createUnicastQueryResponseFrom(queryState, true);
            } else {
                return ReplicationState.createQueryResponseFrom(queryState, true);
            }
        }
       
        //next check for artifacts found in both active and replica caches
        if(replicaSipSession != null && activeSipSession != null) {
            //compare and remove the lesser version
            //keeping the higher version as (tentative) best
            if(replicaSipSession.getVersion() <= activeSipSession.getVersion()) {
                //remove stale replica - work with active
                removeFromSipSessionReplicationCache((String)replicaSipSession.getId());
                //create appropriate response from active
                bestResult
                    = createSipSessionResponseFrom(activeSipSession, queryState, useUnicast);
            } else {
                //remove stale active - work with replica
                this.clearFromSipSessionManagerCache(activeSipSession.getId());               
                //create appropriate response from replica
                bestResult
                    = createSipSessionResponseFrom(replicaSipSession, queryState, useUnicast);
            }
        } else {
            //either replica or active is null and other is non-null
            //replica is null and active is not null
            if(replicaSipSession == null) {               
                //create appropriate response from active
                bestResult
                    = createSipSessionResponseFrom(activeSipSession, queryState, useUnicast);
            } else {
                //active is null & replica is not null
                //create appropriate response from replica
                bestResult
                    = createSipSessionResponseFrom(replicaSipSession, queryState, useUnicast);
            }
        }
        return bestResult;
    }
   
    private ReplicationState createSipSessionResponseFrom(ReplicationState replicaSipSession,
            ReplicationState queryState, boolean useUnicast) {
        //create appropriate response from replica
        ReplicationState result = null;
        long queryVersion = queryState.getVersion();       
        if(queryVersion != -1 && replicaSipSession.getVersion() < queryVersion) {
            //return nack & clear stale replica
            removeFromSipSessionReplicationCache((String)replicaSipSession.getId());
            if(useUnicast) {
                result = ReplicationState.createUnicastQueryResponseFrom(queryState, true);
            } else {
                result = ReplicationState.createQueryResponseFrom(queryState, true);
            }
        } else {
            //return real response based on replica
            if(useUnicast) {
                result = ReplicationState.createUnicastQueryResponseFrom(replicaSipSession, queryState.getCommand());
            } else {
                result = ReplicationState.createQueryResponseFrom(replicaSipSession);
            }
        }               
        return result;
    }

    private ReplicationState createSipSessionResponseFrom(HASipSession activeSipSession,
            ReplicationState queryState, boolean useUnicast) {
        //create appropriate response from active
        ReplicationState result = null;
        long queryVersion = queryState.getVersion();       
        if(queryVersion != -1 && activeSipSession.getVersion() < queryVersion) {
            //return nack & clear stale active
            clearFromSipSessionManagerCache(activeSipSession.getId());
            if(useUnicast) {
                result = ReplicationState.createUnicastQueryResponseFrom(queryState, true);
            } else {
                result = ReplicationState.createQueryResponseFrom(queryState, true);
            }
        } else {
            //return real response based on active SipSession
            try {
                result = createQueryResponseFrom(activeSipSession, useUnicast);
            } catch (IOException ioe) {
                _logger.log(Level.WARNING,
                    "Failed load: Unable to serialize " + activeSipSession,
                    ioe);
                // We've been unable to serialize the given active SipSession.
                // Clear it from the active cache and return a nack instead
                clearFromSipSessionManagerCache(activeSipSession.getId());
                if(useUnicast) {
                    result = ReplicationState.createUnicastQueryResponseFrom(queryState, true);
                } else {
                    result = ReplicationState.createQueryResponseFrom(queryState, true);
                }
            }
        }
        return result;
    }
   
    /**
     * Converts the given SipSession to a ReplicationState.
     *
     * @param ss The SipSession to be converted
     *
     * @return The ReplicationState corresponding to the given SipSession
     */
    private ReplicationState createQueryResponseFrom(HASipSession ss, boolean useUnicast)
            throws IOException {
        byte[] containerExtraParamState = null;
        SipSessionExtraParams containerExtraParams
            = ss.getExtraParameters();
        if(containerExtraParams != null) {
            try {
                containerExtraParamState
                    = ReplicationUtil.getByteArray(containerExtraParams, isReplicationCompressionEnabled());
            } catch (IOException ex) {
                ; //deliberate no-op
            }
        }       
        if(!useUnicast) {
            return new ReplicationState(
                    MODE_SIP,
                    ss.getId(),
                    getApplicationId(),
                    ss.getVersion(),
                    0L,
                    0L,
                    null,
                    null,
                    null,
                    ReplicationState.RETURN_BROADCAST_MSG_COMMAND,
                    ReplicationUtil.getByteArray(ss, isReplicationCompressionEnabled()),
                    null,
                    containerExtraParamState);
        } else {
            return new ReplicationState(
                    MODE_SIP,
                    ss.getId(),
                    getApplicationId(),
                    ss.getVersion(),
                    0L,
                    0L,
                    LOAD_SIP_SESSION_COMMAND, //put original command in extraParam slot
                    null,
                    null,
                    ReplicationState.RETURN_UNICAST_MSG_COMMAND,
                    ReplicationUtil.getByteArray(ss, isReplicationCompressionEnabled()),
                    null,
                    containerExtraParamState);
        }
    }

    private static final String TEMP_MONITOR_KEY_PREFIX = "temp-diagfrag-ss-sas:";

    private String getSipSessionMonitorId(String id) {
        String monitorId = id;
        if (SASLockStatus.isSASLocked()) {
            monitorId = id;
        } else if (appContainsHttpServlets) {
            //Note that sas is not locked here
            monitorId = TEMP_MONITOR_KEY_PREFIX + id;
        } else {
            SASLockStatus.resetSASLockedToDefaultValue();
        }

        return monitorId;
    }

    public SipSessionDialogImpl findSipSession(String id,
                                               boolean loadDependencies)
            throws RemoteLockException {
        String monitorId = getSipSessionMonitorId(id);
        Object monitor = getReplicationSessionMonitor(monitorId);
        synchronized (monitor) {
            return super.findSipSession(id, loadDependencies);
        }
    }

    /**
     * Gets the SipApplicationSession with the given id
     * from the active cache only
     *
     * @return The SipSession with the given id, or null if not
     * found
     */
    public SipSessionDialogImpl findSipSessionFromCacheOnly(String id) {
        if (id == null)
            return (null);
        Object monitor = getReplicationSessionMonitor(id);
        synchronized(monitor) {
            HASipSession result
                = (HASipSession)super.findSipSessionFromCacheOnly(id);
            if(!this.isActiveCacheReconciliationOngoing()) {
                return result;
            } else {
                if(result == null || !result.isSuspect()) {
                    //if null just return it
                    //if not suspect it has already been checked
                    return result;
                }
                if(RollingUpgradeUtil.canUseSuspectSession(result,
                        sipSessionExpatIdsMap, sipSessionExpatReadWriteLock)) {
                    //if it passes the check return it
                    return result;
                } else {
                    removeSipSessionFromCache(result);
                    return null;
                }
            }
        }
    }
   
    protected void clearFromSipSessionManagerCache(String id) {
        SipSessionDialogImpl sess
            = super.findSipSessionFromCacheOnly(id);
        if(sess != null) {                              
            this.removeSipSessionFromCache(sess);
        }
    }   
   
    //ServletTimer process methods
   
    /**
     * process the save of a Servlet Timer
     * @param timerState - contains the save command
     */    
    public void processSaveservlettimer(ReplicationState timerState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() + ">>processSaveservlettimer");
        }       
        this.putInServletTimerReplicationCache(timerState);
    }

    private ReplicationState doUnicastLoadTest(HAServletTimer st) {
        //start unicast load test
        ReplicationState resultState = null;
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        String partnerInstanceName
            = healthChecker.getReshapeReplicateToInstanceName(null, 3000L);
        ServletTimerStoreImpl stStore = this.getSingletonServletTimerStore();
        try {
            resultState = stStore.sendUnicastLoadQuery((String)st.getId(), "" + st.getVersion(), partnerInstanceName);
        } catch (Throwable th) {
            _logger.log(Level.INFO, "error during unicast load test to " + partnerInstanceName, th);
        }
        return resultState;
        //end unicast load test
    }

    private void processBulkRemoveServletTimer(ReplicationState replicationState) {
        servletTimerReplicaCache.removeFromReplicationCache(
                replicationState.getState());
    }
    /**
     * process the removal of a Servlet Timer
     * @param timerState - contains the remove command
     */    
    public void processRemoveservlettimer(ReplicationState timerState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() + ">>processRemoveservlettimer");
        }
        if(timerState == null) {
            return;
        }
        if (timerState.getState() != null) {
            processBulkRemoveServletTimer(timerState);
            return;
        }

        String id = (String)timerState.getId();
        activationHelper.unregisterServletTimerMigrationTask(id);
        //keep track of recent removals
        servletTimerReplicaCache.removeFromReplicationCache(id);
        //do the cyclical remove if not fronted by CLB
        if (!SipReplicationUtil.isInstanceLoadBalancedByCLB()) {
            int cycleCount = 0;
            String cycleCountString = timerState.getExtraParam();
            if(cycleCountString != null) {
                try {
                    cycleCount = Integer.parseInt(cycleCountString);
                } catch (Exception ex) {
                    //ignore
                }
            }
            cycleRemoveServletTimer(id, timerState.getInstanceName(), (cycleCount + 1));
        }
    }
   
    /**
     * process the update of a Servlet Timer
     * @param timerState - contains the updatelastaccesstime command
     */   
    public void processUpdatelastaccesstimeservlettimer(ReplicationState timerState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() +
                ">>processUpdatelastaccesstimeservlettimer:id: " +
                timerState.getId() + ", version: " +
                timerState.getVersion());
        }
        servletTimerReplicaCache.processUpdatelastaccesstime(timerState);
    }
   
    public ReplicableEntity findServletTimerAndPassivate(String id,
                                                         AtomicBoolean cachedSTIsLocal) {
        HAServletTimer haServletTimer = null;
        ServletTimerImpl servletTimer
                = findServletTimerFromCacheOnly(id);
        if (servletTimer instanceof HAServletTimer) {
            haServletTimer = (HAServletTimer) servletTimer;
            if (haServletTimer != null && !haServletTimer.isForegroundLocked()) {
                processLoadReceivedServletTimer(haServletTimer.getId());
            }
        }
        // TODO :: set cachedSTIsLocal value appropriately.
        return haServletTimer;
    }

    /**
     * process the FindServletTimer for ServletTimer
     * @param queryState
     * @param useUnicast
     */    
    public ReplicationState processFindServletTimer(ReplicationState queryState, boolean useUnicast) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processFindServletTimer:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processFindServletTimer:id=" + queryState.getId());
            _logger.fine("in " + this.getClass().getName() + ">>processFindServletTimer:version=" + queryState.getVersion());
        }
       
        //look in active cache
        AtomicBoolean cachedSTIsLocal = new AtomicBoolean();
        HAServletTimer haServletTimer = (HAServletTimer)
                findServletTimerAndPassivate((String)queryState.getId(), cachedSTIsLocal);
       
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processFindServletTimer:cachedTimer: " + haServletTimer);                       
        }       

        // TODO :: why is cachedSTIsLocal not used? It is used for both SAS and SS.
        //look in replica cache
        ReplicationState replicaState
            = getFromServletTimerReplicationCache((String)queryState.getId());
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processFindServletTimer:replicaState: " + replicaState);                       
        }       
        ReplicationState returnState
            = getBestServletTimer(haServletTimer, replicaState, queryState, useUnicast);         
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processFindServletTimer:returnState=" + returnState);
        }
        return returnState;
    }   
   
    /**
     * process the broadcastfindservlettimer for ServletTimer
     * @param queryState
     */    
    public ReplicationState processBroadcastfindservlettimer(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindservlettimer:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindservlettimer:id=" + queryState.getId());
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindservlettimer:version=" + queryState.getVersion());
        }
        return processFindServletTimer(queryState, false);
    }

    /**
     * process the load of a ServletTimer
     * @param queryState - contains the load command
     */
    public ReplicationState processLoadservlettimer(ReplicationState queryState) {
        //complete query and send back response
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processLoadservlettimer:queryState = " + queryState);
            _logger.fine("in " + this.getClass().getName() + ">>processLoadservlettimer:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processLoadservlettimer:id=" + queryState.getId());
            _logger.fine("in " + this.getClass().getName() + ">>processLoadservlettimer:version=" + queryState.getVersion());
        }
        return processFindServletTimer(queryState, true);
    }
   
    public void processBroadcastloadreceivedservlettimer(ReplicationState queryState) {
        //load is acknowledged safe to remove replica now
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processbroadcastloadreceivedservlettimer:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processbroadcastloadreceivedservlettimer:id=" + queryState.getId());                       
        }
        if(queryState == null || queryState.getId() == null) {
            return;
        }
        String id = (String)queryState.getId();
  processLoadReceivedServletTimer(id);
        String ignoreInstance = (String) queryState.getProperty(ReplicationState.IGNORE_REMOVE_INSTANCE_NAME);
        //only safe to remove replica if we are not the replica partner
        //now determined by passed property
        if(ignoreInstance != null && !ignoreInstance.equals(getInstanceName())) {
            ReplicationState removed =
                removeFromServletTimerReplicationCache(id);
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("in " + this.getClass().getName() +
                    ">>processBroadcastloadreceivedservlettimer: Removed replica=" +
                    removed);
            }
        }
    }

    public void processLoadReceivedServletTimer(String id) {
        //  call unregisterServletTimerExtraParam()
        activationHelper.unregisterServletTimerMigrationTask(id);
        //remove active timer if present and not locked
        ServletTimerImpl timer = findServletTimerFromCacheOnly(id);
        if(timer != null && !timer.isForegroundLocked()) {       
            timer.passivate();
        }
    }
   
    /**
     * process the loadAdvisory of a Servlet Timer
     * this should trigger a load call for the ServletTimer
     * @param extraParams
     */    
    public void processLoadadvisoryservlettimer(ServletTimerExtraParams extraParams) {
        if(extraParams == null) {
            return;
        }       
        processLoadadvisoryservlettimer(extraParams.getId(), null);
        //Note: processBroadcastloadreceivedservlettimer will eventually
        //  call unregisterServletTimerExtraParam()       
    }

    public void processLoadadvisoryservlettimer(ReplicationState timerState) {
        if(timerState == null) {
            return;
        }       
        processLoadadvisoryservlettimer((String)timerState.getId(), timerState.getInstanceName());
    }
   
    public void processLoadadvisoryservlettimer(String id, String fromInstanceName) {
        this.processLoadadvisoryservlettimer(id, false, fromInstanceName);
    }
   
    public void processLoadadvisoryservlettimer(String id, boolean calledFromSelf, String fromInstanceName) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN" + this.getClass().getName() + ">>processLoadadvisoryservlettimer");
        }
        if(id == null) {
            return;
        }
        //try to load from local cache first
        ServletTimerImpl activeTimer = this.findServletTimerFromCacheOnly(id);
        if(activeTimer != null) {
            //if calledFromSelf we suppress the load received acknowledgement
            if(!calledFromSelf) {
                //if we already have an active timer - just short-circuit by calling
                //load received
                HAServletTimer haTimer = (HAServletTimer)activeTimer;
                String beKey = null;
                if(haTimer.getParentSASId() != null) {
                    beKey = SipApplicationSessionUtil.getSipApplicationKey(haTimer.getParentSASId());
    }
    if (fromInstanceName == null) {
                    ReplicationState loadReceivedState =
                        ReplicationState.createBroadcastLoadReceivedState(MODE_SIP, id, this.getApplicationId(), haTimer.getVersion(), instanceName, MESSAGE_BROADCAST_LOAD_RECEIVED_SERVLET_TIMER);
                    this.sendLoadAcknowledgement(loadReceivedState, beKey);
        _logger.log(Level.INFO, "Unexpected send of broadcast loadack in servlet timer load advisory");
    }
    else {
        sendUnicastLoadAcknowledgementST(id, fromInstanceName, beKey);
    }
            }
        } else {
            //load and activate ServletTimer
            try {
                swapInServletTimer(id, true);
            } catch (Exception ex) {
                _logger.log(Level.WARNING, "st_unable_to_load_in_response_to_loadadvisory", id);
                _logger.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
   
    /**
     * find the best version of ServletTimer
     * removing any stale versions and return query result
     * @param activeServletTimer ServletTimer
     *      from active cache
     * @param replicaServletTimer ServletTimer replica
     *      from replica cache
     * @param queryState version requested in query (-1 means
     *      version unaware
     * @param useUnicast
     */    
    private ReplicationState getBestServletTimer(HAServletTimer activeServletTimer,
        ReplicationState replicaServletTimer, ReplicationState queryState, boolean useUnicast) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>getBestServletTimer:activeServletTimer: " + activeServletTimer);
            _logger.fine("in " + this.getClass().getName() + ">>getBestServletTimer:replicaServletTimer: " + replicaServletTimer);
            _logger.fine("in " + this.getClass().getName() + ">>getBestServletTimer:queryState=" + queryState);
        }       
        ReplicationState bestResult = null;
        long queryVersion = queryState.getVersion();
       
        //first check for none found in either active or replica caches
        if(replicaServletTimer == null && activeServletTimer == null) {
            //return nack
            if(useUnicast) {
                return ReplicationState.createUnicastQueryResponseFrom(queryState, true);
            } else {
                return ReplicationState.createQueryResponseFrom(queryState, true);
            }
        }
       
        //next check for artifacts found in both active and replica caches
        if(replicaServletTimer != null && activeServletTimer != null) {
            //compare and remove the lesser version
            //keeping the higher version as (tentative) best
            if(replicaServletTimer.getVersion() <= activeServletTimer.getVersion()) {
                //remove stale replica - work with active
                removeFromServletTimerReplicationCache((String)replicaServletTimer.getId());
                //create appropriate response from active
                bestResult
                    = createServletTimerResponseFrom(activeServletTimer, queryState, useUnicast);
                if (activeServletTimer.isForegroundLocked()) {
                    bestResult.setVersion(Integer.MAX_VALUE);
                }               
            } else {
                //remove stale active - work with replica
                clearFromServletTimerManagerCache(activeServletTimer.getId());              
                //create appropriate response from replica
                bestResult
                    = createServletTimerResponseFrom(replicaServletTimer, queryState, useUnicast);
            }
        } else {
            //either replica or active is null and other is non-null
            //replica is null and active is not null
            if(replicaServletTimer == null) {               
                //create appropriate response from active
                bestResult
                    = createServletTimerResponseFrom(activeServletTimer, queryState, useUnicast);
                if (activeServletTimer.isForegroundLocked()) {
                    bestResult.setVersion(Integer.MAX_VALUE);
                }                
            } else {
                //active is null & replica is not null
                //create appropriate response from replica
                bestResult
                    = createServletTimerResponseFrom(replicaServletTimer, queryState, useUnicast);
            }
        }
        return bestResult;
    }
   
    private ReplicationState createServletTimerResponseFrom(ReplicationState replicaServletTimer,
            ReplicationState queryState, boolean useUnicast) {
        //create appropriate response from replica
        ReplicationState result = null;
        long queryVersion = queryState.getVersion();       
        if(queryVersion != -1 && replicaServletTimer.getVersion() < queryVersion) {
            //return nack & clear stale replica
            removeFromServletTimerReplicationCache((String)replicaServletTimer.getId());
            if(useUnicast) {
                result = ReplicationState.createUnicastQueryResponseFrom(queryState, true);
            } else {
                result = ReplicationState.createQueryResponseFrom(queryState, true);
            }
        } else {
            //return real response based on replica
            if(useUnicast) {
                result = ReplicationState.createUnicastQueryResponseFrom(replicaServletTimer, queryState.getCommand());
            } else {
                result = ReplicationState.createQueryResponseFrom(replicaServletTimer);
            }
        }
        return result;
    }

    private ReplicationState createServletTimerResponseFrom(HAServletTimer activeServletTimer,
            ReplicationState queryState, boolean useUnicast) {
        //create appropriate response from active
        ReplicationState result = null;
        long queryVersion = queryState.getVersion();       
        if(queryVersion != -1 && activeServletTimer.getVersion() < queryVersion) {
            //return nack & clear stale active
            clearFromServletTimerManagerCache(activeServletTimer.getId());
            if(useUnicast) {
                result = ReplicationState.createUnicastQueryResponseFrom(queryState, true);
            } else {
                result = ReplicationState.createQueryResponseFrom(queryState, true);
            }
        } else {
            //return real response based on active ServletTimer
            try {
                result = createQueryResponseFrom(activeServletTimer, useUnicast);
            } catch (IOException ioe) {
                _logger.log(Level.WARNING,
                    "Failed load: Unable to serialize " + activeServletTimer,
                    ioe);
                // We've been unable to serialize the given active
                // ServletTimer.
                // Clear it from the active cache and return a nack instead
                clearFromServletTimerManagerCache(activeServletTimer.getId());
                result = ReplicationState.createQueryResponseFrom(queryState,
                                                                  true);
            }
        }
        return result;
    }
   
    /**
     * Converts the given ServletTimer to a ReplicationState.
     *
     * @param timer The ServletTimer to be converted
     *
     * @return The ReplicationState corresponding to the given ServletTimer
     */
    private ReplicationState createQueryResponseFrom(
            HAServletTimer timer, boolean useUnicast) throws IOException {
        byte[] containerExtraParamState = null;
        ServletTimerExtraParams containerExtraParams
            = timer.getExtraParameters();
        if(containerExtraParams != null) {
            try {
                containerExtraParamState
                    = ReplicationUtil.getByteArray(containerExtraParams, isReplicationCompressionEnabled());
            } catch (IOException ex) {
                ; //deliberate no-op
            }
        }
        if(!useUnicast) {
            return new ReplicationState(
                    MODE_SIP,
                    timer.getId(),
                    getApplicationId(),
                    timer.getVersion(),
                    0L,
                    0L,
                    null,
                    null,
                    null,
                    ReplicationState.RETURN_BROADCAST_MSG_COMMAND,
                    ReplicationUtil.getByteArray(timer, isReplicationCompressionEnabled()),
                    null,
                    containerExtraParamState);
        } else {
            return new ReplicationState(
                    MODE_SIP,
                    timer.getId(),
                    getApplicationId(),
                    timer.getVersion(),
                    0L,
                    0L,
                    LOAD_SERVLET_TIMER_COMMAND, //put original command in extraParam slot
                    null,
                    null,
                    ReplicationState.RETURN_UNICAST_MSG_COMMAND,
                    ReplicationUtil.getByteArray(timer, isReplicationCompressionEnabled()),
                    null,
                    containerExtraParamState);
       
    }
   
    /**
     * Gets the ServletTimer with the given id
     * from the active cache only
     *
     * @return The ServletTimer with the given id, or null if not
     * found
     */
    public ServletTimerImpl findServletTimerFromCacheOnly(String id) {
        if (id == null)
            return (null);
        Object monitor = getReplicationSessionMonitor(id);
        synchronized(monitor) {
            ServletTimerImpl st = super.findServletTimerFromCacheOnly(id);
            if (st != null && !st.isPersistent()) {
                return st;
            }
            HAServletTimer result = (HAServletTimer)st;
            if(!this.isActiveCacheReconciliationOngoing()) {
                return result;
            } else {
                if(result == null || !result.isSuspect()) {
                    //if null just return it
                    //if not suspect it has already been checked
                    return result;
                }
                if(RollingUpgradeUtil.canUseSuspectSession(result,
                        servletTimerExpatIdsMap, servletTimerExpatReadWriteLock)) {
                    //if it passes the check return it
                    return result;
                } else {
                    removeServletTimerFromCache(result);
                    return null;
                }
            }
        }
    }
   
    protected void clearFromServletTimerManagerCache(String id) {
        ServletTimerImpl timer
            = super.findServletTimerFromCacheOnly(id);
        if(timer != null) {                              
            this.removeServletTimerFromCache(timer);
        }
    }
   
    public void purge(String owningInstanceName, long purgeStartTime) {
        //do not purge if we are the replica partner
        //of the owning instance
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        String replicatedFromInstanceName
            = healthChecker.getReshapeReplicateFromInstanceName();
        if(replicatedFromInstanceName != null && replicatedFromInstanceName.equalsIgnoreCase(owningInstanceName)) {           
            return;          
        }       
        purgeSipApplicationSessionsForOwningInstance(owningInstanceName);
        purgeSipSessionsForOwningInstance(owningInstanceName);
        purgeServletTimersForOwningInstance(owningInstanceName);
    }
   
    void purgeSipApplicationSessionsForOwningInstance(String owningInstanceName) {
        List idsToRemove = new ArrayList();
        BaseCache replicatedSipApplicationSessionsCache = getReplicatedSipApplicationSessions();
        Iterator it = replicatedSipApplicationSessionsCache.values();
        while(it.hasNext()) {
            ReplicationState nextState
                = (ReplicationState)it.next();
            SipApplicationSessionExtraParams extraParams =
                SipApplicationSessionExtraParams.getDeserializedExtraParams(
                    nextState, isReplicationCompressionEnabled());
            if(extraParams != null) {
                String nextOwningInstance = extraParams.getCurrentOwnerInstanceName();
                if(nextOwningInstance != null
                    && nextOwningInstance.equalsIgnoreCase(owningInstanceName)) {
                    idsToRemove.add((String)nextState.getId());
                }
            }
        }
        for(int i=0; i< idsToRemove.size(); i++) {
            removeFromSipApplicationSessionReplicationCache((String)idsToRemove.get(i));
        }
    }

/*
    HashSet<ExpatListElement> getSASExpatIds(
            String requestingInstance, boolean consultActiveCache) {
//        List expatIds = new ArrayList();
        //using set to avoid dups
        HashSet expatIds = new HashSet();
        BaseCache replicatedSipApplicationSessionsCache = getReplicatedSipApplicationSessions();
        Iterator it = replicatedSipApplicationSessionsCache.values();
        long version = -1L;
        while (it.hasNext()) {
            ReplicationState state = (ReplicationState) it.next();
            String sasId = (String) state.getId();
            String rightfulOwner = SipApplicationSessionUtil.
                    getActualServerInstance(sasId);
            if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                version = state.getVersion();
                expatIds.add(new ExpatListElement(sasId, version, instanceName));
            }
        }
        if (consultActiveCache) {
            try {
                //iterate over active sas cache
                Iterator it2 = applicationSessions.values().iterator();
                while (it2.hasNext()) {
                    HASipApplicationSession sas = (HASipApplicationSession) it2.next();
                    String sasId = (String) sas.getId();
                    String rightfulOwner = SipApplicationSessionUtil.
                            getActualServerInstance(sasId);
                    if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                        version = sas.getVersion();
                        expatIds.add(new ExpatListElement(sasId, version,
                                instanceName, true));
                    }
                }
            } catch (NoSuchFieldError e) {
                ;
            }
        }
        return expatIds;
    }
*/

    /**
     * Get the SAS' expat list from the active cache for a given instance.
     */
    HashSet<ExpatListElement> getSASExpatIdsFromActive(String requestingInstance) {
        HashSet expatIds = new HashSet();
        long version = -1L;
        try {
            //iterate over active sas cache
            Iterator it2 = applicationSessions.values().iterator();
            while (it2.hasNext()) {
                HASipApplicationSession sas = (HASipApplicationSession) it2.next();
                String sasId = (String) sas.getId();
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstance(sasId);
                if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                    version = sas.getVersion();
                    expatIds.add(new ExpatListElement(sasId, version,
                            instanceName, true));
                }
            }
        } catch (NoSuchFieldError e) {
            ;
        }
        return expatIds;
    }

    /**
     * Get the SAS' expat list from the replica cache for a given instance.
     */
    HashSet<ExpatListElement> getSASExpatIdsFromReplica(String requestingInstance) {
        HashSet expatIds = new HashSet();
        BaseCache replicatedSipApplicationSessionsCache = getReplicatedSipApplicationSessions();
        Iterator it = replicatedSipApplicationSessionsCache.values();
        long version = -1L;
        while (it.hasNext()) {
            ReplicationState state = (ReplicationState) it.next();
            String sasId = (String) state.getId();
            String rightfulOwner = SipApplicationSessionUtil.
                    getActualServerInstance(sasId);
            if (requestingInstance.equalsIgnoreCase(rightfulOwner)) {
                version = state.getVersion();
                expatIds.add(new ExpatListElement(sasId, version, instanceName));
            }
        }
        return expatIds;
    }

    /**
     * Get the SAS' expat list from the active cache for all the surviving instances.
     */
    private void getSASExpatIdsFromActive(ExpatListQueryResults results) {
        long version = -1L;
        //iterate over active sas cache
        Iterator it2 = applicationSessions.values().iterator();
        while (it2.hasNext()) {
            HASipApplicationSession sas = (HASipApplicationSession) it2.next();
            String sasId = (String) sas.getId();
            if (sasId != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstance(sasId);
                if (rightfulOwner != null
                        && !rightfulOwner.equalsIgnoreCase(instanceName)) {
                    version = sas.getVersion();
                    ExpatListElement expatElement = new ExpatListElement(sasId,
                            version, instanceName, true);
                    results.addQueryResultFor(rightfulOwner, expatElement);
                }
            }
        }
    }

    /**
     * Get the SAS' expat list from the replica cache for all the surviving instances.
     */
    private void getSASExpatIdsFromReplica(ExpatListQueryResults results) {
        //iterate over sip application session replicas
        BaseCache replicatedSipApplicationSessionsCache = getReplicatedSipApplicationSessions();
        Iterator it = replicatedSipApplicationSessionsCache.values();
        long version = -1L;
        while (it.hasNext()) {
            ReplicationState state = (ReplicationState) it.next();
            String sasId = (String) state.getId();
            if (sasId != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstance(sasId);
                version = state.getVersion();
                ExpatListElement expatElement = new ExpatListElement(sasId,
                        version, instanceName);
                results.addQueryResultFor(rightfulOwner, expatElement);
            }
        }
    }

/*
    private void getAllSASExpatIds(ExpatListQueryResults results) {
        //iterate over sip application session replicas
        BaseCache replicatedSipApplicationSessionsCache = getReplicatedSipApplicationSessions();
        Iterator it = replicatedSipApplicationSessionsCache.values();
        long version = -1L;
        while (it.hasNext()) {
            ReplicationState state = (ReplicationState) it.next();
            String sasId = (String) state.getId();
            if (sasId != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstance(sasId);
                version = state.getVersion();
                ExpatListElement expatElement = new ExpatListElement(sasId,
                        version, instanceName);
                results.addQueryResultFor(rightfulOwner, expatElement);
            }
        }
        //iterate over active sas cache
        Iterator it2 = applicationSessions.values().iterator();
        while (it2.hasNext()) {
            HASipApplicationSession sas = (HASipApplicationSession) it2.next();
            String sasId = (String) sas.getId();
            if (sasId != null) {
                String rightfulOwner = SipApplicationSessionUtil.
                        getActualServerInstance(sasId);
                if (rightfulOwner != null
                        && !rightfulOwner.equalsIgnoreCase(instanceName)) {
                    version = sas.getVersion();
                    ExpatListElement expatElement = new ExpatListElement(sasId,
                            version, instanceName, true);
                    results.addQueryResultFor(rightfulOwner, expatElement);
                }
            }
        }
    }
*/

/*
    List getSipApplicationSessionExpatIdsThirdPartySPI(String owningInstanceName) {
        BackingStore sipApplicationSessionBackingStore
            = this.getSipApplicationSessionBackingStore();
        SipApplicationSessionExtraParams sasExtraParamCriteria
            = SipApplicationSessionExtraParams.createSearchCriteria(
                getApplicationId(), owningInstanceName);       
        Collection<SipApplicationSessionExtraParams> sasColl
            = sipApplicationSessionBackingStore.findByCriteria(sasExtraParamCriteria);

        List expatIds = new ArrayList();
        //using set to avoid dups
        HashSet expatIdsSet = new HashSet();       
        Iterator<SipApplicationSessionExtraParams> sasResults =
            (Iterator<SipApplicationSessionExtraParams>) sasColl.iterator();
        while (sasResults.hasNext()) {
            SipApplicationSessionExtraParams eParam = sasResults.next();
            if (owningInstanceName.equals(eParam.getCurrentOwnerInstanceName())) {
                expatIdsSet.add(new ExpatListElement((String)eParam.getId(), -1L, null));
            }           
        }
        //iterate over active sas cache
        long nextVersion = -1L;
        Iterator it2 = applicationSessions.values().iterator();
        while(it2.hasNext()) {
            HASipApplicationSession nextSipApplicationSession
                = (HASipApplicationSession)it2.next();
            String nextSipApplicationSessionId
                = (String)nextSipApplicationSession.getId();
            String nextRightfulOwnerInstanceName
                = SipApplicationSessionUtil.getActualServerInstance(nextSipApplicationSessionId);
            if(nextRightfulOwnerInstanceName != null
                && nextRightfulOwnerInstanceName.equalsIgnoreCase(owningInstanceName)) {
                nextVersion = nextSipApplicationSession.getVersion();
                expatIdsSet.add(new ExpatListElement(nextSipApplicationSessionId, nextVersion, getInstanceName()));
            }
        }       
        expatIds.addAll(expatIdsSet);       
        return expatIds;
    }   
*/

    void purgeSipSessionsForOwningInstance(String owningInstanceName) {
        List idsToRemove = new ArrayList();
        BaseCache replicatedSipSessionsCache = getReplicatedSipSessions();
        Iterator it = replicatedSipSessionsCache.values();
        while(it.hasNext()) {
            ReplicationState nextState
                = (ReplicationState)it.next();
            SipSessionExtraParams extraParams =
                SipSessionExtraParams.getDeserializedExtraParams(
                    nextState, isReplicationCompressionEnabled());
            if(extraParams != null) {
                String nextOwningInstance = extraParams.getCurrentOwnerInstanceName();
                if(nextOwningInstance != null
                    && nextOwningInstance.equalsIgnoreCase(owningInstanceName)) {
                    idsToRemove.add((String)nextState.getId());
                }
            }
        }
        for(int i=0; i< idsToRemove.size(); i++) {
            removeFromSipSessionReplicationCache((String)idsToRemove.get(i));
        }
    }
   
    void purgeServletTimersForOwningInstance(String owningInstanceName) {       
        List idsToRemove = new ArrayList();
        BaseCache replicatedServletTimersCache = getReplicatedServletTimers();
        Iterator it = replicatedServletTimersCache.values();
        while(it.hasNext()) {
            ReplicationState nextState
                = (ReplicationState)it.next();
            ServletTimerExtraParams extraParams =
                ServletTimerExtraParams.getDeserializedExtraParams(
                    nextState, isReplicationCompressionEnabled());
            if(extraParams != null) {
                String nextOwningInstance = extraParams.getCurrentOwnerInstanceName();
                if(nextOwningInstance != null
                    && nextOwningInstance.equalsIgnoreCase(owningInstanceName)) {
                    idsToRemove.add((String)nextState.getId());
                }
            }
        }
        for(int i=0; i< idsToRemove.size(); i++) {
            removeFromServletTimerReplicationCache((String)idsToRemove.get(i));
        }
    }   
   
    //end receiver side process methods
   
    //start expiration related methods
   
    private long deltaMillis = -1L;

    /**
     * a delta adjustment applied to the calculated wiggle adjustment
     * this is to insure that SipSessions and DialogFragments are
     * not prematurely purged by the reaper thread before an active
     * SAS has possibly extended their expiration times
     */   
    protected long getDeltaMillis() {
        if(deltaMillis == -1L) {
            long reapIntervalSeconds
                = this.getContext().getBackgroundProcessorDelay();
            deltaMillis = Math.max(ActivationHelper.DELAYED_EXPIRATION,
                    (reapIntervalSeconds * 1000 * 2));
        }
        return deltaMillis;
    }
   
//    void processExpiredSipApplicationSessionReplicas() {
//        //code assumes that isExpired works for this type of ReplicationState
//        if(_logger.isLoggable(Level.FINE)) {
//            _logger.fine("in " + this.getClass().getName() + ">>processExpiredSipApplicationSessionReplicas");
//        }
//        int expiredReplicas = 0;
//        BaseCache replicatedSipApplicationSessionsCache = getReplicatedSipApplicationSessions();
//        for (Iterator it = replicatedSipApplicationSessionsCache.keys();
//                it.hasNext();) {
//            ReplicationState nextState = (ReplicationState)
//                replicatedSipApplicationSessionsCache.get((String)it.next());
//            if (nextState != null) {
//                if (_logger.isLoggable(Level.FINE)) {
//                    _logger.fine("in " + this.getClass().getName() +
//                        ">>processExpiredSipApplicationSessionReplicas: " +
//                        "nextState=" + nextState);
//                }
//                if (isTimeForSipApplicationSessionLoadAdvisory(nextState)) {
//                    //if(!LoadProcessingGovernor.isSystemUnderLoadStress()
//                    //        && !SipReplicationUtil.isExpatInProgress()) {
//                    if(!ExpatListHandler.isExpatInProgress()) {
//                        expiredReplicas++;
//                        processExpiredSipApplicationSessionReplica(nextState);
//                    }
//                }
//            }
//        }
//        if(_logger.isLoggable(Level.FINE)) {
//            _logger.fine("in " + this.getClass().getName() +
//                ">>processExpiredSipApplicationSessionReplicas: expiredReplicas.size=" +
//                expiredReplicas);
//        }
//    }

/*
    private void processExpiredSipApplicationSessionReplica(
            ReplicationState state) {
        processExpiredSipApplicationSessionReplicaById((String) state.getId(), state.getInstanceName());
    }

    private void processExpiredSipApplicationSessionReplicaById(
                    String nextId, String fromInstanceName) {
        try {
            String rightfulOwnerInstanceName =
                SipReplicationUtil.getCurrentServerInstance(nextId);
            if (rightfulOwnerInstanceName == null) {
                _logger.warning(
                    "in " + this.getClass().getName() +
                    ">>processExpiredSipApplicationSessionReplica: " +
                    "No rightful owner instance returned by " +
                    "DataCentricUtil for SipApplicationSession " +
                    "with id: " + nextId);
                // FIXME Skip this SAS id by removing it from replica cache
                return;
            }

            if(getInstanceName().equals(rightfulOwnerInstanceName)) {
                //short circuit version of load advisory
                processLoadadvisorysas(nextId, true, fromInstanceName);
            } else {
                sendLoadAdvisorySipApplicationSession(
                    nextId, rightfulOwnerInstanceName);
            }
        } catch (Throwable t) {
                _logger.log(Level.WARNING,
                    "in " + this.getClass().getName() +
                    ">>processExpiredSipApplicationSessionReplica: " +
                    "Unable to process expiration of " +
                    "SipApplicationSession replica with id: " +
                    nextId, t);
            // FIXME Skip this SAS id by removing it from replica cache
        }
    }

*/
    private SipApplicationSessionExtraParams getSipApplicationSessionExtraParamsFrom(ReplicationState state) {
        if(state == null) {
            return null;
        }
        if(state.getDeserializedExtraParam() != null) {
            return (SipApplicationSessionExtraParams)state.getDeserializedExtraParam();
        } else {
            //deserialize and cache result in state
            SipApplicationSessionExtraParams extraParams =
                SipApplicationSessionExtraParams.getDeserializedExtraParams(
                    state, isReplicationCompressionEnabled());
            state.setDeserializedExtraParam(extraParams);
            return extraParams;
        }
    }   
   
    protected boolean isTimeForSipApplicationSessionLoadAdvisory(ReplicationState state) {
        SipApplicationSessionExtraParams extraParams
            = getSipApplicationSessionExtraParamsFrom(state);
        return isTimeForSipApplicationSessionLoadAdvisory(extraParams);
    }
   
    protected boolean isTimeForSipApplicationSessionLoadAdvisory(SipApplicationSessionExtraParams extraParams) {       
        if(extraParams == null) {
            return false;
        } else {
            if(extraParams.getExpirationTime() <= 0) {  //infinite case
                long timeSinceLastAccessed
                    = System.currentTimeMillis() - extraParams.getInternalLastAccessedTime();
                return(timeSinceLastAccessed > (ActivationHelper.SAS_TIMER_MAX_THRESHOLD_IN_MILLIS + 1));
            } else {
                return (System.currentTimeMillis() >= extraParams.getWiggledExpirationTime());
            }
        }
    }   
   
//    void processExpiredSipApplicationSessionReplicasThirdPartySPI() {
//        //code assumes that isExpired works for this type of ReplicationState
//        if(_logger.isLoggable(Level.FINE)) {
//            _logger.fine("in " + this.getClass().getName() + ">>processExpiredSipApplicationSessionReplicasThirdPartySPI");
//        }
//        ArrayList expiredReplicas = new ArrayList(30);
//        List sasExtraParams = getSipApplicationSessionExtraParamsThirdPartySPI();
//        for(Iterator it = sasExtraParams.iterator(); it.hasNext();) {
//            SipApplicationSessionExtraParams nextExtraParam = (SipApplicationSessionExtraParams)it.next();
//            if(_logger.isLoggable(Level.FINE)) {
//                _logger.fine("in " + this.getClass().getName() + " nextExtraParam=" + nextExtraParam);
//            }
//            if(isTimeForSipApplicationSessionLoadAdvisory(nextExtraParam)) {
//                expiredReplicas.add(nextExtraParam);
//            }
//        }
//        if(_logger.isLoggable(Level.FINE)) {
//            _logger.fine("processExpiredSipApplicationSessionReplicasThirdPartySPI:expiredReplicas.size=" + expiredReplicas.size());
//        }
//        for(int i=0; i<expiredReplicas.size(); i++) {
//            SipApplicationSessionExtraParams nextExtraParam =
//                (SipApplicationSessionExtraParams)expiredReplicas.get(i);
//            String rightfulOwnerInstanceName
//                = SipApplicationSessionUtil.getActualServerInstance((String)nextExtraParam.getId());
//            this.sendLoadAdvisorySipApplicationSession((String)nextExtraParam.getId(), rightfulOwnerInstanceName);
//        }
//    }
//

    //TODO: Remove processExpiredSipApplicationSessionReplicasThirdPartySPI() method
    //TODO: Remove getSipApplicationSessionExtraParamsThirdPartySPI() method
    //

    public void sendSASLoadAdvisories(String instanceName,
                                      HashSet<String> expiredReplicaIds) {
        SipApplicationSessionStoreImpl store = null;
        try {
            store = getSipApplicationSessionStore();
            if (store != null) {
                store.sendLoadAdvisories(instanceName, expiredReplicaIds);
            }
        } finally {
            this.putSipApplicationSessionStore(store);
        }
    }

    void processExpiredSASReplicas(Map<String, HashSet<String>> expiredReplicaMap) {

        HashSet<String> expiredInSelfReplica = new HashSet();

        for(String instance : expiredReplicaMap.keySet()) {
            HashSet<String> expiredReplicaIds = expiredReplicaMap.get(instance);
            if(ReplicationUtil.getInstanceName().equalsIgnoreCase(instance)) {
                // process our own expired replicas after sending load advisories.
                expiredInSelfReplica = expiredReplicaIds;
            } else {
                sendSASLoadAdvisories(instance, expiredReplicaIds);
            }
        }

        for(String expiredReplicaId : expiredInSelfReplica) {
            HASipApplicationSession sas =
                    processLoadadvisorysas(expiredReplicaId);
            if(sas != null) {
                removeFromSipApplicationSessionReplicationCache(sas.getId());
            }
        }
    }

    void _processExpiredSipApplicationSessions() {
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processExpiredSipApplicationSessionReplicasThirdPartySPI");
        }
        Map<String, HashSet<String>> expiredReplicaMap =
                new HashMap<String, HashSet<String>>();
        BackingStore sipApplicationSessionBackingStore
                = this.getSipApplicationSessionBackingStore();
        String applicationId = this.getApplicationId();
        SipApplicationSessionExtraParams sasExtraParamCriteria
                = SipApplicationSessionExtraParams.createSearchCriteriaAppid(this, applicationId);
        Collection<SipApplicationSessionExtraParams> expiredReplicas
                = (Collection<SipApplicationSessionExtraParams>)
                sipApplicationSessionBackingStore.findByCriteria(null, sasExtraParamCriteria); //TODO: pass criteria

        for (SipApplicationSessionExtraParams nextExtraParam : expiredReplicas) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("in " + this.getClass().getName() + " nextExtraParam=" + nextExtraParam);
            }
            if (this.isTimeForSipApplicationSessionLoadAdvisory(nextExtraParam)) {
                String sasId = nextExtraParam.getId();
                String rightfulOwnerInstanceName =
                    SipReplicationUtil.getCurrentServerInstance(sasId);
                HashSet s = expiredReplicaMap.get(rightfulOwnerInstanceName);
                if(s == null) {
                    s = new HashSet<String>();
                    expiredReplicaMap.put(rightfulOwnerInstanceName, s);
                }
                s.add(sasId);
            }
        }
        processExpiredSASReplicas(expiredReplicaMap);
    }

    Collection<SipApplicationSessionExtraParams> _findByCriteriaExpiredSipApplicationSessions(SipApplicationSessionExtraParams criteria) {
          Collection<SipApplicationSessionExtraParams> result =
                  new LinkedList<SipApplicationSessionExtraParams>();
                  if(_logger.isLoggable(Level.FINE)) {
              _logger.fine("in " + this.getClass().getName() + ">>processExpiredSipApplicationSessionReplicas");
          }

          int expiredReplicas = 0;
          BaseCache replicatedSipAppSessionsCache = getReplicatedSipApplicationSessions();
          for(Iterator it = replicatedSipAppSessionsCache.keys(); it.hasNext();) {
              ReplicationState nextState = (ReplicationState)
                  replicatedSipAppSessionsCache.get((String) it.next());
              if (nextState != null) {
                  if(_logger.isLoggable(Level.FINE)) {
                      _logger.fine("in " + this.getClass().getName() +
                          ">>_findByCriteria_ExpiredSAS: nextState=" +
                          nextState);
                  }
                  if (isTimeForSipApplicationSessionLoadAdvisory(nextState)) {
                      //if(!LoadProcessingGovernor.isSystemUnderLoadStress()
                      //        && !SipReplicationUtil.isExpatExtraDurationInEffect()
                      //        && !SipReplicationUtil.isExpatInProgress()) {
                      if(!ExpatListHandler.isExpatExtraDurationInEffect()
                              && !ExpatListHandler.isExpatInProgress()) {
                          expiredReplicas++;
                          result.add(getSipApplicationSessionExtraParamsFrom(nextState));
                      }
                  }
              }
          }
          if(_logger.isLoggable(Level.FINE)) {
              _logger.fine("in " + this.getClass().getName() +
                  ">>processExpiredSipApplicationSessionReplicas: expiredReplicas.size=" +
                  expiredReplicas);
          }

          return result;
      }

//    List getSipApplicationSessionExtraParamsThirdPartySPI() {
//        BackingStore sipApplicationSessionBackingStore
//            = this.getSipApplicationSessionBackingStore();
//        String applicationId = this.getApplicationId();
//        SipApplicationSessionExtraParams sasExtraParamCriteria
//            = SipApplicationSessionExtraParams.createSearchCriteriaAppid(applicationId);
//        Collection<SipApplicationSessionExtraParams> sasColl
//            = sipApplicationSessionBackingStore.findByCriteria(sasExtraParamCriteria);
//
//        List result = new ArrayList();
//        Iterator<SipApplicationSessionExtraParams> sasResults =
//            (Iterator<SipApplicationSessionExtraParams>) sasColl.iterator();
//        while (sasResults.hasNext()) {
//            SipApplicationSessionExtraParams eParam = sasResults.next();
//            if (applicationId.equals(eParam.getAppId())) {
//                result.add(eParam);
//            }
//        }
//        return result;
//    }
   
    void processExpiredSipSessionReplicas() {
        //code assumes that isExpired works for this type of ReplicationState       
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processExpiredSipSessionReplicas");           
        }
        int expiredReplicas = 0;
        BaseCache replicatedSipSessionsCache = getReplicatedSipSessions();
        for(Iterator it = replicatedSipSessionsCache.keys(); it.hasNext();) {
            ReplicationState nextState = (ReplicationState)
                replicatedSipSessionsCache.get((String) it.next());
            if (nextState != null) {
                if(_logger.isLoggable(Level.FINE)) {
                    _logger.fine("in " + this.getClass().getName() +
                        ">>processExpiredSipSessionReplicas: nextState=" +
                        nextState);           
                }           
                if (isExpiredSipSessionReplica(nextState)) {
                    //if(!LoadProcessingGovernor.isSystemUnderLoadStress()
                    //        && !SipReplicationUtil.isExpatExtraDurationInEffect()
                    //        && !SipReplicationUtil.isExpatInProgress()) {
                    if(!ExpatListHandler.isExpatExtraDurationInEffect()
                            && !ExpatListHandler.isExpatInProgress()) {                   
                        expiredReplicas++;
                        removeFromSipSessionReplicationCache((String)nextState.getId());
                    }
                }
            }
        }

        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() +
                ">>processExpiredSipSessionReplicas: expiredReplicas.size=" +
                expiredReplicas);           
        }       
    }
   
    private SipSessionExtraParams getSipSessionExtraParamsFrom(ReplicationState state) {
        if(state == null) {
            return null;
        }
        if(state.getDeserializedExtraParam() != null) {
            return (SipSessionExtraParams)state.getDeserializedExtraParam();
        } else {
            //deserialize and cache result in state
            SipSessionExtraParams extraParams =
                SipSessionExtraParams.getDeserializedExtraParams(
                    state, isReplicationCompressionEnabled());
            state.setDeserializedExtraParam(extraParams);
            return extraParams;
        }
    }
   
    void processExpiredSipSessionReplicasThirdPartySPI() {
        //code assumes that isExpired works for this type of ReplicationState
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processExpiredSipSessionReplicasThirdPartySPI");           
        }
        ArrayList expiredReplicas = new ArrayList(30);
        List sipSessionExtraParams = getSipSessionExtraParamsThirdPartySPI();
        for(Iterator it = sipSessionExtraParams.iterator(); it.hasNext();) {
            SipSessionExtraParams nextExtraParam = (SipSessionExtraParams)it.next();
            if(_logger.isLoggable(Level.FINE)) {
                _logger.fine("in " + this.getClass().getName() + " nextExtraParam=" + nextExtraParam);           
            }
            if(isExpiredSipSessionReplica(nextExtraParam)) {
                expiredReplicas.add(nextExtraParam);
            }
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("processExpiredSipSessionReplicasThirdPartySPI:expiredReplicas.size=" + expiredReplicas.size());           
        }
        for(int i=0; i<expiredReplicas.size(); i++) {
            SipApplicationSessionExtraParams nextExtraParam =
                (SipApplicationSessionExtraParams)expiredReplicas.get(i);
            this.removeSipSession((String)nextExtraParam.getId());
        }
    }

    public void _processExpiredSipSessions() {
          if (_logger.isLoggable(Level.FINE)) {
              _logger.fine("in " + this.getClass().getName() + ">>_process_ExpiredSipSessions");
          }

          BackingStore sipSessionBackingStore
                  = this.getSipSessionBackingStore();
          String applicationId = this.getApplicationId();
          SipSessionExtraParams sipSessionExtraParamCriteria
                  = SipSessionExtraParams.createSearchCriteriaAppid(
                  this, applicationId);
          Collection<SipSessionExtraParams> sipSessionColl
                  = sipSessionBackingStore.findByCriteria(null, sipSessionExtraParamCriteria);

          for (SipSessionExtraParams nextExtraParam : sipSessionColl) {
              if (_logger.isLoggable(Level.FINE)) {
                  _logger.fine("in " + this.getClass().getName() + " nextExtraParam=" + nextExtraParam);
              }
              if (isExpiredSipSessionReplica(nextExtraParam)) {
                  if (!ExpatListHandler.isExpatExtraDurationInEffect()
                          && !ExpatListHandler.isExpatInProgress()) {
                      removeFromSipSessionReplicationCache(nextExtraParam.getId());
                  }
              }
          }
      }
    Collection<SipSessionExtraParams> _findByCriteriaExpiredSipSessions() {
        //code assumes that isExpired works for this type of ReplicationState
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processExpiredSipSessionReplicas");
        }
        Collection<SipSessionExtraParams> result = new
                LinkedList<SipSessionExtraParams>();
        BaseCache replicatedSipSessionsCache = getReplicatedSipSessions();
        for(Iterator it = replicatedSipSessionsCache.keys(); it.hasNext();) {
            ReplicationState nextState = (ReplicationState)
                replicatedSipSessionsCache.get((String) it.next());
            if (nextState != null) {
                if(_logger.isLoggable(Level.FINE)) {
                    _logger.fine("in " + this.getClass().getName() +
                        ">>_findByCriteria_ExpiredSipSessions: nextState=" +
                        nextState);
                }
                if (isExpiredSipSessionReplica(nextState)) {
                    //if(!LoadProcessingGovernor.isSystemUnderLoadStress()
                    //        && !SipReplicationUtil.isExpatExtraDurationInEffect()
                    //        && !SipReplicationUtil.isExpatInProgress()) {
                    if(!ExpatListHandler.isExpatExtraDurationInEffect()
                            && !ExpatListHandler.isExpatInProgress()) {
                        result.add(getSipSessionExtraParamsFrom(nextState));
                    }
                }
            }
        }

        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() +
                ">>_findByCriteria_ExpiredSipSessions: expiredReplicas.size=" +
                result.size());
        }

        return result;
    }         
   
    List getSipSessionExtraParamsThirdPartySPI() {       
        BackingStore sipSessionBackingStore
            = this.getSipSessionBackingStore();
        String applicationId = this.getApplicationId();
        SipSessionExtraParams sipSessionExtraParamCriteria
            = SipSessionExtraParams.createSearchCriteriaAppid(this, applicationId);
        Collection<SipSessionExtraParams> sipSessionColl
            = sipSessionBackingStore.findByCriteria(null, sipSessionExtraParamCriteria);

        List result = new ArrayList();       
        Iterator<SipSessionExtraParams> sipSessionResults =
            (Iterator<SipSessionExtraParams>) sipSessionColl.iterator();
        while (sipSessionResults.hasNext()) {
            SipSessionExtraParams eParam = sipSessionResults.next();
            if (applicationId.equals(eParam.getAppId())) {
                result.add(eParam);
            }           
        }       
        return result;
    }       
   
    protected boolean isExpiredSipSessionReplica(ReplicationState state) {
        SipSessionExtraParams extraParams
            = getSipSessionExtraParamsFrom(state);
        return isExpiredSipSessionReplica(extraParams);         
    }
   
    protected boolean isExpiredSipSessionReplica(SipSessionExtraParams extraParams) {      
        if(extraParams == null) {
            return false;
        } else {
            long nextExpirationTime = extraParams.getExpirationTime();
            //expirationTime of 0 or -1 means infinite
            //in this case we expire if duration since last access
            //is greater than SERVLET_TIMER_MAX_THRESHOLD_IN_MILLIS
            if(nextExpirationTime == 0L || nextExpirationTime == -1L) {
                if( (System.currentTimeMillis() - extraParams.getInternalLastAccessedTime()) > ActivationHelper.SERVLET_TIMER_MAX_THRESHOLD_IN_MILLIS ) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return (System.currentTimeMillis() >= (nextExpirationTime + getDeltaMillis()));
            }
        }              
    }   
   
    void processExpiredServletTimerReplicas() {
        //code assumes that isExpired works for this type of ReplicationState       
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processExpiredServletTimerReplicas");           
        }
        int expiredReplicas = 0;
        BaseCache replicatedServletTimersCache = getReplicatedServletTimers();
        for (Iterator it = replicatedServletTimersCache.keys(); it.hasNext();) {
            ReplicationState nextState = (ReplicationState)
                replicatedServletTimersCache.get((String) it.next());
            if (nextState != null) {
                if(_logger.isLoggable(Level.FINE)) {
                    _logger.fine("in " + this.getClass().getName() +
                        ">>processExpiredServletTimerReplicas: nextState=" +
                        nextState);           
                }           
                if (isTimeForServletTimerLoadAdvisory(nextState)) {
                    //if(!LoadProcessingGovernor.isSystemUnderLoadStress()
                    //        && !SipReplicationUtil.isExpatInProgress()) {
                    if(!ExpatListHandler.isExpatInProgress()) {                   
                        expiredReplicas++;
                        processExpiredServletTimerReplica(nextState);
                    }
                }
            }
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() +
                ">>processExpiredServletTimerReplicas: expiredReplicas.size=" +
                expiredReplicas);           
        }       
    }

    private void processExpiredServletTimerReplica(ReplicationState state) {
        ServletTimerExtraParams extraParams
            = (ServletTimerExtraParams)state.getContainerExtraParams();
        processExpiredServletTimerReplica(extraParams, state.getInstanceName());
    }

    private void processExpiredServletTimerReplica(ServletTimerExtraParams extraParams, String fromInstanceName) {
        if (extraParams == null || extraParams.getParentSasId() == null) {
            return;
        }
        String sasId = extraParams.getParentSasId();
        String id = extraParams.getId(); //TODO: Verify. Was: String id = (String)state.getId();
        try {
            String rightfulOwnerInstanceName =
                SipReplicationUtil.getCurrentServerInstance(sasId);
            if (rightfulOwnerInstanceName == null) {
                _logger.warning(
                    "in " + this.getClass().getName() +
                    ">>processExpiredServletTimerReplica: " +
                    "No rightful owner instance returned by " +
                    "DataCentricUtil for SipApplicationSession " +
                    "with id: " + sasId);
                // FIXME Skip this ST id by removing it from replica cache
                return;
            }
            if (getInstanceName().equals(rightfulOwnerInstanceName)) {
                //short circuit version of load advisory
                processLoadadvisoryservlettimer(id, true, fromInstanceName);
            } else {                              
                sendLoadAdvisoryServletTimer(id, rightfulOwnerInstanceName);
            }
        } catch (Throwable t) {
            _logger.log(Level.WARNING,
                "in " + this.getClass().getName() +
                ">>processExpiredServletTimerReplica: " +
                "Unable to process expiration of " +
                "ServletTimer replica with id: " + id, t);
            // FIXME Skip this ST id by removing it from replica cache
        }
    }

    private ServletTimerExtraParams getServletTimerExtraParamsFrom(ReplicationState state) {
        if(state == null) {
            return null;
        }
        if(state.getDeserializedExtraParam() != null) {
            return (ServletTimerExtraParams)state.getDeserializedExtraParam();
        } else {
            //deserialize and cache result in state
            ServletTimerExtraParams extraParams =
                ServletTimerExtraParams.getDeserializedExtraParams(
                    state, isReplicationCompressionEnabled());
            state.setDeserializedExtraParam(extraParams);
            return extraParams;
        }
    }

    void _processExpiredServletTimers() {

        //code assumes that isExpired works for this type of ReplicationState
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processExpiredServletTimerReplicasThirdPartySPI");
        }

        BackingStore servletTimerBackingStore
                = this.getServletTimerBackingStore();
        String applicationId = this.getApplicationId();
        ServletTimerExtraParams servletTimerExtraParamCriteria
                = ServletTimerExtraParams.createSearchCriteriaAppid(this, applicationId);
        Collection<ServletTimerExtraParams> servletTimerColl
                = servletTimerBackingStore.findByCriteria(
                null, servletTimerExtraParamCriteria);

        int count = 0;
        for (ServletTimerExtraParams nextExtraParam : servletTimerColl) {
            if (_logger.isLoggable(Level.FINE)) {
                if (isTimeForServletTimerLoadAdvisory(nextExtraParam)) {
                    //if(!LoadProcessingGovernor.isSystemUnderLoadStress()
                    //        && !SipReplicationUtil.isExpatInProgress()) {
                    if (!ExpatListHandler.isExpatInProgress()) {
                        count++;
                        processExpiredServletTimerReplica(nextExtraParam, nextExtraParam.getCurrentOwnerInstanceName());
                    }
                }
            }
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("_process_ExpiredServletTimers:expiredReplicas.size=" + count);
            }
        }
    }

    Collection<ServletTimerExtraParams> _findByCriteriaExpiredServletTimers(ServletTimerExtraParams stEP) {
        Collection<ServletTimerExtraParams> result = new LinkedList<ServletTimerExtraParams>();

        //code assumes that isExpired works for this type of ReplicationState
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processExpiredServletTimerReplicas");
        }
        int expiredReplicas = 0;
        BaseCache replicatedServletTimersCache = getReplicatedServletTimers();
        for (Iterator it = replicatedServletTimersCache.keys(); it.hasNext();) {
            ReplicationState nextState = (ReplicationState)
                    replicatedServletTimersCache.get((String) it.next());
            if (nextState != null) {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("in " + this.getClass().getName() +
                            ">>_findByCriteria_ExpiredServletTimers: nextState=" +
                            nextState);
                }
                if (isTimeForServletTimerLoadAdvisory(nextState)) {
                    //if(!LoadProcessingGovernor.isSystemUnderLoadStress()
                    //        && !SipReplicationUtil.isExpatInProgress()) {
                    if (!ExpatListHandler.isExpatInProgress()) {
                        expiredReplicas++;
                        result.add(getServletTimerExtraParamsFrom(nextState));
                    }
                }
            }
        }
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() +
                    ">>_findByCriteria_ExpiredServletTimers: expiredReplicas.size=" +
                    expiredReplicas);
        }

        return result;
    }
   
//    void processExpiredServletTimerReplicasThirdPartySPI() {
//        //code assumes that isExpired works for this type of ReplicationState
//        if(_logger.isLoggable(Level.FINE)) {
//            _logger.fine("in " + this.getClass().getName() + ">>processExpiredServletTimerReplicasThirdPartySPI");
//        }
//        ArrayList expiredReplicas = new ArrayList(30);
//        List servletTimerExtraParams = getServletTimerExtraParamsThirdPartySPI();
//        for(Iterator it = servletTimerExtraParams.iterator(); it.hasNext();) {
//            ServletTimerExtraParams nextExtraParam = (ServletTimerExtraParams)it.next();
//            if(_logger.isLoggable(Level.FINE)) {
//                _logger.fine("in " + this.getClass().getName() + " nextExtraParam=" + nextExtraParam);
//            }
//            if(isTimeForServletTimerLoadAdvisory(nextExtraParam)) {
//                expiredReplicas.add(nextExtraParam);
//            }
//        }
//        if(_logger.isLoggable(Level.FINE)) {
//            _logger.fine("processExpiredServletTimerReplicasThirdPartySPI:expiredReplicas.size=" + expiredReplicas.size());
//        }
//        for(int i=0; i<expiredReplicas.size(); i++) {
//            ServletTimerExtraParams nextExtraParam =
//                (ServletTimerExtraParams)expiredReplicas.get(i);
//            if(nextExtraParam.getParentSasId() != null) {
//                String sasId = nextExtraParam.getParentSasId();
//                String rightfulOwnerInstanceName
//                    = SipApplicationSessionUtil.getActualServerInstance(sasId);
//                this.sendLoadAdvisoryServletTimer((String)nextExtraParam.getId(), rightfulOwnerInstanceName);
//            }
//        }
//    }
//
//    List getServletTimerExtraParamsThirdPartySPI() {
//        BackingStore servletTimerBackingStore
//            = this.getServletTimerBackingStore();
//        String applicationId = this.getApplicationId();
//        ServletTimerExtraParams servletTimerExtraParamCriteria
//            = ServletTimerExtraParams.createSearchCriteriaAppid(this, applicationId);
//        Collection<ServletTimerExtraParams> servletTimerColl
//            = servletTimerBackingStore.findByCriteria(null, servletTimerExtraParamCriteria);
//
//        List result = new ArrayList();
//        Iterator<ServletTimerExtraParams> servletTimerResults =
//            (Iterator<ServletTimerExtraParams>) servletTimerColl.iterator();
//        while (servletTimerResults.hasNext()) {
//            ServletTimerExtraParams eParam = servletTimerResults.next();
//            if (applicationId.equals(eParam.getAppId())) {
//                result.add(eParam);
//            }
//        }
//        return result;
//    }
   
    protected boolean isTimeForServletTimerLoadAdvisory(ReplicationState state) {
        ServletTimerExtraParams extraParams
            = getServletTimerExtraParamsFrom(state);
        return isTimeForServletTimerLoadAdvisory(extraParams);
    }
   
    protected boolean isTimeForServletTimerLoadAdvisory(ServletTimerExtraParams extraParams) {       
        if(extraParams == null) {
            return false;
        } else {
            if(extraParams.getExpirationTime() <= 0) {  //infinite case
                long timeSinceLastAccessed
                    = System.currentTimeMillis() - extraParams.getInternalLastAccessedTime();
                return(timeSinceLastAccessed > (ActivationHelper.SERVLET_TIMER_MAX_THRESHOLD_IN_MILLIS + 1));
            } else {
                return (System.currentTimeMillis() >= extraParams.getWiggledExpirationTime());
            }
        }
    }   
   
    private boolean applySipApplicationSessionTimingHeuristicTo(long timerExpirationTime) {
        return activationHelper.calculateSasTimerTaskScheduleTime(timerExpirationTime) == 0L;
    }
   
    private boolean applyServletTimerTimingHeuristicTo(long timerExpirationTime) {
        return activationHelper.calculateServletTimerTaskScheduleTime(timerExpirationTime) == 0L;
    }   
   
    //end expiration related methods

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }   

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
   
    public StorePool getSipApplicationSessionStorePool() {
        return sipApplicationSessionStorePool;
    }
   
    public void setSipApplicationSessionStorePool(StorePool sipApplicationSessionStorePool) {
        this.sipApplicationSessionStorePool = sipApplicationSessionStorePool;
    }
   
    public StorePool getSipSessionStorePool() {
        return sipSessionStorePool;
    }
   
    public void setSipSessionStorePool(StorePool sipSessionStorePool) {
        this.sipSessionStorePool = sipSessionStorePool;
    }          

    public StorePool getServletTimerStorePool() {
        return servletTimerStorePool;
    }
   
    public void setServletTimerStorePool(StorePool servletTimerStorePool) {
        this.servletTimerStorePool = servletTimerStorePool;
    }          
   
    /**
     * Creates a new SipSession.
     *
     * @param set
     * @param to
     * @param appSession
     * @param handler
     * @type type
     *
     * @return The new SipSession
     */
    protected SipSessionDialogImpl createNewSipSession(
            DialogSet set, Address to, SipApplicationSessionImpl appSession,
            String handler, Type type) {

        return getSessionFactory().createSipSession(this, set, to, appSession,
                                                    handler, type);
    }


    /**
     * Creates a new SipApplicationSession.
     *
     * @param id The id of the new SipApplicationSession
     *
     * @return The new SipApplicationSession
     */
    protected SipApplicationSessionImpl createNewSipApplicationSession(String id) {

        return getSessionFactory().createSipApplicationSession(this, id);
    }


    /**
     * Creates a new ServletTimer.
     *
     * @return The new ServletTimer
     */
    protected ServletTimerImpl createNewServletTimer(
            SipApplicationSessionImpl sas, Serializable info, long delay,
            TimerListener listener, boolean isPersistent) {
        if (isPersistent) {
            return sessionFactory.createServletTimer(this, sas, info, delay, listener);
        } else {
            return super.createNewServletTimer(sas, info, delay, listener,
                                               isPersistent);
        }
    }


    /**
     * Creates a new ServletTimer.
     *
     * @return The new ServletTimer
     */
    protected ServletTimerImpl createNewServletTimer(
            SipApplicationSessionImpl sas, Serializable info, long delay,
            boolean fixedDelay, long period, TimerListener listener,
            boolean isPersistent) {
        if (isPersistent) {
            return sessionFactory.createServletTimer(this, sas, info, delay, fixedDelay, period, listener);
        } else {
            return super.createNewServletTimer(sas, info, delay,
                    fixedDelay, period, listener, isPersistent);
        }
    }


    /**
     * Gets the persistence type of this session manager.
     */
    public String getPersistenceType() {
        return EEPersistenceTypeResolver.REPLICATED_TYPE;
    }
   
    //begin send-side methods
   
    /**
     * Persists the given SipApplicationSession.
     *
     * @param sas The SipApplicationSession to be persisted
     */
    public void saveSipApplicationSession(SipApplicationSessionImpl sas)
            throws IOException {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "saveSipApplicationSession", sas);
        }       
        SipApplicationSessionStoreImpl store = null;
        try {
            store = getSipApplicationSessionStore();
            if (store != null) {
                store.save(sas);
            }
        }
        finally {
            this.putSipApplicationSessionStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "saveSipApplicationSession");
        }
       
    }

    /**
     * Adds the given SipApplicationSession to this session manager's
     * active cache.
     * This method checks for an existing version and avoids overriding
     * a later version with an earlier version
     *
     * @param sas The SipApplicationSession to add
     *
     * @return the previous SipApplicationSession, or null
     */
    @Override
    public SipApplicationSession addSipApplicationSession(SipApplicationSessionImpl sas) {
        SipApplicationSession ret = null;
        HASipApplicationSession currentSas = null;
        HASipApplicationSession addedSas = (HASipApplicationSession)sas;
        String id = sas.getId();
        Object monitor = getReplicationSessionMonitor(id);
        synchronized(monitor) {
            currentSas = (HASipApplicationSession)applicationSessions.get(id);
            if(_logger.isLoggable(Level.FINE)) {
                if(currentSas != null) {
                    _logger.fine("currentVersion: " + currentSas.getVersion()
                                 + " newVersion: " + addedSas.getVersion());
                }
            }
            if((currentSas != null) && currentSas.getVersion() >= addedSas.getVersion()) {
                return currentSas;
            }
            ret = applicationSessions.put(addedSas.getId(), addedSas);
        }
        if (_logger.isLoggable(Level.FINE)) {
            String replacedVersion = "";
            if (currentSas != null) {
                replacedVersion = ". Replaced version " + currentSas.getVersion();
            }
            _logger.fine("Put in active cache appId=" + this.getApplicationId() + " id:" + id +
                    "[ver:" + addedSas.getVersion() + "] of instance " + getInstanceName() +
                    replacedVersion);
        }
        return ret;
    }

    /**
     * Removes the given SipApplicationSession from only the active cache
     *
     * @param sas The SipApplicationSession to be removed
     */
    @Override
    public void removeSipApplicationSessionFromCache(SipApplicationSessionImpl sas) {
        Object monitor = getReplicationSessionMonitor(sas.getId());
        synchronized(monitor) {
            super.removeSipApplicationSessionFromCache(sas);
        }
    }   
   
    /**
     * Removes the given SipApplicationSession from both the active cache
     * and the persistent session store of this session manager,
     *
     * @param sas The SipApplicationSession to be removed
     */
    public void removeSipApplicationSession(SipApplicationSessionImpl sas) {
       
        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "removeSipApplicationSession", sas);
        }
        this.removeSipApplicationSessionFromCache(sas);
        if(!sasExpatListHandler.isAwaitingExpatList()) {
            synchronized(sasExpatIdsMap) {
    sasExpatIdsMap.remove(sas.getId());
      }
        }
        SipApplicationSessionStoreImpl store = null;
        try {
            store = getSipApplicationSessionStore();
            if (store != null) {     
                store.remove(sas.getId());
            }
        } catch (IOException ex) {
            _logger.log(
                Level.WARNING,
                "unable to remove SipApplicationSession:id = " + sas.getId(),
                ex);
        } finally {
            this.putSipApplicationSessionStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "removeSipApplicationSession");
        }
    }


    /**
     * Removes the given ServletTimer from both the active cache and the
     * persistent session store of this session manager,
     *
     * @param sasId The id of the SipApplicationSession to be removed
     * @param originatingInstanceName the name of the originating instance for this cyclical remove
     * @param cycleCount the counter used to determine when a complete cycle of the cluster is complete
     */
    public void cycleRemoveSipApplicationSession(String sasId, String originatingInstanceName, int cycleCount) {       
        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "cycleRemoveSipApplicationSession", sasId);
        }
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        int clusterSize = healthChecker.getCurrentGroupMembersSizeViaGMS();
        if(getInstanceName().equalsIgnoreCase(originatingInstanceName)
                || cycleCount >= clusterSize) {
            return;
        }
        SipApplicationSessionStoreImpl store = null;
        try {
            store = getSipApplicationSessionStore();
            if (store != null) {     
                store.remove(sasId, originatingInstanceName, cycleCount);
            }
        } catch (IOException ex) {
            _logger.log(
                Level.WARNING,
                "unable to remove SipApplicationSession:id = " + sasId,
                ex);
        } finally {
            this.putSipApplicationSessionStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "removeSipApplicationSession");
        }
    }   
   
    /**
     * Removes the given SipApplicationSession from the
     * persistent session store of this session manager,
     *
     * @param sasId The id SipApplicationSession replica to be removed
     */
    public void removeSipApplicationSessionReplica(String sasId) {
       
        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "removeSipApplicationSessionReplica", sasId);
        }
        SipApplicationSessionStoreImpl store = null;
        try {
            store = getSipApplicationSessionStore();           
            if (store != null) {
                store.remove(sasId);
            }
        } catch (IOException ex) {
            _logger.log(
                Level.WARNING,
                "unable to remove SipApplicationSession:id = " + sasId,
                ex);
        } finally {
            this.putSipApplicationSessionStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "removeSipApplicationSessionReplica");
        }
    }   
   
    /**
     * send a load advisory message to instance to trigger
     * it to load a given id
     *
     * @param id The id of the SipApplicationSession to be loaded
     * @param instanceName the instance to be sent the load advisory
     */
    public void sendLoadAdvisorySipApplicationSession(String id, String instanceName) {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager",
                             "sendLoadAdvisorySipApplicationSession",
                             new Object[] { id, instanceName});
        }
        SipApplicationSessionStoreImpl store = null;
        try {
            store = getSipApplicationSessionStore();
            if (store != null) {
                store.sendLoadAdvisory(id, instanceName);
            }
        } catch (IOException ex) {
            _logger.log(Level.WARNING, "sas_send_loadadvisory_error", new Object[] { id, instanceName });
            _logger.log(Level.WARNING, ex.getMessage(), ex);
        } finally {
            this.putSipApplicationSessionStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager",
                            "sendLoadAdvisorySipApplicationSession");
        }
    }      

    public <V> V __load(String id, String version, JxtaBackingStoreImpl jxtaBackingStore)
            throws BackingStoreException {
        V session = null;
        if (jxtaBackingStore == sipApplicationSessionBackingStore) {
            SipApplicationSessionStoreImpl store =
                    getSingletonSipApplicationSessionStore();
            session = (V) store.__load(id, version);
        } else if(jxtaBackingStore == sipSessionBackingStore) {
            SipSessionStoreImpl store = getSingletonSipSessionStore();
            session = (V) store.__load(id, version);
        } else if(jxtaBackingStore == servletTimerBackingStore) {
            ServletTimerStoreImpl store = getSingletonServletTimerStore();
            session = (V) store.__load(id, version);
        }
        return session;
    }

    private Set<String> remotelyLoadedSessionIds =
            Collections.synchronizedSet(new HashSet<String>());

    public Set<String> getRemotelyLoadedSessionIds() {
        return remotelyLoadedSessionIds;
    }

   
    /**
     * Look for a SipApplicationSession in the Store and, if found, restore
     * it in the Manager's list of active sessions if appropriate.
     * The session will be removed from the Store after swapping
     * in, but will not be added to the active session list if it
     * is invalid or past its expiration.
     * @param id the id of the SAS
     */
    protected SipApplicationSessionImpl swapInSipApplicationSession(String id,
                                                                    boolean force)
            throws IOException, RemoteLockException  {

  // We always call load if
  //
  // 1. force -- we were asked to
  // 2. we are loading the expat list, so don't know if the sas
  //     exists yet
  // 3. the id is in our replica cache
  // 4. there is no CLB to rely on
  //
  // The third case is an artifact of the way the CLB increases
  // load: the expat list is sent when the instance comes online.
  // A new call can start after that and be handled by another
  // instance if the CLB hasn't migtrated that call to us yet.
  // In that case, the id isn't in the expat list, but it will have
  // been replicated to us.
  boolean doCall =
      force || sasExpatListHandler.isAwaitingExpatList() ||
      (getFromSipApplicationSessionReplicationCache(id) != null) ||
      !SipReplicationUtil.isInstanceLoadBalancedByCLB();
        if (doCall) {
            return swapInSipApplicationSession(id, null);
        } else {
            // Avoid unnecessary load if the requested session has never
            // existed, i.e., is not contained in the expat list
            ExpatListElement expat;
      synchronized(sasExpatIdsMap) {
    expat = sasExpatIdsMap.get(id);
      }
            if (expat != null) {
                //return swapInSipApplicationSession(
                //    expat.getId(),
                //    Long.toString(expat.getVersion()), true);
                // now using version unaware load, see IT1550
                return swapInSipApplicationSession(
                    expat.getId(),
                    null, true);               
            } else {
                return null;
            }
        }
    }   
   
    private SipApplicationSessionImpl swapInSipApplicationSession(
            String id, String version)
            throws IOException, RemoteLockException {
        return swapInSipApplicationSession(id, version, false);
    }

    /**
     * Look for a SipApplicationSession in the Store and, if found, restore
     * it in the Manager's list of active sessions if appropriate.
     * The session will be removed from the Store after swapping
     * in, but will not be added to the active session list if it
     * is invalid or past its expiration.
     * @param id the id of the SAS
     * @param version - the version of the SAS
     */
    private SipApplicationSessionImpl swapInSipApplicationSession(
                                            String id, String version,
                                            boolean removeFromExpat)
            throws IOException, RemoteLockException  {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager",
                             "swapInSipApplicationSession",
                             new Object[] { id, version});
        }

        SipApplicationSessionStoreImpl store = getSipApplicationSessionStore();
        if (store == null) {
            return null;
        }

        try {
            SipApplicationSessionImpl session = null;
            try {
                if (SecurityUtil.isPackageProtectionEnabled()){
                    try{
                        session = (SipApplicationSessionImpl) AccessController.doPrivileged(new PrivilegedStoreLoadSipApplicationSession(id, version, store));
                    }catch(PrivilegedActionException ex){
                        Exception exception = ex.getException();
                        if (exception instanceof IOException){
                            throw (IOException)exception;
                        } else if (exception instanceof ClassNotFoundException) {
                            throw (ClassNotFoundException)exception;
                        }
                    }
                } else {
                    if (version != null) {
                         session = store.load(id, version);
                    } else {
                         session = store.load(id);
                    }
                }  
            } catch (ClassNotFoundException e) {
                IOException ex1 =
                    (IOException) new IOException("Error during swapInSipApplicationSession: " + e.getMessage()).initCause(e);
                throw ex1;                
            }
           
            if (SASLockStatus.isSASLocked()) {
                session = activate(session, removeFromExpat);
            } else if (session != null) {
                synchronized (session.getSasObjectLock()) {
                    SASLockStatus.resetSASLockedToDefaultValue();
                    session = activate(session, removeFromExpat);
                }
            }
            return session;
        } finally {
            this.putSipApplicationSessionStore(store);
        }
    }

    public SipApplicationSessionImpl activate(SipApplicationSessionImpl session,
                                              boolean removeFromExpat) {

        if (session == null) {
            return (null);
        }

        SipApplicationSessionImpl activatedSession = null;

        if (!session.isValid()) {
            if (_logger.isLoggable(Level.INFO)) {
                _logger.log(Level.INFO,
                        "SipApplicationSession with id: " +
                                session.getId() + " not swapped in " +
                                "because invalid");
            }
            // Cause replica to be removed
            removeSipApplicationSession(session);
        } else {
            boolean isActivated = session.activate();
            // Activate may have changed the validity of the session, so
            // we need to check again
            if (!isActivated || !session.isValid()) {
                // Cause replica to be removed
                // but leave invalid session in active cache
                removeSipApplicationSessionReplica(session.getId());
            } else {
                activatedSession = session;
            }
        }
        // remove from the expat at the end.
        if (removeFromExpat) {
            removeSipApplicationSessionExpatListElement(session.getId());
        }
        return activatedSession;
    }

    ExpatListElement getSipApplicationSessionExpatListElement(String id) {
        if(sasExpatReadWriteLock.readLock().tryLock()) {
            try {
    synchronized(sasExpatIdsMap) {
        ExpatListElement result = sasExpatIdsMap.get(id);
                    return result;
    }
            } finally {
                sasExpatReadWriteLock.readLock().unlock();
            }
        } else {
            return null;
        }
    }

    ExpatListElement removeSipApplicationSessionExpatListElement(String id) {
        if(sasExpatReadWriteLock.readLock().tryLock()) {
            try {
    synchronized(sasExpatIdsMap) {
                    ExpatListElement result = sasExpatIdsMap.remove(id);
                    return result;
    }
            } finally {
                sasExpatReadWriteLock.readLock().unlock();
            }
        } else {
            return null;
        }
    }

    ExpatListElement getSipSessionExpatListElement(String id) {
        if(sipSessionExpatReadWriteLock.readLock().tryLock()) {
            try {
    synchronized(sipSessionExpatIdsMap) {
                    ExpatListElement result = sipSessionExpatIdsMap.get(id);
                    return result;
    }
            } finally {
                sipSessionExpatReadWriteLock.readLock().unlock();
            }
        } else {
            return null;
        }
    }

    ExpatListElement removeSipSessionExpatListElement(String id) {
        if(sipSessionExpatReadWriteLock.readLock().tryLock()) {
            try {
    synchronized(sipSessionExpatIdsMap) {
                    ExpatListElement result = sipSessionExpatIdsMap.remove(id);
                    return result;
    }
            } finally {
                sipSessionExpatReadWriteLock.readLock().unlock();
            }
        } else {
            return null;
        }
    }

    ExpatListElement getServletTimerExpatListElement(String id) {
        if(servletTimerExpatReadWriteLock.readLock().tryLock()) {
            try {
    synchronized(servletTimerExpatIdsMap) {
                    ExpatListElement result = servletTimerExpatIdsMap.get(id);
                    return result;
    }
            } finally {
                servletTimerExpatReadWriteLock.readLock().unlock();
            }
        } else {
            return null;
        }
    }

    ExpatListElement removeServletTimerExpatListElement(String id) {
        if(servletTimerExpatReadWriteLock.readLock().tryLock()) {
            try {
    synchronized(servletTimerExpatIdsMap) {
                    ExpatListElement result = servletTimerExpatIdsMap.remove(id);
                    return result;
    }
            } finally {
                servletTimerExpatReadWriteLock.readLock().unlock();
            }
        } else {
            return null;
        }
    }
   
    /**
     * Persists the given SipSession.
     *
     * @param sipSession The SipSession to be persisted
     */
    public void saveSipSession(SipSessionDialogImpl sipSession)
            throws IOException {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "saveSipSession", sipSession);
        }       
        SipSessionStoreImpl store = null;
        try {
            store = getSipSessionStore();
            if (store != null) {
                store.save(sipSession);              
            }
        }
        finally {
            this.putSipSessionStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "saveSipSession");
        }
    }

    /**
     * Adds the given SipSession to this session manager's active cache.
     * This method checks for an existing version and avoids overriding
     * a later version with an earlier version
     *
     * @param sipSession The SipSession to add
     *
     * @return the previous SipSession, or null
     */
    @Override
    public SipSession addSipSession(SipSessionDialogImpl sipSession) {
        SipSession ret = null;
        HASipSession currentSipSession = null;
        HASipSession addedSipSession = (HASipSession)sipSession;
        String id = sipSession.getId();
        Object monitor = getReplicationSessionMonitor(id);
        synchronized(monitor) {
            currentSipSession = (HASipSession)sipSessions.get(id);
            if(_logger.isLoggable(Level.FINE)) {
                if(currentSipSession != null) {
                    _logger.fine("currentVersion: " + currentSipSession.getVersion()
                                 + " newVersion: " + addedSipSession.getVersion());
                }
            }
            if((currentSipSession != null) && currentSipSession.getVersion() >= addedSipSession.getVersion()) {
                return currentSipSession;
            }
            ret = sipSessions.put(addedSipSession.getId(), addedSipSession);
        }
        if (_logger.isLoggable(Level.FINE)) {
            String replacedVersion = "";
            if (currentSipSession != null) {
                replacedVersion = ". Replaced version " + currentSipSession.getVersion();
            }
            _logger.fine("Put in active cache appId=" + this.getApplicationId() + " id:" + id +
                    "[ver:" + addedSipSession.getVersion() + "] of instance " + getInstanceName() +
                    replacedVersion);
        }
        return ret;
    }

    /**
     * Removes the given SipSession from only the active cache
     *
     * @param sipSession The SipSession to be removed
     */
    @Override
    public void removeSipSessionFromCache(SipSessionDialogImpl sipSession) {
        Object monitor = getReplicationSessionMonitor(sipSession.getId());
        synchronized(monitor) {
            super.removeSipSessionFromCache(sipSession);
        }
    }   
   
    /**
     * Removes the given SipSession from both the active cache and the
     * persistent session store of this session manager,
     *
     * @param sipSession The SipSession to be removed
     */
    public void removeSipSession(SipSessionDialogImpl sipSession) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "removeSipSession", sipSession);
        }
        removeSipSessionFromCache(sipSession);
        SipSessionStoreImpl store = null;
        try {
            store = getSipSessionStore();
            if (store != null) {
                store.remove(sipSession.getId());
            }
        } catch (IOException ex) {
            _logger.log(
                Level.WARNING,
                "unable to remove SipSession:id = " + sipSession.getId(),
                ex);
        } finally {
            this.putSipSessionStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "removeSipSession");
        }
    }
   
    /**
     * Removes the given SipSession from the
     * persistent session store of this session manager,
     *
     * @param sipSessionId The id of the SipSession replica to be removed
     */
    public void removeSipSessionReplica(String sipSessionId) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "removeSipSessionReplica", sipSessionId);
        }
        SipSessionStoreImpl store = null;
        try {
            store = getSipSessionStore();
            if (store != null) {
                store.remove(sipSessionId);
            }
        } catch (IOException ex) {
            _logger.log(
                Level.WARNING,
                "unable to remove SipSession:id = " + sipSessionId,
                ex);
        } finally {
            this.putSipSessionStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "removeSipSessionReplica");
        }
    }    
   
    /**
     * Removes the given SipSession from both the active cache and the
     * persistent session store of this session manager,
     *
     * @param id The id of the SipSession to be removed
     */
    public void removeSipSession(String id) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "removeSipSession", id);
        }
        removeSipSessionFromCache(id);
        SipSessionStoreImpl store = null;
        try {
            store = getSipSessionStore();
            if (store != null) {
                store.remove(id);
            }
        } catch (IOException ex) {
            _logger.log(
                Level.WARNING,
                "unable to remove SipSession:id = " + id,
                ex);
        } finally {
            this.putSipSessionStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "removeSipSession");
        }
    }    
   
    /**
     * Look for a SipSession in the Store and, if found, restore
     * it in the Manager's list of active sessions if appropriate.
     * The session will be removed from the Store after swapping
     * in, but will not be added to the active session list if it
     * is invalid or past its expiration.
     * @param id the id of the SipSession
     */
    protected SipSessionDialogImpl swapInSipSession(String id,
                                                    boolean loadDependencies)
            throws IOException, RemoteLockException {
        return swapInSipSession(id, null, loadDependencies);
    }    
   
    /**
     * Look for a SipSession in the Store and, if found, restore
     * it in the Manager's list of active sessions if appropriate.
     * The session will be removed from the Store after swapping
     * in, but will not be added to the active session list if it
     * is invalid or past its expiration.
     * @param id the id of the SipSession
     * @param version - the version of the SipSession
     */
    private SipSessionDialogImpl swapInSipSession(String id, String version,
                                                  boolean loadDependencies)
            throws IOException, RemoteLockException {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager",
                             "swapInSipSession",
                             new Object[] { id, version, loadDependencies});
        }

        SipSessionStoreImpl store = getSipSessionStore();
        if (store == null) {
            return null;
        }

        try {
            SipSessionDialogImpl session = null;
            try {
                if (SecurityUtil.isPackageProtectionEnabled()){
                    try{
                        session = (SipSessionDialogImpl) AccessController.doPrivileged(new PrivilegedStoreLoadSipSession(id, version, loadDependencies, store));
                    } catch(PrivilegedActionException ex){
                        Exception exception = ex.getException();
                        if (exception instanceof IOException){
                            throw (IOException)exception;
                        } else if (exception instanceof ClassNotFoundException) {
                            throw (ClassNotFoundException)exception;
                        }
                    }
                } else {
                    if (version != null) {
                        session = store.load(id, version, loadDependencies);
                    } else {
                        session = store.load(id, loadDependencies);
                    }
                }  
            } catch (ClassNotFoundException e) {
                IOException ex1 =
                    (IOException) new IOException("Error during swapInSipSession: " + e.getMessage()).initCause(e);
                throw ex1;
            }
            return activate(session, false);
        } finally {
            this.putSipSessionStore(store);
        }
    }   
   
    public SipSessionDialogImpl activate(SipSessionDialogImpl session,
                                         boolean removeFromExpat) {
        if (session == null)
            return (null);

        SipSessionDialogImpl activatedSession = null;
        if (!session.isValid()) {
            // TODO :: shouldn't we call removeSipSessionReplica(session.getId())?
            if (_logger.isLoggable(Level.INFO)) {
                _logger.log(Level.INFO,
                        "SipSession with id: " +
                                session.getId() + " not swapped in " +
                                "because invalid");
            }
        } else {
            boolean isActivated = session.activate();
            if (isActivated) {
                activatedSession = session;
            } else {
                // TODO :: shouldn't we call removeSipSessionReplica(session.getId())?
            }
        }
        if (removeFromExpat) {
            removeSipSessionExpatListElement(session.getId());
        }
        return activatedSession;
    }

    /**
     * Persists the given ServletTimer.
     *
     * @param servletTimer The ServletTimer to be persisted
     */
    public void saveServletTimer(ServletTimerImpl servletTimer)
            throws IOException {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "saveServletTimer", servletTimer);
        }       
        ServletTimerStoreImpl store = null;
        try {
            store = getServletTimerStore();           
            if (store != null) {
                store.save(servletTimer);
            }
        }
        finally {
            this.putServletTimerStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "saveServletTimer");
        }      
    }

    /**
     * Adds the given ServletTimer to this session manager's
     * active cache.
     * This method checks for an existing version and avoids overriding
     * a later version with an earlier version
     *
     * @param timer The ServletTimer to add
     *
     * @return the previous ServletTimer, or null
     */
    @Override
    public ServletTimer addServletTimer(ServletTimerImpl timer) {
        ServletTimer ret = null;
        HAServletTimer currentTimer = null;
        HAServletTimer addedTimer = (HAServletTimer)timer;
        String id = timer.getId();
        Object monitor = getReplicationSessionMonitor(id);
        synchronized(monitor) {
            currentTimer = (HAServletTimer)servletTimers.get(id);
            if(_logger.isLoggable(Level.FINE)) {
                if(currentTimer != null) {
                    _logger.fine("currentVersion: " + currentTimer.getVersion()
                                 + " newVersion: " + addedTimer.getVersion());
                }
            }
            if((currentTimer != null) && currentTimer.getVersion() >= addedTimer.getVersion()) {
                return currentTimer;
            }
            ret = servletTimers.put(addedTimer.getId(), addedTimer);
        }
        if (_logger.isLoggable(Level.FINE)) {
            String replacedVersion = "";
            if (currentTimer != null) {
                replacedVersion = ". Replaced version " + currentTimer.getVersion();
            }
            _logger.fine("Put in active cache appId=" + this.getApplicationId() + " id:" + id +
                    "[ver:" + addedTimer.getVersion() + "] of instance " + getInstanceName() +
                    replacedVersion);
        }
        return ret;
    }

    /**
     * Removes the given ServletTimer from only the active cache
     *
     * @param servletTimer The ServletTimer to be removed
     */
    @Override
    public void removeServletTimerFromCache(ServletTimerImpl servletTimer) {
        Object monitor = getReplicationSessionMonitor(servletTimer.getId());
        synchronized(monitor) {
            super.removeServletTimerFromCache(servletTimer);
        }
    }

    public int processExpiredSessions() {
        throw new RuntimeException("processExpiredSessions in SipTransactionPersistentManager called");
    }
   
    /**
     * Removes the given ServletTimer from both the active cache and the
     * persistent session store of this session manager,
     *
     * @param servletTimer The ServletTimer to be removed
     */
    public void removeServletTimer(ServletTimerImpl servletTimer) {

        removeServletTimerFromCache(servletTimer);

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "removeServletTimer", servletTimer);
        }       
        ServletTimerStoreImpl store = null;
        try {
            store = getServletTimerStore();
            if (store != null) {
                store.remove(servletTimer.getId());
            }
        } catch (IOException ex) {
            _logger.log(Level.WARNING,
                "unable to remove ServletTimer:id = " + servletTimer.getId(),
                ex);
        } finally {
            this.putServletTimerStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "removeServletTimer");
        }
    }

    /**
     * Removes the given ServletTimer from both the active cache and the
     * persistent session store of this session manager,
     *
     * @param timerId The id of the ServletTimer to be removed
     * @param originatingInstanceName the name of the originating instance for this cyclical remove
     * @param cycleCount the counter used to determine when a complete cycle of the cluster is complete
     */
    public void cycleRemoveServletTimer(String timerId, String originatingInstanceName, int cycleCount) {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "cycleRemoveServletTimer", timerId);
        }
        ServletTimerStoreImpl store = null;
        try {
            store = getServletTimerStore();
            if (store != null) {
                store.remove(timerId, originatingInstanceName, cycleCount);
            }
        } catch (IOException ex) {
            _logger.log(Level.WARNING,
                "unable to remove ServletTimer:id = " + timerId,
                ex);
        } finally {
            this.putServletTimerStore(store);
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "removeServletTimer");
        }
    }
   
    /**
     * Removes the given ServletTimer from the
     * persistent session store of this session manager,
     *
     * @param servletTimerId The id of the ServletTimer replica to be removed
     */
    public void removeServletTimerReplica(String servletTimerId) {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "removeServletTimerReplica", servletTimerId);
        }       
        ServletTimerStoreImpl store = null;
        try {
            store = getServletTimerStore();
            if (store != null) {
                store.remove(servletTimerId);
            }
        } catch (IOException ex) {
            _logger.log(Level.WARNING,
                "unable to remove ServletTimer:id = " + servletTimerId,
                ex);
        } finally {
            this.putServletTimerStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "removeServletTimerReplica");
        }
    }   
   
    /**
     * send a load advisory message to instance to trigger
     * it to load a given id
     *
     * @param id The id of the ServletTimer to be loaded
     * @param instanceName the instance to be sent the load advisory
     */
    public void sendLoadAdvisoryServletTimer(String id, String instanceName) {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "sendLoadAdvisoryServletTimer", new Object[] {id, instanceName});
        }       
        ServletTimerStoreImpl store = null;
        try {
            store = getServletTimerStore();
            if (store != null) {
                store.sendLoadAdvisory(id, instanceName);
            }
        } catch (IOException ex) {
            _logger.log(Level.WARNING, "st_send_loadadvisory_error", new Object[] { id, instanceName });
            _logger.log(Level.WARNING, ex.getMessage(), ex);
        } finally {
            this.putServletTimerStore(store);
        }                
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "sendLoadAdvisoryServletTimer");
        }
    }  
   
    /**
     * Look for a ServletTimer in the Store and, if found, restore
     * it in the Manager's list of active sessions if appropriate.
     * The session will be removed from the Store after swapping
     * in, but will not be added to the active session list if it
     * is invalid or past its expiration.
     * @param id the id of the ServletTimer
     */
    protected ServletTimerImpl swapInServletTimer(String id,
                                                  boolean loadDependencies)
            throws IOException, RemoteLockException {
        return swapInServletTimer(id, null, loadDependencies);
    }    
   
    /**
     * Look for a ServletTimer in the Store and, if found, restore
     * it in the Manager's list of active sessions if appropriate.
     * The session will be removed from the Store after swapping
     * in, but will not be added to the active session list if it
     * is invalid or past its expiration.
     * @param id the id of the ServletTimer
     * @param version - the version of the ServletTimer
     */
    private ServletTimerImpl swapInServletTimer(String id, String version,
                                                boolean loadDependencies)
                throws IOException, RemoteLockException {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager",
                             "swapInServletTimer",
                             new Object[] { id, version, loadDependencies});
        }

        ServletTimerStoreImpl store = getServletTimerStore();
        if (store == null) {
            return null;
        }

        try {
            ServletTimerImpl timer = null;
            try {
                if (SecurityUtil.isPackageProtectionEnabled()){
                    try{
                        timer = (ServletTimerImpl) AccessController.doPrivileged(new PrivilegedStoreLoadServletTimer(id, version, loadDependencies, store));
                    }catch(PrivilegedActionException ex){
                        Exception exception = ex.getException();
                        if (exception instanceof IOException){
                            throw (IOException)exception;
                        } else if (exception instanceof ClassNotFoundException) {
                            throw (ClassNotFoundException)exception;
                        }
                    }
                } else {
                    if (version != null) {
                         timer = store.load(id, version, loadDependencies);
                    } else {
                         timer = store.load(id, loadDependencies);
                    }
                }  
            } catch (ClassNotFoundException e) {
                 IOException ex1 =
                    (IOException) new IOException("Error during swapInServletTimer: " + e.getMessage()).initCause(e);
                throw ex1;
            }

            return activate(timer, false);
        } finally {
            this.putServletTimerStore(store);
        }
    }

    public ServletTimerImpl activate(ServletTimerImpl timer, boolean removeFromExpat) {
        if (timer == null) {
            return (null);
        }

        boolean isActivated = timer.activate();
        if (!isActivated) {
            return null;
        }

        if(removeFromExpat) {
            removeServletTimerExpatListElement(timer.getId());
        }
        return timer;
    }

    /** Returns a store from the pool
     * This method intializes the store with right parameters
     * @return returns SipApplicationSessionStoreImpl
     */
    public SipApplicationSessionStoreImpl getSipApplicationSessionStore() {
        if(ReplicationUtil.isSynchronousReplicationConfigured()) {
            return getSipApplicationSessionStore(true);
        }
        return getSipApplicationSessionStore(false);
    }
   
    /** Returns a store from the pool
     * This method intializes the store with right parameters
     * @param useSingleton if true use a singleton store rather than obtaining from the pool
     * @return returns SipApplicationSessionStoreImpl
     */
    public SipApplicationSessionStoreImpl getSipApplicationSessionStore(boolean useSingleton) {

        // Suppress any replication during undeployment
        if (isBeingReleased) {
            return null;
        }

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "getSipApplicationSessionStore");
        }
        if(useSingleton) {
            return getSingletonSipApplicationSessionStore();
        }       
        if(sipApplicationSessionStorePool == null) {
            return null;
        }
        SipApplicationSessionStoreImpl store = null;
        try {
            store = (SipApplicationSessionStoreImpl) sipApplicationSessionStorePool.take();
            store.setSipSessionManager(this);
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST,
                    "SipTransactionPersistentManager.getSipApplicationSessionStore returning   " + store);
            }
            return store;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "getSipApplicationSessionStore", store);
        }
        return store;
    }

    /**
     *  Returns (puts) a store back to the pool
     */
    private void putSipApplicationSessionStore(StorePoolElement store) {
        if(ReplicationUtil.isSynchronousReplicationConfigured()) {
            putSipApplicationSessionStore(store, true);
        } else {
            putSipApplicationSessionStore(store, false);
        }
    }
   
    /**
     *  Returns (puts) a store back to the pool
     */
    private void putSipApplicationSessionStore(StorePoolElement store, boolean useSingleton) {
        if(useSingleton) {
            return;
        }       
        if (store != null) {
            ((SipApplicationSessionStoreImpl) store).setSipSessionManager(null);
            try {
                if(sipApplicationSessionStorePool != null) {
                    sipApplicationSessionStorePool.put(store);
                }
            }
            catch (InterruptedException ex1) {
                ex1.printStackTrace();
            }
        }
    }
   
    /** Returns the singleton store
     * This method intializes the store with right parameters
     * @return returns SipApplicationSessionStoreImpl
     */
    public SipApplicationSessionStoreImpl getSingletonSipApplicationSessionStore() {
        return (SipApplicationSessionStoreImpl)super.getSipApplicationSessionStore();
    }

    /** Returns a store from the pool
     * This method intializes the store with right parameters
     * @return returns SipSessionStoreImpl
     */
    public SipSessionStoreImpl getSipSessionStore() {
        if(ReplicationUtil.isSynchronousReplicationConfigured()) {
            return getSipSessionStore(true);
        }
        return getSipSessionStore(false);
    }
   
    /** Returns a store from the pool.
     * This method intializes the store with right parameters
     * @param useSingleton if true return a singleton store rather than from the pool
     * @return returns SipSessionStoreImpl
     */
    public SipSessionStoreImpl getSipSessionStore(boolean useSingleton) {

        // Suppress any replication during undeployment
        if (isBeingReleased) {
            return null;
        }

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "getSipSessionStore");
        }
        if(useSingleton) {
            return getSingletonSipSessionStore();
        }        
        if(sipSessionStorePool == null) {
            return null;
        }       
        SipSessionStoreImpl store = null;
        try {
            store = (SipSessionStoreImpl) sipSessionStorePool.take();
            store.setSipSessionManager(this);
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST,
                    "SipTransactionPersistentManager.getSipSessionStore returning   " + store);
            }
            return store;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "getSipSessionStore", store);
        }
        return store;
    }

    /**
     *  Returns (puts) a store back to the pool
     */
    private void putSipSessionStore(StorePoolElement store) {
        if(ReplicationUtil.isSynchronousReplicationConfigured()) {
            putSipSessionStore(store, true);
        } else {
            putSipSessionStore(store, false);
        }
    }
   
    /**
     *  Returns (puts) a store back to the pool
     */
    private void putSipSessionStore(StorePoolElement store, boolean useSingleton) {
        if(useSingleton) {
            return;
        }       
        if (store != null) {
            ((SipSessionStoreImpl) store).setSipSessionManager(null);
            try {
                if(sipSessionStorePool != null) {
                    sipSessionStorePool.put(store);
                }
            }
            catch (InterruptedException ex1) {
                ex1.printStackTrace();
            }
        }
    }
   
    /** Returns the singleton store
     * This method intializes the store with right parameters
     * @return returns SipSessionStoreImpl
     */
    public SipSessionStoreImpl getSingletonSipSessionStore() {
        return (SipSessionStoreImpl)super.getSipSessionStore();
    }

    /** Returns a store from the pool
     * This method intializes the store with right parameters
     * @return returns ServletTimerStoreImpl
     */
    public ServletTimerStoreImpl getServletTimerStore() {
        if(ReplicationUtil.isSynchronousReplicationConfigured()) {
            return getServletTimerStore(true);
        }
        return getServletTimerStore(false);
    }
   
    /** Returns a store from the pool
     * This method intializes the store with right parameters
     * @param useSingleton if true use the singleton store rather than from the pool
     * @return returns ServletTimerStoreImpl
     */
    public ServletTimerStoreImpl getServletTimerStore(boolean useSingleton) {

        // Suppress any replication during undeployment
        if (isBeingReleased) {
            return null;
        }

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager", "getServletTimerStore");
        }
        if(useSingleton) {
            return getSingletonServletTimerStore();
        }       
        if(servletTimerStorePool == null) {
            return null;
        }       
        ServletTimerStoreImpl store = null;
        try {
            store = (ServletTimerStoreImpl) servletTimerStorePool.take();
            store.setSipSessionManager(this);
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST,
                    "SipTransactionPersistentManager.getServletTimerStore returning   " + store);
            }
            return store;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager", "getServletTimerStore", store);
        }
        return store;
    }

    /**
     *  Returns (puts) a store back to the pool
     */
    private void putServletTimerStore(StorePoolElement store) {
        if(ReplicationUtil.isSynchronousReplicationConfigured()) {
            putServletTimerStore(store, true);
        } else {
            putServletTimerStore(store, false);
        }
    }
   
    /**
     *  Returns (puts) a store back to the pool
     */
    private void putServletTimerStore(StorePoolElement store, boolean useSingleton) {
        if(useSingleton) {
            return;
        }       
        if (store != null) {
            ((ServletTimerStoreImpl) store).setSipSessionManager(null);
            try {
                if(servletTimerStorePool != null) {
                    servletTimerStorePool.put(store);
                }
            }
            catch (InterruptedException ex1) {
                ex1.printStackTrace();
            }
        }
    }
   
    /** Returns the singleton store
     * This method intializes the store with right parameters
     * @return returns ServletTimerStoreImpl
     */
    public ServletTimerStoreImpl getSingletonServletTimerStore() {
        return (ServletTimerStoreImpl)super.getServletTimerStore();
    }    
   
    //end send-side methods
   
    //begin implement ReplicationManager
   
    private boolean isBroadcastState(ReplicationState state) {
        return(broadcastMethods.contains(state.getCommand()));
    }
               
    public void processMessage(ReplicationState message) {

        //handle broadcast methods
        if(isBroadcastState(message)) {
            processBroadcastMessage(message);
            return;
        }
       
        //handle non-void methods
        ReplicationStateQueryResponse queryResult = null;
        //do process non-void message (and cannot be response either)
        if(!message.isResponseState() && !message.isVoidMethodReturnState()) {
            //do non-void processing including sending response
            queryResult = this.doProcessQueryMessage(message);
            ReplicationState qResponse = queryResult.getState();
            if(qResponse != null) {
                //sourceInstanceName is preserved in the response
                ReplicationState response =
                    ReplicationState.createResponseFrom(qResponse);
                if(_logger.isLoggable(Level.FINE)) {
                    _logger.fine("RepMgrBase:responseState=" + response);
                }               
                this.doSendResponse(response);
            }
            return;
        }
        //end do process non-void message       

        boolean isResponse = this.doProcessMessage(message);
       
    }
   
    //return true if message is processResponse
    public boolean doProcessMessage(ReplicationState message) {
        boolean result = false;
        String methodName = ReplicationUtil.getProcessMethodName(message);
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>doProcessMessageName=" + methodName);
        }
        try {
            Class myClass = this.getClass();
            myClass.getMethod(
                methodName,
                    new Class[]{ message.getClass() }).invoke(
                        this, new Object[]{ message });           
        } catch (Throwable t) {
           _logger.log(Level.SEVERE, "manager_unable_to_process_replication_message", methodName);
           _logger.log(Level.SEVERE, t.getMessage(), t);
        }
        if(methodName.equals("processResponse")) {
            result = true;
        }
        return result;
    }   
   
    /**
    * send the response
    *
    * @param sessionState
    *   The replication state response
    */   
    public void doSendResponse(ReplicationState sessionState) {
              
        JxtaReplicationReceiver replicationReceiver =
                JxtaReplicationReceiver.createInstance();
        ReplicationState resultState =
                replicationReceiver.sendReplicationStateResponse(sessionState);
    }       
   
    public void processBroadcastMessage(ReplicationState message) {
        ReplicationStateQueryResponse response = this.doProcessQueryMessage(message);
        boolean isResponse = response.isResponse();
        ReplicationState responseState = response.getState();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("processBroadcastMessage:after doProcessQueryMessage:response=" + isResponse);
            _logger.fine("processBroadcastMessage:after doProcessQueryMessage:responseState=" + responseState);
            _logger.fine("processBroadcastMessage:after doProcessQueryMessage:responseStateTrunk=" + responseState.getTrunkState());
            _logger.fine("processBroadcastMessage:after doProcessQueryMessage:responseStateAttr=" + responseState.getState());
            _logger.fine("processBroadcastMessage:after doProcessQueryMessage:responseStateVer=" + responseState.getVersion());
        }

        //don't send a response to a response
        if(!isResponse) {
            //point-to-point response back to sender
            //System.out.println("processBroadcastMessage - need to send back result");
            //doSendQueryResponse(responseState, instanceName);
            doSendQueryResponse(responseState, message.getInstanceName());
        }
    }
   
    /**
    * send the response
    *
    * @param sessionState
    *   The replication state response
    * @param instanceName  the name of the target instance
    */   
    public void doSendQueryResponse(ReplicationState sessionState, String instanceName) {
        JxtaReplicationSender replicationSender =
                JxtaReplicationSender.createInstance();
        ReplicationState resultState =
                replicationSender.sendReplicationStateQueryResponse(sessionState, instanceName, useReplicationUnicastLoadResponseBatching);
    }       
   
    //return true if message is processQueryResponse
    public ReplicationStateQueryResponse doProcessQueryMessage(ReplicationState message) {
        ReplicationState resultState = null;
        String methodName = ReplicationUtil.getProcessMethodName(message);
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>doProcessQueryMessage:methodName=" + methodName);
            _logger.fine("in " + this.getClass().getName() + ">>doProcessQueryMessage:thisInstance=" + instanceName + " returnInstance=" + message.getInstanceName() );
        }        
        try {
            Class myClass = this.getClass();
            resultState = (ReplicationState) myClass.getMethod(
                methodName,
                    new Class[]{ message.getClass() }).invoke(
                        this, new Object[]{ message });
            if(_logger.isLoggable(Level.FINE)) {
                _logger.fine("doProcessQueryMessage:methodName = " + methodName + " resultState =" + resultState);
            }
        } catch (Throwable t) {
           _logger.log(Level.SEVERE, "manager_unable_to_process_replication_message", methodName);
           _logger.log(Level.SEVERE, t.getMessage(), t);
        }
        boolean isResponse = (methodName.equals("processBroadcastresponse") || methodName.equals("processUnicastresponse"));
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("doProcessQueryMessage:message command = " + message.getCommand());
            _logger.fine("doProcessQueryMessage:isResponse = " + isResponse);
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>doProcessQueryMessage:resultState=" + resultState);
        }
        if (resultState != null) {
            resultState.setRouteAdvertisement(message.getRouteAdvertisement());
        }       
        return new ReplicationStateQueryResponse(resultState, isResponse);
    }
   
    public void processQueryMessage(ReplicationState message, String returnInstance) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processQueryMessage:returnInstance= " + returnInstance);
        }        
        ReplicationStateQueryResponse response = this.doProcessQueryMessage(message);
        boolean isResponse = response.isResponse();
        ReplicationState responseState = response.getState();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("processQueryMessage:after doProcessQueryMessage:response=" + isResponse);
            _logger.fine("processQueryMessage:after doProcessQueryMessage:responseState=" + responseState);           
        }
        //don't send a response to a response
        if(!isResponse && responseState != null) {
            //point-to-point response back to sender
            if(_logger.isLoggable(Level.FINE)) {
                _logger.fine("processQueryMessage - need to send back result to " + returnInstance);           
            }            
            doSendQueryResponse(responseState, returnInstance);
        }
    }   
   
    public ReplicationState processBroadcastresponse(ReplicationState queryResponseState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastresponse:queryResponseState=" + queryResponseState);           
        }
        ReplicationResponseRepository.putFederatedEntry(queryResponseState);
        return queryResponseState;
    }

    public ReplicationState processUnicastresponse(ReplicationState queryResponseState) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processUnicastresponse:queryResponseState=" + queryResponseState);
        }
        String originalCommand = null;
        ReplicationResponseRepository.putEntry(queryResponseState, originalCommand);
        return queryResponseState;
    }

    public void repair(long repairStartTime) {
       if (!isRepairDuringFailure()) {
           return;
       }       
       repairServletTimers(repairStartTime);
       repairSipSessions(repairStartTime);
       repairSipApplicationSessions(repairStartTime);
    }    
   
    public void repair(long repairStartTime, boolean checkForStopping) {
        if (!isRepairDuringFailure()) {
            return;
        }        
        if(checkForStopping && ReplicationHealthChecker.isStopping()) {
            return;
        }
        repair(repairStartTime);
    }
   
    public void repairSipApplicationSessions(long repairStartTime) {   
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("SipTransactionPersistentManager>>repairSipApplicationSessions");                      
        }        

        if(ReplicationHealthChecker.isStopping()) {
            return;
        }

        Iterator it = applicationSessions.values().iterator();
        while (it.hasNext()) {
            SipApplicationSessionImpl session = (SipApplicationSessionImpl) it.next();
            //by virtue of being in the cache it is considered to
            //be not expired
            //but since invalidate is called before removal we must check
            if(session.isValid()
                && (session.getId() != null)
                && isSipApplicationSessionOlderThan(session, repairStartTime)          
                && session.lockBackground()) {
                try {
                    ((HASipApplicationSession)session).setReplicated(false);
                    ((HASipApplicationSession)session).setDirty(true, false);
                    saveSipApplicationSession(session);
                } catch (IOException ex) {
                    _logger.log(Level.WARNING,
                        "during repair unable to save SipApplicationSession:id = " + session.getId(),
                        ex);
                } finally {
                    session.unlockBackground();
                }                              
      }           
        }
    }
   
    protected boolean isSipApplicationSessionOlderThan(SipApplicationSessionImpl session, long aTime) {
        return (session.getLastAccessedTime() <= aTime);
    }
   
    public void repairSipSessions(long repairStartTime) {   
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("SipTransactionPersistentManager>>repairSipSessions");                      
        }        

        if(ReplicationHealthChecker.isStopping()) {
            return;
        }

        Iterator it = sipSessions.values().iterator();
        while (it.hasNext()) {
            SipSessionDialogImpl session = (SipSessionDialogImpl) it.next();
            //by virtue of being in the cache it is considered to
            //be not expired
            //but since invalidate is called before removal we must check           
            if(session.isValid()
                && (session.getId() != null)
                && isSipSessionOlderThan(session, repairStartTime)          
                && session.lockBackground()) {
                try {
                    ((HASipSession)session).setReplicated(false);
                    ((HASipSession)session).setDirty(true, false);
                    saveSipSession(session);
                } catch (IOException ex) {
                    _logger.log(Level.WARNING,
                        "during repair unable to save SipSession:id = " + session.getId(),
                        ex);
                } finally {
                    session.unlockBackground();
                }                              
      }           
        }
    }
   
    protected boolean isSipSessionOlderThan(SipSessionDialogImpl session, long aTime) {
        return (session.getLastAccessedTime() <= aTime);
    }
   
    public void repairServletTimers(long repairStartTime) {   
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("SipTransactionPersistentManager>>repairServletTimers");                      
        }        

        if(ReplicationHealthChecker.isStopping()) {
            return;
        }

        Iterator it = servletTimers.values().iterator();
        while (it.hasNext()) {
            ServletTimerImpl timer = (ServletTimerImpl)it.next();
            //by virtue of being in the cache it is considered to
            //be not expired          
            if(timer.getId() != null
                && timer.isPersistent()
                && isServletTimerOlderThan(timer, repairStartTime)
                && timer.lockBackground()) {
                try {
                    ((HAServletTimer)timer).setReplicated(false);
                    ((HAServletTimer)timer).setDirty(true, false);
                    saveServletTimer(timer);
                } catch (IOException ex) {
                    _logger.log(Level.WARNING,
                        "during repair unable to save ServletTimer:id = " + timer.getId(),
                        ex);
                } finally {
                    timer.unlockBackground();
                }
      }           
        }
    }
   
    protected boolean isServletTimerOlderThan(ServletTimerImpl timer, long aTime) {
        return (((HAServletTimer)timer).getInternalLastAccessedTime() <= aTime);
    }     
   
    public void respondToFailure(String failedInstanceName, boolean checkForStopping) {
        /*
        //only do timer wakeup if failedInstanceName was replicating
        //to us
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        String replicatedFromInstanceName
            = healthChecker.getReshapeReplicateFromInstanceName(failedInstanceName);
        //when third party SPI implementation in use then only former replica partner
        //responds otherwise all surviving instances each respond
        if(isThirdPartyBackingStoreInUse() && !failedInstanceName.equalsIgnoreCase(replicatedFromInstanceName)) {
            return;
        }

        if(isThirdPartyBackingStoreInUse()) {
            respondToFailureThirdPartySPI(failedInstanceName);
            return;
        }

        Iterator<String> results =
            (Iterator<String>) replicatedServletTimers.keys();
        while (results.hasNext()) {
            String timerId = (String) results.next();
            try {
                ServletTimerExtraParams eParam = deserializeServletTimerExtraParams(timerId);
                if (eParam != null && failedInstanceName.equals(eParam.getCurrentOwnerInstanceName())) {
                    activationHelper.registerServletTimerMigrationTask(eParam);
                }
            } catch (Exception ex) {
                _logger.log(Level.WARNING, "Error during deserialization", ex);
            }
        }
       
        //now do SipApplicationSessions
        Iterator<String> sasResults =
            (Iterator<String>) replicatedSipApplicationSessions.keys();
        while (sasResults.hasNext()) {
            String sasId = (String) sasResults.next();
            try {
                SipApplicationSessionExtraParams eParam
                    = deserializeSipApplicationSessionExtraParams(sasId);
    
                if (eParam != null && failedInstanceName.equals(eParam.getCurrentOwnerInstanceName())) {               
                    activationHelper.registerSipApplicationSessionMigrationTask(eParam);
                }
            } catch (Exception ex) {
                _logger.log(Level.WARNING, "Error during deserialization", ex);
            }
        }
         */       
    }
   
    void respondToFailureThirdPartySPI(String failedInstanceName) {
        BackingStore servletTimerBackingStore = this.getServletTimerBackingStore();
        ServletTimerExtraParams timerExtraParamCriteria
            = ServletTimerExtraParams.createSearchCriteria(
                    this, getApplicationId(), failedInstanceName);
        Collection<ServletTimerExtraParams> timerColl
            = servletTimerBackingStore.findByCriteria(null, timerExtraParamCriteria);
       
        Iterator<ServletTimerExtraParams> timerResults =
            (Iterator<ServletTimerExtraParams>) timerColl.iterator();
        while (timerResults.hasNext()) {
            ServletTimerExtraParams eParam = timerResults.next();
            if (failedInstanceName.equals(eParam.getCurrentOwnerInstanceName())) {
                activationHelper.registerServletTimerMigrationTask(eParam);
            }           
        }
       
        BackingStore sipApplicationSessionBackingStore
            = this.getSipApplicationSessionBackingStore();
        SipApplicationSessionExtraParams sasExtraParamCriteria
            = SipApplicationSessionExtraParams.createSearchCriteria(
                    this, getApplicationId(), failedInstanceName);
        Collection<SipApplicationSessionExtraParams> sasColl
            = sipApplicationSessionBackingStore.findByCriteria(null, sasExtraParamCriteria);
       
        Iterator<SipApplicationSessionExtraParams> sasResults =
            (Iterator<SipApplicationSessionExtraParams>) sasColl.iterator();
        while (sasResults.hasNext()) {
            SipApplicationSessionExtraParams eParam = sasResults.next();
            if (failedInstanceName.equals(eParam.getCurrentOwnerInstanceName())) {
                activationHelper.registerSipApplicationSessionMigrationTask(eParam);
            }           
        }        
    }
   
    boolean isThirdPartyBackingStoreInUse() {
        BackingStore sasBackingStore
            = getSipApplicationSessionBackingStore();
        return (!(sasBackingStore instanceof JxtaBackingStoreImpl));
    }

   
    /**
     * Gets the name of the instance.on which this session manager resides.
     *
     * @return The name of the instance on which this session manager
     * resides
     */
    String getInstanceName() {
        return instanceName;
    }
   
    // begin post join reconciliation

    /**
     * do reconciliation processing
     * used for both rolling upgrade and post network partition rejoin
     * @param waitTime the waitTime in seconds
     * @param ctx the RollingUpgradeContext
     */
    public void doPostJoinReconciliation(long waitTime, RollingUpgradeContext ctx) {
        long startTime = System.currentTimeMillis();
        if (_logger.isLoggable(Level.FINE)) {
            startTime = System.currentTimeMillis();
        }
        CountDownLatch doneSignal = new CountDownLatch(2);
        //do active cache reconciliation
        ReconcileActive reconcileActive
            = new ReconcileActive(this, waitTime, doneSignal, ctx);
        RollingUpgradeHandler.executeTask(reconcileActive);

        //trigger replica cache reconciliation
        TriggerReconcileReplica triggerReconcileReplica
            = new TriggerReconcileReplica(this, waitTime, doneSignal, ctx);
        RollingUpgradeHandler.executeTask(triggerReconcileReplica);

        try {
            doneSignal.await(waitTime, TimeUnit.SECONDS);
        } catch(InterruptedException ex) {
            ;
        } finally {
            if(doneSignal.getCount() != 0) {
                String errorMsg = "SipTransactionPersistentManager>>doPostJoinReconciliation timed out after " + waitTime + " seconds";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager doPostJoinReconciliation successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
                }
            }
        }
    }
    // end post join reconciliation
   
    // begin rolling upgrade related code
   
    public void doRollingUpgradePreShutdownProcessing(long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
        //do syncpoint save
        doSyncpointSave(waitTime, doneSignal, ctx);
    }

    public void doRollingUpgradePostStartupProcessing(String rollingUpgradeType, long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
        if(RollingUpgradeHandler.isFileBased(rollingUpgradeType)) {
            //do syncpoint load
            doSyncpointLoad(waitTime, doneSignal, ctx);
        } else {
            doMemoryLoad(waitTime, doneSignal, ctx);
        }
    }

    public void doRollingUpgradePostStartupReconciliationProcessing(long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
        //do post join reconciliation
        try {
            doPostJoinReconciliation(waitTime, ctx);
        } finally {
            doneSignal.countDown();
        }
    }

    void doSyncpointSave(long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
        try {
            if(this.isSkipRollingUpgradeBackupRestore()) {
                return;
            }
            SipFileSync syncStore = new SipFileSync((ReplicationManager)this);
            try {
                syncStore.save(waitTime, ctx);
            } catch (IOException ex) {
                ex.printStackTrace();
                String errorMsg = "SipTransactionPersistentManager>>doSyncPointSave IOException";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            }
        } finally {
            doneSignal.countDown();
        }
    }

    void doSyncpointLoad(long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
        try {
            if(this.isSkipRollingUpgradeBackupRestore()) {
                return;
            }
            SipFileSync syncStore = new SipFileSync((ReplicationManager)this);
            try {
                syncStore.load(waitTime, ctx);
                markActiveCacheAsSuspected(true);
            } catch (IOException ex) {
                String errorMsg = "SipTransactionPersistentManager>>doSyncPointLoad IOException";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } catch (ClassNotFoundException ex2) {
                String errorMsg = "SipTransactionPersistentManager>>doSyncPointLoad ClassNotFoundException";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            }
        } finally {
            doneSignal.countDown();
        }
    }

    void doMemoryLoad(long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
        try {
            if(this.isSkipRollingUpgradeBackupRestore()) {
                return;
            }
            SipMemorySync syncStore = new SipMemorySync((ReplicationManager)this);
            try {
                syncStore.load(waitTime, ctx);
                markActiveCacheAsSuspected(true);
            } catch (IOException ex) {
                String errorMsg = "SipTransactionPersistentManager>>doMemoryLoad IOException";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } catch (ClassNotFoundException ex2) {
                String errorMsg = "SipTransactionPersistentManager>>doMemoryLoad ClassNotFoundException";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            }
        } finally {
            doneSignal.countDown();
        }
    }

    void restoreSipApplicationSessionActiveCacheViaMemory(long waitTime, RollingUpgradeContext ctx) {
        triggerSipApplicationSessionActiveCacheRestoration(waitTime, ctx);
    }

    void restoreSipSessionActiveCacheViaMemory(long waitTime, RollingUpgradeContext ctx) {
        triggerSipSessionActiveCacheRestoration(waitTime, ctx);
    }

    void restoreServletTimerActiveCacheViaMemory(long waitTime, RollingUpgradeContext ctx) {
        triggerServletTimerActiveCacheRestoration(waitTime, ctx);
    }

    void restoreSipApplicationSessionReplicaCacheViaMemory(long waitTime, RollingUpgradeContext ctx) {
        triggerSipApplicationSessionReplicaCacheRestoration(waitTime, ctx);
    }

    void restoreSipSessionReplicaCacheViaMemory(long waitTime, RollingUpgradeContext ctx) {
        triggerSipSessionReplicaCacheRestoration(waitTime, ctx);
    }

    void restoreServletTimerReplicaCacheViaMemory(long waitTime, RollingUpgradeContext ctx) {
        triggerServletTimerReplicaCacheRestoration(waitTime, ctx);
    }

    public void triggerSipApplicationSessionActiveCacheRestoration(long waitTime, RollingUpgradeContext ctx) {
        long startTime = System.currentTimeMillis();
        int numberOfRespondants = RollingUpgradeUtil.getNumberOfExpectedRespondants();
        restoreSipApplicationSessionActiveCacheDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateTo partner(s) to do
        //active cache restoration
        ownedReplicaListsReceivedForSipApplicationSessionActiveCacheRestoration
            = new ConcurrentHashMap<String, ReplicationState>();
        doTriggerSipApplicationSessionActiveCacheRestoration(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());

        try {
            restoreSipApplicationSessionActiveCacheDoneSignal.await(waitTime, TimeUnit.SECONDS);
            processSipApplicationSessionActiveCacheRestorationResults(ownedReplicaListsReceivedForSipApplicationSessionActiveCacheRestoration);
        } catch(InterruptedException ex) {
            ;
        } finally {
            if(restoreSipApplicationSessionActiveCacheDoneSignal.getCount() != 0) {
                String errorMsg = "SipTransactionPersistentManager>>triggerSipApplicationSessionActiveCacheRestoration timed out after " + waitTime + " seconds";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerSipApplicationSessionActiveCacheRestoration successful after a wait: wait time = " + (System.currentTimeMillis() - startTime+ " active SipApplicationSessions restored: " + applicationSessions.size());
                }
            }
            ctx.addMessage(getApplicationId(), "Active cache restoration completed for SipApplicationSession. " +
                    ", Size of active cache = " + applicationSessions.size() +
                    ", Time taken (ms) = " + (System.currentTimeMillis()-startTime));

        }
    }

    protected void doTriggerSipApplicationSessionActiveCacheRestoration(boolean isInstanceLoadBalancedByCLB) {
        if(!isInstanceLoadBalancedByCLB) {
            //trigger replicateTo partner to do
            //active cache restoration
            ReplicationHealthChecker healthChecker
                = ReplicationHealthChecker.getInstance();
            String replicateToInstanceName = healthChecker.getReshapeReplicateToInstanceName(null, 0L);
            sendRollingUpgradeActiveCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RESTORATION_ADVISORY, replicateToInstanceName);
        } else {
            //trigger all partners to do
            //active cache restoration
            sendRollingUpgradeActiveCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RESTORATION_ADVISORY);
        }
    }

    protected void processSipApplicationSessionActiveCacheRestorationResults(ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForActiveCacheRestoration) {
        SipApplicationSessionStoreImpl store = getSingletonSipApplicationSessionStore();
        Collection<ReplicationState> ownedReplicasList = ownedReplicaListsReceivedForActiveCacheRestoration.values();
        Iterator<ReplicationState> it = ownedReplicasList.iterator();
        while(it.hasNext()) {
            ReplicationState nextOwnedListReplicationState = it.next();
            List<ReplicationState>nextOwnedListOfStates
                = (List<ReplicationState>)RollingUpgradeUtil.getObject(nextOwnedListReplicationState.getState());
            for(int i=0; i<nextOwnedListOfStates.size(); i++) {
                ReplicationState nextState = nextOwnedListOfStates.get(i);
                HASipApplicationSession nextSession = null;
                try {
                    nextSession = store.getSipApplicationSession(nextState);
                } catch (Exception ex) {}
                if(nextSession != null) {
                    this.addSipApplicationSession(nextSession);
                }
            }
        }
    }

    public void triggerSipApplicationSessionReplicaCacheRestoration(long waitTime, RollingUpgradeContext ctx) {
        long startTime =  System.currentTimeMillis();
       
        int numberOfRespondants = RollingUpgradeUtil.getNumberOfExpectedRespondants();
        restoreSipApplicationSessionReplicaCacheDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateFrom partner(s) to do
        //replica cache restoration
        ownedReplicaListsReceivedForSipApplicationSessionReplicaCacheRestoration
            = new ConcurrentHashMap<String, ReplicationState>();
        doTriggerSipApplicationSessionReplicaCacheRestoration(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());

        try {
            restoreSipApplicationSessionReplicaCacheDoneSignal.await(waitTime, TimeUnit.SECONDS);
            processSipApplicationSessionReplicaCacheRestorationResults(ownedReplicaListsReceivedForSipApplicationSessionReplicaCacheRestoration);
        } catch(InterruptedException ex) {
            ;
        } finally {
            if(restoreSipApplicationSessionReplicaCacheDoneSignal.getCount() != 0) {
                String errorMsg = "SipTransactionPersistentManager>>triggerSipApplicationSessionReplicaCacheRestoration timed out after " + waitTime + " seconds";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerSipApplicationSessionReplicaCacheRestoration successful after a wait: wait time = " + (System.currentTimeMillis() - startTime+ " replica SipApplicationSessions restored: " + getReplicatedSipApplicationSessions().getEntryCount());
                }
            }
            ctx.addMessage(getApplicationId(), "Replica cache restoration completed for SipApplicationSession. " +
                    ", Size of replica cache = " + getReplicatedSipApplicationSessions().getEntryCount() +
                    ", Time taken (ms) = " + (System.currentTimeMillis()-startTime));

        }
    }

    protected void doTriggerSipApplicationSessionReplicaCacheRestoration(boolean isInstanceLoadBalancedByCLB) {
        if(!isInstanceLoadBalancedByCLB) {
            //trigger replicateTo partner to do
            //replica cache restoration
            ReplicationHealthChecker healthChecker
                = ReplicationHealthChecker.getInstance();
            String replicateToInstanceName = healthChecker.getReshapeReplicateToInstanceName(null, 0L);
            sendRollingUpgradeReplicaCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_REPLICA_CACHE_RESTORATION_ADVISORY, replicateToInstanceName);
        } else {
            //trigger all partners to do
            //replica cache restoration
            sendRollingUpgradeReplicaCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_REPLICA_CACHE_RESTORATION_ADVISORY);
        }
    }

    protected void processSipApplicationSessionReplicaCacheRestorationResults(ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForReplicaCacheRestoration) {
        Collection<ReplicationState> ownedReplicasList = ownedReplicaListsReceivedForReplicaCacheRestoration.values();
        Iterator<ReplicationState> it = ownedReplicasList.iterator();
        while(it.hasNext()) {
            ReplicationState nextOwnedListReplicationState = it.next();
            List<ReplicationState>nextOwnedListOfStates
                = (List<ReplicationState>)RollingUpgradeUtil.getObject(nextOwnedListReplicationState.getState());           
            for(int i=0; i<nextOwnedListOfStates.size(); i++) {
                ReplicationState nextState = nextOwnedListOfStates.get(i);
                this.putInSipApplicationSessionReplicationCache(nextState);
            }
        }
    }

    public void triggerSipSessionActiveCacheRestoration(long waitTime, RollingUpgradeContext ctx) {
        long startTime =System.currentTimeMillis();
        int numberOfRespondants = RollingUpgradeUtil.getNumberOfExpectedRespondants();
        restoreSipSessionActiveCacheDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateTo partner(s) to do
        //active cache restoration
        ownedReplicaListsReceivedForSipSessionActiveCacheRestoration
            = new ConcurrentHashMap<String, ReplicationState>();
        doTriggerSipSessionActiveCacheRestoration(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());

        try {
            restoreSipSessionActiveCacheDoneSignal.await(waitTime, TimeUnit.SECONDS);
            processSipSessionActiveCacheRestorationResults(ownedReplicaListsReceivedForSipSessionActiveCacheRestoration);
        } catch(InterruptedException ex) {
            ;
        } finally {
            if(restoreSipSessionActiveCacheDoneSignal.getCount() != 0) {
                String errorMsg = "SipTransactionPersistentManager>>triggerSipSessionActiveCacheRestoration timed out after " + waitTime + " seconds";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerSipSessionActiveCacheRestoration successful after a wait: wait time = " + (System.currentTimeMillis() - startTime+ " active SipSessions restored: " + sipSessions.size());
                }
            }
            ctx.addMessage(getApplicationId(), "Active cache restoration completed for SipSession. " +
                    ", Size of active cache = " + sipSessions.size() +
                    ", Time taken (ms) = " + (System.currentTimeMillis()-startTime));

        }
    }

    protected void doTriggerSipSessionActiveCacheRestoration(boolean isInstanceLoadBalancedByCLB) {
        if(!isInstanceLoadBalancedByCLB) {
            //trigger replicateTo partner to do
            //active cache restoration
            ReplicationHealthChecker healthChecker
                = ReplicationHealthChecker.getInstance();
            String replicateToInstanceName = healthChecker.getReshapeReplicateToInstanceName(null, 0L);
            sendRollingUpgradeActiveCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_ACTIVE_CACHE_RESTORATION_ADVISORY, replicateToInstanceName);
        } else {
            //trigger all partners to do
            //active cache restoration
            sendRollingUpgradeActiveCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_ACTIVE_CACHE_RESTORATION_ADVISORY);
        }
    }

    protected void processSipSessionActiveCacheRestorationResults(ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForActiveCacheRestoration) {
        SipSessionStoreImpl store = getSingletonSipSessionStore();
        Collection<ReplicationState> ownedReplicasList = ownedReplicaListsReceivedForActiveCacheRestoration.values();
        Iterator<ReplicationState> it = ownedReplicasList.iterator();
        while(it.hasNext()) {
            ReplicationState nextOwnedListReplicationState = it.next();
            List<ReplicationState>nextOwnedListOfStates
                = (List<ReplicationState>)RollingUpgradeUtil.getObject(nextOwnedListReplicationState.getState());
            for(int i=0; i<nextOwnedListOfStates.size(); i++) {
                ReplicationState nextState = nextOwnedListOfStates.get(i);
                HASipSession nextSession = null;
                try {
                    nextSession = store.getSipSession(nextState);
                } catch (Exception ex) {}
                if(nextSession != null) {
                    this.addSipSession(nextSession);
                }
            }
        }
    }

    public void triggerSipSessionReplicaCacheRestoration(long waitTime, RollingUpgradeContext ctx) {
        long startTime = System.currentTimeMillis();
        int numberOfRespondants = RollingUpgradeUtil.getNumberOfExpectedRespondants();
        restoreSipSessionReplicaCacheDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateFrom partner(s) to do
        //replica cache restoration
        ownedReplicaListsReceivedForSipSessionReplicaCacheRestoration
            = new ConcurrentHashMap<String, ReplicationState>();
        doTriggerSipSessionReplicaCacheRestoration(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());

        try {
            restoreSipSessionReplicaCacheDoneSignal.await(waitTime, TimeUnit.SECONDS);
            processSipSessionReplicaCacheRestorationResults(ownedReplicaListsReceivedForSipSessionReplicaCacheRestoration);
        } catch(InterruptedException ex) {
            ;
        } finally {
            if(restoreSipSessionReplicaCacheDoneSignal.getCount() != 0) {
                String errorMsg = "SipTransactionPersistentManager>>triggerSipSessionReplicaCacheRestoration timed out after " + waitTime + " seconds";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerSipSessionReplicaCacheRestoration successful after a wait: wait time = " + (System.currentTimeMillis() - startTime) + " replica SipSessions restored: " + getReplicatedSipSessions().getEntryCount());
                }
            }
            ctx.addMessage(getApplicationId(), "Replica cache restoration completed for SipSession. " +
                    ", Size of replica cache = " + getReplicatedSipSessions().getEntryCount() +
                    ", Time taken (ms) = " + (System.currentTimeMillis()-startTime));

        }
    }

    protected void doTriggerSipSessionReplicaCacheRestoration(boolean isInstanceLoadBalancedByCLB) {
        if(!isInstanceLoadBalancedByCLB) {
            //trigger replicateTo partner to do
            //replica cache restoration
            ReplicationHealthChecker healthChecker
                = ReplicationHealthChecker.getInstance();
            String replicateToInstanceName = healthChecker.getReshapeReplicateToInstanceName(null, 0L);
            sendRollingUpgradeReplicaCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_REPLICA_CACHE_RESTORATION_ADVISORY, replicateToInstanceName);
        } else {
            //trigger all partners to do
            //replica cache restoration
            sendRollingUpgradeReplicaCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_REPLICA_CACHE_RESTORATION_ADVISORY);
        }
    }

    protected void processSipSessionReplicaCacheRestorationResults(ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForReplicaCacheRestoration) {
        Collection<ReplicationState> ownedReplicasList = ownedReplicaListsReceivedForReplicaCacheRestoration.values();
        Iterator<ReplicationState> it = ownedReplicasList.iterator();
        while(it.hasNext()) {
            ReplicationState nextOwnedListReplicationState = it.next();
            List<ReplicationState>nextOwnedListOfStates
                = (List<ReplicationState>)RollingUpgradeUtil.getObject(nextOwnedListReplicationState.getState());
            for(int i=0; i<nextOwnedListOfStates.size(); i++) {
                ReplicationState nextState = nextOwnedListOfStates.get(i);
                this.putInSipSessionReplicationCache(nextState);
            }
        }
    }

    public void triggerServletTimerActiveCacheRestoration(long waitTime, RollingUpgradeContext ctx) {
        long startTime =  System.currentTimeMillis();
        int numberOfRespondants = RollingUpgradeUtil.getNumberOfExpectedRespondants();
        restoreServletTimerActiveCacheDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateTo partner(s) to do
        //active cache restoration
        ownedReplicaListsReceivedForServletTimerActiveCacheRestoration
            = new ConcurrentHashMap<String, ReplicationState>();
        doTriggerServletTimerActiveCacheRestoration(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());

        try {
            restoreServletTimerActiveCacheDoneSignal.await(waitTime, TimeUnit.SECONDS);
            processServletTimerActiveCacheRestorationResults(ownedReplicaListsReceivedForServletTimerActiveCacheRestoration);
        } catch(InterruptedException ex) {
            ;
        } finally {
            if(restoreServletTimerActiveCacheDoneSignal.getCount() != 0) {
                String errorMsg = "SipTransactionPersistentManager>>triggerServletTimerActiveCacheRestoration timed out after " + waitTime + " seconds";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerServletTimerActiveCacheRestoration successful after a wait: wait time = " + (System.currentTimeMillis() - startTime) + " active ServletTimers restored: " + servletTimers.size());
                }
            }
            ctx.addMessage(getApplicationId(), "Active cache restoration completed for ServletTimer. " +
                    ", Size of active cache = " + servletTimers.size() +
                    ", Time taken (ms) = " + (System.currentTimeMillis()-startTime));

        }
    }

    protected void doTriggerServletTimerActiveCacheRestoration(boolean isInstanceLoadBalancedByCLB) {
        if(!isInstanceLoadBalancedByCLB) {
            //trigger replicateTo partner to do
            //active cache restoration
            ReplicationHealthChecker healthChecker
                = ReplicationHealthChecker.getInstance();
            String replicateToInstanceName = healthChecker.getReshapeReplicateToInstanceName(null, 0L);
            sendRollingUpgradeActiveCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_ACTIVE_CACHE_RESTORATION_ADVISORY, replicateToInstanceName);
        } else {
            //trigger all partners to do
            //active cache restoration
            sendRollingUpgradeActiveCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_ACTIVE_CACHE_RESTORATION_ADVISORY);
        }
    }

    protected void processServletTimerActiveCacheRestorationResults(ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForActiveCacheRestoration) {
        ServletTimerStoreImpl store = getSingletonServletTimerStore();
        Collection<ReplicationState> ownedReplicasList = ownedReplicaListsReceivedForActiveCacheRestoration.values();
        Iterator<ReplicationState> it = ownedReplicasList.iterator();
        while(it.hasNext()) {
            ReplicationState nextOwnedListReplicationState = it.next();
            List<ReplicationState>nextOwnedListOfStates
                = (List<ReplicationState>)RollingUpgradeUtil.getObject(nextOwnedListReplicationState.getState());
            for(int i=0; i<nextOwnedListOfStates.size(); i++) {
                ReplicationState nextState = nextOwnedListOfStates.get(i);
                HAServletTimer nextTimer = null;
                try {
                    nextTimer = store.getServletTimer(nextState);
                } catch (Exception ex) {}
                if(nextTimer != null) {
                    this.addServletTimer(nextTimer);
                }
            }
        }
    }

    public void triggerServletTimerReplicaCacheRestoration(long waitTime, RollingUpgradeContext ctx) {
        long startTime =System.currentTimeMillis();
        int numberOfRespondants = RollingUpgradeUtil.getNumberOfExpectedRespondants();
        restoreServletTimerReplicaCacheDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateFrom partner(s) to do
        //replica cache restoration
        ownedReplicaListsReceivedForServletTimerReplicaCacheRestoration
            = new ConcurrentHashMap<String, ReplicationState>();
        doTriggerServletTimerReplicaCacheRestoration(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());

        try {
            restoreServletTimerReplicaCacheDoneSignal.await(waitTime, TimeUnit.SECONDS);
            processServletTimerReplicaCacheRestorationResults(ownedReplicaListsReceivedForServletTimerReplicaCacheRestoration);
        } catch(InterruptedException ex) {
            ;
        } finally {
            if(restoreServletTimerReplicaCacheDoneSignal.getCount() != 0) {
                String errorMsg = "SipTransactionPersistentManager>>triggerServletTimerReplicaCacheRestoration timed out after " + waitTime + " seconds";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerServletTimerReplicaCacheRestoration successful after a wait: wait time = " + (System.currentTimeMillis() - startTime+ " replica ServletTimers restored: " + getReplicatedServletTimers().getEntryCount());
                }
            }
            ctx.addMessage(getApplicationId(), "Replica cache restoration completed for ServletTimer. " +
                    ", Size of replica cache = " + getReplicatedServletTimers().getEntryCount() +
                    ", Time taken (ms) = " + (System.currentTimeMillis()-startTime));

        }
    }

    protected void doTriggerServletTimerReplicaCacheRestoration(boolean isInstanceLoadBalancedByCLB) {
        if(!isInstanceLoadBalancedByCLB) {
            //trigger replicateTo partner to do
            //replica cache restoration
            ReplicationHealthChecker healthChecker
                = ReplicationHealthChecker.getInstance();
            String replicateToInstanceName = healthChecker.getReshapeReplicateToInstanceName(null, 0L);
            sendRollingUpgradeReplicaCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_REPLICA_CACHE_RESTORATION_ADVISORY, replicateToInstanceName);
        } else {
            //trigger all partners to do
            //replica cache restoration
            sendRollingUpgradeReplicaCacheRestorationAdvisory(MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_REPLICA_CACHE_RESTORATION_ADVISORY);
        }
    }

    protected void processServletTimerReplicaCacheRestorationResults(ConcurrentHashMap<String, ReplicationState> ownedReplicaListsReceivedForReplicaCacheRestoration) {
        Collection<ReplicationState> ownedReplicasList = ownedReplicaListsReceivedForReplicaCacheRestoration.values();
        Iterator<ReplicationState> it = ownedReplicasList.iterator();
        while(it.hasNext()) {
            ReplicationState nextOwnedListReplicationState = it.next();
            List<ReplicationState>nextOwnedListOfStates
                = (List<ReplicationState>)RollingUpgradeUtil.getObject(nextOwnedListReplicationState.getState());
            for(int i=0; i<nextOwnedListOfStates.size(); i++) {
                ReplicationState nextState = nextOwnedListOfStates.get(i);
                this.putInServletTimerReplicationCache(nextState);
            }
        }
    }
   
    void markActiveCacheAsSuspected(boolean value) {
        Iterator it = applicationSessions.values().iterator();
        while(it.hasNext()) {
            ((HASipApplicationSession)it.next()).setSuspect(value);
        }
        Iterator it2 = sipSessions.values().iterator();
        while(it2.hasNext()) {
            ((HASipSession)it2.next()).setSuspect(value);
        }
        Iterator it3 = servletTimers.values().iterator();
        while(it3.hasNext()) {
            ServletTimerImpl timer = (ServletTimerImpl)it3.next();
            if (timer.isPersistent()) {
                ((HAServletTimer) timer).setSuspect(value);
            }
        }       
    }   
   
    public void doActiveCacheReconciliation(long waitTime, RollingUpgradeContext ctx) {
        long startTime = System.currentTimeMillis();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("SipTransactionPersistentManager>>begin doActiveCacheReconciliation");
            startTime = System.currentTimeMillis();
        }
        this.setActiveCacheReconciliationOngoing(true);
        CountDownLatch reconcileActiveCacheDoneSignal = new CountDownLatch(3);

        ReconcileActiveSipApplicationSession reconcileActiveCacheSipApplicationSession
            = new ReconcileActiveSipApplicationSession(this, waitTime, reconcileActiveCacheDoneSignal, ctx);
        RollingUpgradeHandler.executeTask(reconcileActiveCacheSipApplicationSession);

        ReconcileActiveSipSession reconcileActiveCacheSipSession
            = new ReconcileActiveSipSession(this, waitTime, reconcileActiveCacheDoneSignal, ctx);
        RollingUpgradeHandler.executeTask(reconcileActiveCacheSipSession);

        ReconcileActiveServletTimer reconcileActiveCacheServletTimer
            = new ReconcileActiveServletTimer(this, waitTime, reconcileActiveCacheDoneSignal, ctx);
        RollingUpgradeHandler.executeTask(reconcileActiveCacheServletTimer);
        try {
            reconcileActiveCacheDoneSignal.await(waitTime, TimeUnit.SECONDS);
        } catch(InterruptedException ex) {
            ;
        } finally {
            if(reconcileActiveCacheDoneSignal.getCount() != 0) {
                String errorMsg = "SipTransactionPersistentManager>>doActiveCacheReconciliation timed out after " + waitTime + " seconds";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager>>doActiveCacheReconciliation successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
                }
            }
            this.setActiveCacheReconciliationOngoing(false);
        }
    }

    public void doSipApplicationSessionActiveCacheReconciliation(long waitTime, RollingUpgradeContext ctx) {
        reconcileSipApplicationSessionActiveCache(waitTime, ctx);
    }

    public ConcurrentHashMap<String, FederatedQueryListElement> triggerGetIdsForSipApplicationSessionActiveCacheReconciliation(long waitTime) {
        long startTime = System.currentTimeMillis();
        if (_logger.isLoggable(Level.FINE)) {
            startTime = System.currentTimeMillis();
        }
        //because sending to all instances
        int numberOfRespondants = ReplicationUtil.getNumberExpectedRespondants();
        getIdsForSipApplicationSessionActiveCacheReconciliationDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateTo partner(s) to
        //provide owned session ids list(s)
        ownedIdsForSipApplicationSessionActiveCacheReconciliation =
            new ConcurrentHashMap<String, ReplicationState>();       
        doTriggerGetIdsForSipApplicationSessionActiveCacheReconciliation(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());
        ConcurrentHashMap<String, FederatedQueryListElement> result = null;
        try {
            getIdsForSipApplicationSessionActiveCacheReconciliationDoneSignal.await(waitTime, TimeUnit.SECONDS);
            result = processCacheReconciliationResults(ownedIdsForSipApplicationSessionActiveCacheReconciliation);
        } catch(InterruptedException ex) {
            result = new ConcurrentHashMap<String, FederatedQueryListElement>();
        } finally {
            if(getIdsForSipApplicationSessionActiveCacheReconciliationDoneSignal.getCount() != 0) {
                _logger.log(Level.WARNING, "SipTransactionPersistentManager>>triggerGetIdsForSipApplicationSessionActiveCacheReconciliation timed out after "
                    + waitTime + " seconds" + " signalCount=" + getIdsForSipApplicationSessionActiveCacheReconciliationDoneSignal.getCount());
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerGetIdsForSipApplicationSessionActiveCacheReconciliation successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
                }
            }
            ownedIdsForSipApplicationSessionActiveCacheReconciliation = null;
        }
        return result;
    }

    protected void doTriggerGetIdsForSipApplicationSessionActiveCacheReconciliation(boolean isInstanceLoadBalancedByCLB) {
        //trigger all partners to do
        //active cache reconciliation
        sendRollingUpgradeGetIdsForSipApplicationSessionActiveCacheReconciliationAdvisory();
    }

    /**
     * broadcast a rolling upgrade getIds
     * for replica cache reconciliation advisory message
     *
     */
    protected void sendRollingUpgradeGetIdsForSipApplicationSessionActiveCacheReconciliationAdvisory() {
        //broadcast rolling upgrade getIds for replica cache reconciliation advisory
        RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RECONCILIATION_ADVISORY);
    }

    public void processRollingupgradegetidsforsipapplicationsessionactivecachereconciliationadvisory(ReplicationState replicationState) {
        String instanceName = getInstanceName();
        String owningInstanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforsipapplicationsessionactivecachereconciliationadvisory:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforsipapplicationsessionactivecachereconciliationadvisory:owningInstance=" + owningInstanceName);
        }
        List<FederatedQueryListElement> sipApplicationSessionIds = getSipApplicationSessionIds(owningInstanceName);
        sendReplicasList(sipApplicationSessionIds, owningInstanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RECONCILIATION_RESPONSE);
    }

    public void processRollingupgradegetidsforsipapplicationsessionactivecachereconciliationresponse(ReplicationState replicationState) {
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradegetidsforsipapplicationsessionactivecachereconciliationresponse received from " + instanceName);
        }
        ownedIdsForSipApplicationSessionActiveCacheReconciliation.putIfAbsent(instanceName, replicationState);
        getIdsForSipApplicationSessionActiveCacheReconciliationDoneSignal.countDown();
    }   

    public void doSipSessionActiveCacheReconciliation(long waitTime, RollingUpgradeContext ctx) {
        reconcileSipSessionActiveCache(waitTime, ctx);
    }

    public ConcurrentHashMap<String, FederatedQueryListElement> triggerGetIdsForSipSessionActiveCacheReconciliation(long waitTime) {
        long startTime = System.currentTimeMillis();
        if (_logger.isLoggable(Level.FINE)) {
            startTime = System.currentTimeMillis();
        }
        //because sending to all instances
        int numberOfRespondants = ReplicationUtil.getNumberExpectedRespondants();
        getIdsForSipSessionActiveCacheReconciliationDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateTo partner(s) to
        //provide owned session ids list(s)
        ownedIdsForSipSessionActiveCacheReconciliation = new ConcurrentHashMap<String, ReplicationState>();
        doTriggerGetIdsForSipSessionActiveCacheReconciliation(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());
        ConcurrentHashMap<String, FederatedQueryListElement> result = null;
        try {
            getIdsForSipSessionActiveCacheReconciliationDoneSignal.await(waitTime, TimeUnit.SECONDS);
            result = processCacheReconciliationResults(ownedIdsForSipSessionActiveCacheReconciliation);
        } catch(InterruptedException ex) {
            result = new ConcurrentHashMap<String, FederatedQueryListElement>();
        } finally {
            if(getIdsForSipSessionActiveCacheReconciliationDoneSignal.getCount() != 0) {
                _logger.log(Level.WARNING, "SipTransactionPersistentManager>>triggerGetIdsForSipSessionActiveCacheReconciliation timed out after "
                    + waitTime + " seconds");
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerGetIdsForSipSessionActiveCacheReconciliation successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
                }
            }
            ownedIdsForSipSessionActiveCacheReconciliation = null;
        }
        return result;
    }

    protected void doTriggerGetIdsForSipSessionActiveCacheReconciliation(boolean isInstanceLoadBalancedByCLB) {
        //trigger all partners to do
        //active cache reconciliation
        sendRollingUpgradeGetIdsForSipSessionActiveCacheReconciliationAdvisory();
    }

    /**
     * broadcast a rolling upgrade getIds
     * for replica cache reconciliation advisory message
     *
     */
    protected void sendRollingUpgradeGetIdsForSipSessionActiveCacheReconciliationAdvisory() {
        //broadcast rolling upgrade getIds for replica cache reconciliation advisory
        RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_ACTIVE_CACHE_RECONCILIATION_ADVISORY);
    }

    public void processRollingupgradegetidsforsipsessionactivecachereconciliationadvisory(ReplicationState replicationState) {
        String instanceName = getInstanceName();
        String owningInstanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforsipsessionactivecachereconciliationadvisory:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforsipsessionactivecachereconciliationadvisory:owningInstance=" + owningInstanceName);
        }
        List<FederatedQueryListElement> sipSessionIds = getSipSessionIds(owningInstanceName);
        sendReplicasList(sipSessionIds, owningInstanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_ACTIVE_CACHE_RECONCILIATION_RESPONSE);
    }

    public void processRollingupgradegetidsforsipsessionactivecachereconciliationresponse(ReplicationState replicationState) {
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradegetidsforsipsessionactivecachereconciliationresponse received from " + instanceName);
        }
        ownedIdsForSipSessionActiveCacheReconciliation.putIfAbsent(instanceName, replicationState);
        getIdsForSipSessionActiveCacheReconciliationDoneSignal.countDown();
    }   

    public void doServletTimerActiveCacheReconciliation(long waitTime, RollingUpgradeContext ctx) {
        reconcileServletTimerActiveCache(waitTime, ctx);
    }

    public ConcurrentHashMap<String, FederatedQueryListElement> triggerGetIdsForServletTimerActiveCacheReconciliation(long waitTime) {
        long startTime = 0L;
        if (_logger.isLoggable(Level.FINE)) {
            startTime = System.currentTimeMillis();
        }
        //because sending to all instances
        int numberOfRespondants = ReplicationUtil.getNumberExpectedRespondants();
        getIdsForServletTimerActiveCacheReconciliationDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateTo partner(s) to
        //provide owned session ids list(s)
        ownedIdsForServletTimerActiveCacheReconciliation =
            new ConcurrentHashMap<String, ReplicationState>();       
        doTriggerGetIdsForServletTimerActiveCacheReconciliation(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());
        ConcurrentHashMap<String, FederatedQueryListElement> result = null;
        try {
            getIdsForServletTimerActiveCacheReconciliationDoneSignal.await(waitTime, TimeUnit.SECONDS);
            result = processCacheReconciliationResults(ownedIdsForServletTimerActiveCacheReconciliation);
        } catch(InterruptedException ex) {
            result = new ConcurrentHashMap<String, FederatedQueryListElement>();
        } finally {
            if(getIdsForServletTimerActiveCacheReconciliationDoneSignal.getCount() != 0) {
                _logger.log(Level.WARNING, "SipTransactionPersistentManager>>triggerGetIdsForServletTimerActiveCacheReconciliation timed out after "
                    + waitTime + " seconds");
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerGetIdsForServletTimerActiveCacheReconciliation successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
                }
            }
            ownedIdsForServletTimerActiveCacheReconciliation = null;
        }
        return result;
    }

    protected void doTriggerGetIdsForServletTimerActiveCacheReconciliation(boolean isInstanceLoadBalancedByCLB) {
        //trigger all partners to do
        //active cache reconciliation
        sendRollingUpgradeGetIdsForServletTimerActiveCacheReconciliationAdvisory();
    }

    /**
     * broadcast a rolling upgrade getIds
     * for replica cache reconciliation advisory message
     *
     */
    protected void sendRollingUpgradeGetIdsForServletTimerActiveCacheReconciliationAdvisory() {
        //broadcast rolling upgrade getIds for replica cache reconciliation advisory
        RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_ACTIVE_CACHE_RECONCILIATION_ADVISORY);
    }

    public void processRollingupgradegetidsforservlettimeractivecachereconciliationadvisory(ReplicationState replicationState) {
        String instanceName = getInstanceName();
        String owningInstanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforservlettimeractivecachereconciliationadvisory:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforservlettimeractivecachereconciliationadvisory:owningInstance=" + owningInstanceName);
        }
        List<FederatedQueryListElement> servletTimerIds = getServletTimerIds(owningInstanceName);
        sendReplicasList(servletTimerIds, owningInstanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_ACTIVE_CACHE_RECONCILIATION_RESPONSE);
    }

    public void processRollingupgradegetidsforservlettimeractivecachereconciliationresponse(ReplicationState replicationState) {
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradegetidsforservlettimeractivecachereconciliationresponse received from " + instanceName);
        }
        ownedIdsForServletTimerActiveCacheReconciliation.putIfAbsent(instanceName, replicationState);
        getIdsForServletTimerActiveCacheReconciliationDoneSignal.countDown();
    }   
   
    // temporarily keep the migrated sessions until they successully reach the destination.
    ConcurrentHashMap<String, Set<String>> migratedSasIds =
            new ConcurrentHashMap<String, Set<String>>();
    ConcurrentHashMap<String, Set<String>> migratedSipSessionIds =
            new ConcurrentHashMap<String, Set<String>>();
    ConcurrentHashMap<String, Set<String>> migratedServletTimerIds =
            new ConcurrentHashMap<String, Set<String>>();

    public void processReconcilesasrequest(ReplicationState reconcileRequest) {
        Set<String> migratedSessionIds = RollingUpgradeUtil.processActiveCacheReconciliationRequest(reconcileRequest,
                getSingletonSipApplicationSessionStore(),
                RECONCILE_SAS_RESPONSE, isReplicationCompressionEnabled());
        migratedSasIds.put(reconcileRequest.getInstanceName(), migratedSessionIds);
    }

    public void processReconcilesasresponse(ReplicationState reconcileResponse) {
        reconciledActiveSases.put(reconcileResponse.getInstanceName(),
                reconcileResponse);
        activeSasReconcileSignal.get().countDown();
    }

    public void processReconcilesasreplicarequest(ReplicationState reconcileRequest) {
        RollingUpgradeUtil.processReplicaCacheReconciliationRequest(reconcileRequest, applicationSessions,
                RECONCILE_SAS_REPLICA_RESPONSE, isReplicationCompressionEnabled());
    }

    public void processReconcilesasreplicaresponse(ReplicationState reconcileResponse) {
        reconciledReplicaSases.put(reconcileResponse.getInstanceName(),
                reconcileResponse);
        replicaSasReconcileSignal.get().countDown();
    }

    public void processPostreconcilesasrequest(ReplicationState reconcileRequest) {
        boolean saveMigratedSessionToReplicaCache = EEPersistenceTypeResolver.REPLICATED_TYPE.
                equalsIgnoreCase(getPassedInPersistenceType());
        RollingUpgradeUtil.processPostActiveCacheReconciliationRequest(reconcileRequest,
                getSingletonSipApplicationSessionStore(),
                migratedSasIds.get(reconcileRequest.getInstanceName()),
                saveMigratedSessionToReplicaCache,
                POST_RECONCILE_SAS_RESPONSE);
    }

    public void processPostreconcilesasresponse(ReplicationState reconcileResponse) {
        remotelyLockedSases.put(reconcileResponse.getInstanceName(), reconcileResponse);
        postSasReconcileSignal.get().countDown();
    }

    // Sip Session related methods.
    public void processReconcilesipsessionrequest(ReplicationState reconcileRequest) {
        Set<String> migratedSessionIds = RollingUpgradeUtil.processActiveCacheReconciliationRequest(reconcileRequest,
                getSingletonSipSessionStore(),
                RECONCILE_SIPSESSION_RESPONSE, isReplicationCompressionEnabled());
        migratedSipSessionIds.put(reconcileRequest.getInstanceName(), migratedSessionIds);
    }

    public void processReconcilesipsessionresponse(ReplicationState reconcileResponse) {
        reconciledActiveSipSessions.put(reconcileResponse.getInstanceName(),
                reconcileResponse);
        activeSipSessionReconcileSignal.get().countDown();
    }

    public void processReconcilesipsessionreplicarequest(ReplicationState reconcileRequest) {
        RollingUpgradeUtil.processReplicaCacheReconciliationRequest(reconcileRequest, sipSessions,
                RECONCILE_SIPSESSION_REPLICA_RESPONSE, isReplicationCompressionEnabled());
    }

    public void processReconcilesipsessionreplicaresponse(ReplicationState reconcileResponse) {
        reconciledReplicaSipSessions.put(reconcileResponse.getInstanceName(),
                reconcileResponse);
        replicaSipSessionReconcileSignal.get().countDown();
    }


    public void processPostreconcilesipsessionrequest(ReplicationState reconcileRequest) {
        boolean saveMigratedSessionToReplicaCache = EEPersistenceTypeResolver.REPLICATED_TYPE.
                equalsIgnoreCase(getPassedInPersistenceType());
        RollingUpgradeUtil.processPostActiveCacheReconciliationRequest(reconcileRequest,
                getSingletonSipSessionStore(),
                migratedSipSessionIds.get(reconcileRequest.getInstanceName()),
                saveMigratedSessionToReplicaCache,
                POST_RECONCILE_SIPSESSION_RESPONSE);
    }

    public void processPostreconcilesipsessionresponse(ReplicationState reconcileResponse) {
        remotelyLockedSipSessions.put(reconcileResponse.getInstanceName(), reconcileResponse);
        postSipSessionReconcileSignal.get().countDown();
    }
   
    // Servlet timer related methods.
    public void processReconcileservlettimerrequest(ReplicationState reconcileRequest) {
        Set<String> migratedSessionIds = RollingUpgradeUtil.processActiveCacheReconciliationRequest(reconcileRequest,
                getSingletonServletTimerStore(),
                RECONCILE_SERVLETTIMER_RESPONSE, isReplicationCompressionEnabled());
        migratedServletTimerIds.put(reconcileRequest.getInstanceName(), migratedSessionIds);
    }

    public void processReconcileservlettimerresponse(ReplicationState reconcileResponse) {
        reconciledActiveServletTimers.put(reconcileResponse.getInstanceName(),
                reconcileResponse);
        activeServletTimerReconcileSignal.get().countDown();
    }

    public void processReconcileservlettimerreplicarequest(ReplicationState reconcileRequest) {
        RollingUpgradeUtil.processReplicaCacheReconciliationRequest(reconcileRequest, servletTimers,
                RECONCILE_SERVLETTIMER_REPLICA_RESPONSE, isReplicationCompressionEnabled());
    }

    public void processReconcileservlettimerreplicaresponse(ReplicationState reconcileResponse) {
        reconciledReplicaServletTimers.put(reconcileResponse.getInstanceName(),
                reconcileResponse);
        replicaServletTimerReconcileSignal.get().countDown();
    }


    public void processPostreconcileservlettimerrequest(ReplicationState reconcileRequest) {
        boolean saveMigratedSessionToReplicaCache = EEPersistenceTypeResolver.REPLICATED_TYPE.
                equalsIgnoreCase(getPassedInPersistenceType());
        RollingUpgradeUtil.processPostActiveCacheReconciliationRequest(reconcileRequest,
                getSingletonServletTimerStore(),
                migratedServletTimerIds.get(reconcileRequest.getInstanceName()),
                saveMigratedSessionToReplicaCache,
                POST_RECONCILE_SERVLETTIMER_RESPONSE);
    }

    public void processPostreconcileservlettimerresponse(ReplicationState reconcileResponse) {
        remotelyLockedServletTimers.put(reconcileResponse.getInstanceName(), reconcileResponse);
        postServletTimerReconcileSignal.get().countDown();
    }

    private void reconcileSipApplicationSessionActiveCache(long waitTime, RollingUpgradeContext ctx) {
        long startTime = System.currentTimeMillis();
        SipApplicationSessionStoreImpl storeImpl = getSingletonSipApplicationSessionStore();

        int reconciledSessions =  RollingUpgradeUtil.doActiveCacheReconciliation(
                storeImpl, RECONCILE_SAS_REQUEST, activeSasReconcileSignal,
                waitTime, reconciledActiveSases);
        long timeTaken = (System.currentTimeMillis() - startTime) / 1000;

        int suspectSessions = RollingUpgradeUtil.doPostActiveCacheReconcilation(
                storeImpl, POST_RECONCILE_SAS_REQUEST,
                postSasReconcileSignal, waitTime - timeTaken, remotelyLockedSases);
       
        timeTaken = System.currentTimeMillis() - startTime;
        ctx.addMessage(getApplicationId(), "Active cache reconciliation completed for SipApplicationSession. " +
                " No. of sessions reconciled = " + reconciledSessions +
                ", No. of sessions still in suspect = " + suspectSessions +
                ", Size of active cache = " + applicationSessions.size() +
                ", Size of expat = " + sasExpatIdsMap.size() + ", Time taken (ms) = " + timeTaken);
    }

    private void reconcileSipSessionActiveCache(long waitTime, RollingUpgradeContext ctx) {
        long startTime = System.currentTimeMillis();
        SipSessionStoreImpl storeImpl = getSingletonSipSessionStore();
        int reconciledSessions = RollingUpgradeUtil.doActiveCacheReconciliation(
                storeImpl, RECONCILE_SIPSESSION_REQUEST,
                activeSipSessionReconcileSignal, waitTime, reconciledActiveSipSessions);
        long timeTaken = (System.currentTimeMillis() - startTime)/1000;

        int suspectSessions = RollingUpgradeUtil.doPostActiveCacheReconcilation(
                storeImpl, POST_RECONCILE_SIPSESSION_REQUEST,
                postSipSessionReconcileSignal, waitTime - timeTaken, remotelyLockedSipSessions);

        timeTaken = System.currentTimeMillis() - startTime;
        ctx.addMessage(getApplicationId(), "Active cache reconciliation completed for SipSessions. " +
                " No. of sessions reconciled = " + reconciledSessions +
                ", No. of sessions still in suspect = " + suspectSessions +
                ", Size of active cache = " + sipSessions.size() +
            ", Size of expat = " + sipSessionExpatIdsMap.size() + ", Time taken (ms) = " + timeTaken);

    }

    private void reconcileServletTimerActiveCache(long waitTime, RollingUpgradeContext ctx) {
        long startTime = System.currentTimeMillis();
        ServletTimerStoreImpl storeImpl = getSingletonServletTimerStore();

        int reconciledSessions =  RollingUpgradeUtil.doActiveCacheReconciliation(
                storeImpl, RECONCILE_SERVLETTIMER_REQUEST, activeServletTimerReconcileSignal,
                waitTime, reconciledActiveServletTimers);
        long timeTaken = (System.currentTimeMillis() - startTime) / 1000;

        int suspectSessions = RollingUpgradeUtil.doPostActiveCacheReconcilation(
                storeImpl, POST_RECONCILE_SERVLETTIMER_REQUEST,
                postServletTimerReconcileSignal, waitTime - timeTaken, remotelyLockedServletTimers);

        timeTaken = System.currentTimeMillis() - startTime;
        ctx.addMessage(getApplicationId(), "Active cache reconciliation completed for ServletTimer. " +
                " No. of timers reconciled = " + reconciledSessions +
                ", No. of timers still in suspect = " + suspectSessions +
                ", Size of active cache = " + servletTimers.size() +
                ", Size of expat = " + servletTimerExpatIdsMap.size() + ", Time taken (ms) = " + timeTaken);
    }

    protected void doTriggerReplicaCacheReconciliation(long waitTime, boolean isInstanceLoadBalancedByCLB) {
        if(!isInstanceLoadBalancedByCLB) {
            //trigger replicateFrom partner to do
            //replica cache reconciliation
            ReplicationHealthChecker healthChecker
                = ReplicationHealthChecker.getInstance();
            String replicateFromInstanceName = healthChecker.getReshapeReplicateFromInstanceName();
            sendRollingUpgradeAdvisory(waitTime, replicateFromInstanceName);
        } else {
            //trigger all partners to do
            //replica cache reconciliation
            sendRollingUpgradeAdvisory(waitTime);
        }
    }

    public void triggerReplicaCacheReconciliation(long waitTime, RollingUpgradeContext ctx) {
        int numberOfRespondants = 1;
        if(ReplicationUtil.checkIsInstanceLoadBalancedByCLB()) {
            numberOfRespondants = ReplicationUtil.getNumberExpectedRespondants();
        }
        long startTime = System.currentTimeMillis();
        if (_logger.isLoggable(Level.FINE)) {
            startTime = System.currentTimeMillis();
        }
        reconcileReplicaCacheDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateFrom partner(s) to do
        //replica cache reconciliation
        doTriggerReplicaCacheReconciliation(waitTime, ReplicationUtil.checkIsInstanceLoadBalancedByCLB());

        try {
            reconcileReplicaCacheDoneSignal.await(waitTime, TimeUnit.SECONDS);
        } catch(InterruptedException ex) {
            ;
        } finally {
            if(reconcileReplicaCacheDoneSignal.getCount() != 0) {
                String errorMsg = "SipTransactionPersistentManager>>triggerReplicaCacheReconciliation timed out after " + waitTime + " seconds";
                ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerReplicaCacheReconciliation successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
                }
            }
        }
    }
   
    /**
     * reconcile the replica cache (of your replica partner)
     * query instance1 to get a list of replica id/version data elements
     * then do 2 iterations:
     * iterate over the query result:
     * if an id from this list does not exist in this active cache
     * issue a remove message & load acknowledgment
     * if an id exists and the versions match do nothing
     * if an id exists and the active version is > replica version,
     *   - do a save
     * iterate over the active cache
     * if an id from active cache does not exist in the replica list
     *   - do a save
     */
    public void doReplicaCacheReconciliation(long waitTime, RollingUpgradeContext ctx) {
        CountDownLatch reconcileReplicaCacheDoneSignal = new CountDownLatch(3);
        //cleanOutZombieReplicas();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("SipTransactionPersistentManager>>begin doReplicaCacheReconciliation");
        }
        ReconcileReplicaSipApplicationSession reconcileReplicaCacheSipApplicationSession
            = new ReconcileReplicaSipApplicationSession(this, waitTime, reconcileReplicaCacheDoneSignal, ctx);
        RollingUpgradeHandler.executeTask(reconcileReplicaCacheSipApplicationSession);

        ReconcileReplicaSipSession reconcileReplicaCacheSipSession
            = new ReconcileReplicaSipSession(this, waitTime, reconcileReplicaCacheDoneSignal, ctx);
        RollingUpgradeHandler.executeTask(reconcileReplicaCacheSipSession);

        ReconcileReplicaServletTimer reconcileReplicaCacheServletTimer
            = new ReconcileReplicaServletTimer(this, waitTime, reconcileReplicaCacheDoneSignal, ctx);
        RollingUpgradeHandler.executeTask(reconcileReplicaCacheServletTimer);
        try {
            reconcileReplicaCacheDoneSignal.await(waitTime, TimeUnit.SECONDS);
        } catch(InterruptedException ex) {

        } finally {
            if(reconcileReplicaCacheDoneSignal.getCount() != 0) {
                String errorMsg = "SipTransactionPersistentManager>>doReplicaCacheReconciliation timed out after " + waitTime + " seconds";
                _logger.log(Level.WARNING, errorMsg);
            }
        }
    }

    protected ConcurrentHashMap<String, FederatedQueryListElement> processCacheReconciliationResults(ConcurrentHashMap<String, ReplicationState> ownedIdsForReplicaCacheReconciliation) {
        ConcurrentHashMap<String, FederatedQueryListElement> result =
            new ConcurrentHashMap<String, FederatedQueryListElement>();
        Collection<ReplicationState> ownedReplicasList = ownedIdsForReplicaCacheReconciliation.values();
        Iterator<ReplicationState> it = ownedReplicasList.iterator();
        while(it.hasNext()) {
            ReplicationState nextOwnedListReplicationState = it.next();
            List<FederatedQueryListElement>nextOwnedListOfStates
                = (List<FederatedQueryListElement>)RollingUpgradeUtil.getObject(nextOwnedListReplicationState.getState());
            for(int i=0; i<nextOwnedListOfStates.size(); i++) {
                FederatedQueryListElement nextElement = nextOwnedListOfStates.get(i);
                String nextElementId = nextElement.getId();
                if(nextElementId != null) {
                    FederatedQueryListElement existingElement = result.get(nextElementId);
                    if(existingElement == null || existingElement.getVersion() < nextElement.getVersion()) {
                        result.put(nextElementId, nextElement);
                    }
                }
            }
        }
        return result;
    }    

    /**
     * reconcile the replica cache (of your replica partner)
     * query instance1 to get a list of replica id/version data elements
     * then do 2 iterations:
     * iterate over the query result:
     * if an id from this list does not exist in this active cache
     * issue a remove message & load acknowledgment
     * if an id exists and the versions match do nothing
     * if an id exists and the active version is > replica version,
     *   - do a save
     * iterate over the active cache
     * if an id from active cache does not exist in the replica list
     *   - do a save
     * @param waitTime the waitTime
     */
    void doSipApplicationSessionReplicaCacheReconciliation(long waitTime, RollingUpgradeContext ctx) {
        reconcileSipApplicationSessionReplicaCache(waitTime, ctx);
    }

    public ConcurrentHashMap<String, FederatedQueryListElement> triggerGetIdsForSipApplicationSessionReplicaCacheReconciliation(long waitTime) {
        long startTime = 0L;
        if (_logger.isLoggable(Level.FINE)) {
            startTime = System.currentTimeMillis();
        }
        //because sending to all instances
        int numberOfRespondants = ReplicationUtil.getNumberExpectedRespondants();
        getIdsForSipApplicationSessionReplicaCacheReconciliationDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateTo partner(s) to
        //provide owned session ids list(s)
        ownedIdsForSipApplicationSessionReplicaCacheReconciliation =
            new ConcurrentHashMap<String, ReplicationState>();       
        doTriggerGetIdsForSipApplicationSessionReplicaCacheReconciliation(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());
        ConcurrentHashMap<String, FederatedQueryListElement> result = null;
        try {
            getIdsForSipApplicationSessionReplicaCacheReconciliationDoneSignal.await(waitTime, TimeUnit.SECONDS);
            result = processCacheReconciliationResults(ownedIdsForSipApplicationSessionReplicaCacheReconciliation);
        } catch(InterruptedException ex) {
            result = new ConcurrentHashMap<String, FederatedQueryListElement>();
        } finally {
            if(getIdsForSipApplicationSessionReplicaCacheReconciliationDoneSignal.getCount() != 0) {
                _logger.log(Level.WARNING, "SipTransactionPersistentManager>>triggerGetIdsForSipApplicationSessionReplicaCacheReconciliation timed out after "
                    + waitTime + " seconds");
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerGetIdsForSipApplicationSessionReplicaCacheReconciliation successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
                }
            }
            ownedIdsForSipApplicationSessionReplicaCacheReconciliation = null;
        }
        return result;
    }

    protected void doTriggerGetIdsForSipApplicationSessionReplicaCacheReconciliation(boolean isInstanceLoadBalancedByCLB) {
        //trigger all partners to do
        //replica cache reconciliation
        sendRollingUpgradeGetIdsForSipApplicationSessionReplicaCacheReconciliationAdvisory();
    }

    /**
     * broadcast a rolling upgrade getIds
     * for replica cache reconciliation advisory message
     *
     */
    protected void sendRollingUpgradeGetIdsForSipApplicationSessionReplicaCacheReconciliationAdvisory() {
        //broadcast rolling upgrade getIds for replica cache reconciliation advisory
        RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_REPLICA_CACHE_RECONCILIATION_ADVISORY);
    }

    public void processRollingupgradegetidsforsipapplicationsessionreplicacachereconciliationadvisory(ReplicationState replicationState) {
        String instanceName = getInstanceName();
        String owningInstanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforsipapplicationsessionreplicacachereconciliationadvisory:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforsipapplicationsessionreplicacachereconciliationadvisory:owningInstance=" + owningInstanceName);
        }
        List<FederatedQueryListElement> sessionIds = null;
        if(!this.isThirdPartyBackingStoreInUse()) {
            sessionIds = getSipApplicationSessionIds(owningInstanceName);
        } else {
            sessionIds = getSipApplicationSessionIdsThirdPartySPI(owningInstanceName);
        }
        sendReplicasList(sessionIds, owningInstanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_APPLICATION_SESSION_REPLICA_CACHE_RECONCILIATION_RESPONSE);
    }

    public void processRollingupgradegetidsforsipapplicationsessionreplicacachereconciliationresponse(ReplicationState replicationState) {
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradegetidsforsipapplicationsessionreplicacachereconciliationresponse received from " + instanceName);
        }
        ownedIdsForSipApplicationSessionReplicaCacheReconciliation.putIfAbsent(instanceName, replicationState);
        getIdsForSipApplicationSessionReplicaCacheReconciliationDoneSignal.countDown();
    }   

    /**
     * reconcile the replica cache (of your replica partner)
     * query instance1 to get a list of replica id/version data elements
     * then do 2 iterations:
     * iterate over the query result:
     * if an id from this list does not exist in this active cache
     * issue a remove message & load acknowledgment
     * if an id exists and the versions match do nothing
     * if an id exists and the active version is > replica version,
     *   - do a save
     * iterate over the active cache
     * if an id from active cache does not exist in the replica list
     *   - do a save
     * @param waitTime the waitTime
     */
    void doSipSessionReplicaCacheReconciliation(long waitTime, RollingUpgradeContext ctx) {
        reconcileSipSessionReplicaCache(waitTime, ctx);
    }

    public ConcurrentHashMap<String, FederatedQueryListElement> triggerGetIdsForSipSessionReplicaCacheReconciliation(long waitTime) {
        long startTime = 0L;
        if (_logger.isLoggable(Level.FINE)) {
            startTime = System.currentTimeMillis();
        }
        //because sending to all instances
        int numberOfRespondants = ReplicationUtil.getNumberExpectedRespondants();
        getIdsForSipSessionReplicaCacheReconciliationDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateTo partner(s) to
        //provide owned session ids list(s)
        ownedIdsForSipSessionReplicaCacheReconciliation
            = new ConcurrentHashMap<String, ReplicationState>();       
        doTriggerGetIdsForSipSessionReplicaCacheReconciliation(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());
        ConcurrentHashMap<String, FederatedQueryListElement> result = null;
        try {
            getIdsForSipSessionReplicaCacheReconciliationDoneSignal.await(waitTime, TimeUnit.SECONDS);
            result = processCacheReconciliationResults(ownedIdsForSipSessionReplicaCacheReconciliation);
        } catch(InterruptedException ex) {
            result = new ConcurrentHashMap<String, FederatedQueryListElement>();
        } finally {
            if(getIdsForSipSessionReplicaCacheReconciliationDoneSignal.getCount() != 0) {
                _logger.log(Level.WARNING, "SipTransactionPersistentManager>>triggerGetIdsForSipSessionReplicaCacheReconciliation timed out after "
                    + waitTime + " seconds");
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerGetIdsForSipSessionReplicaCacheReconciliation successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
                }
            }
            ownedIdsForSipSessionReplicaCacheReconciliation = null;
        }
        return result;
    }

    protected void doTriggerGetIdsForSipSessionReplicaCacheReconciliation(boolean isInstanceLoadBalancedByCLB) {
        //trigger all partners to do
        //replica cache reconciliation
        sendRollingUpgradeGetIdsForSipSessionReplicaCacheReconciliationAdvisory();
    }

    /**
     * broadcast a rolling upgrade getIds
     * for replica cache reconciliation advisory message
     *
     */
    protected void sendRollingUpgradeGetIdsForSipSessionReplicaCacheReconciliationAdvisory() {
        //broadcast rolling upgrade getIds for replica cache reconciliation advisory
        RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_REPLICA_CACHE_RECONCILIATION_ADVISORY);
    }

    public void processRollingupgradegetidsforsipsessionreplicacachereconciliationadvisory(ReplicationState replicationState) {
        String instanceName = getInstanceName();
        String owningInstanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforsipsessionreplicacachereconciliationadvisory:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforsipsessionreplicacachereconciliationadvisory:owningInstance=" + owningInstanceName);
        }
        List<FederatedQueryListElement> sessionIds = null;
        if(!this.isThirdPartyBackingStoreInUse()) {
            sessionIds = getSipSessionIds(owningInstanceName);
        } else {
            sessionIds = getSipSessionIdsThirdPartySPI(owningInstanceName);
        }
        sendReplicasList(sessionIds, owningInstanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SIP_SESSION_REPLICA_CACHE_RECONCILIATION_RESPONSE);
    }

    public void processRollingupgradegetidsforsipsessionreplicacachereconciliationresponse(ReplicationState replicationState) {
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradegetidsforsipsessionreplicacachereconciliationresponse received from " + instanceName);
        }
        ownedIdsForSipSessionReplicaCacheReconciliation.putIfAbsent(instanceName, replicationState);
        getIdsForSipSessionReplicaCacheReconciliationDoneSignal.countDown();
    }   

    /**
     * reconcile the replica cache (of your replica partner)
     * query instance1 to get a list of replica id/version data elements
     * then do 2 iterations:
     * iterate over the query result:
     * if an id from this list does not exist in this active cache
     * issue a remove message & load acknowledgment
     * if an id exists and the versions match do nothing
     * if an id exists and the active version is > replica version,
     *   - do a save
     * iterate over the active cache
     * if an id from active cache does not exist in the replica list
     *   - do a save
     * @param waitTime the waitTime
     */
    void doServletTimerReplicaCacheReconciliation(long waitTime, RollingUpgradeContext ctx) {
        reconcileServletTimerReplicaCache(waitTime, ctx);
    }

    public ConcurrentHashMap<String, FederatedQueryListElement> triggerGetIdsForServletTimerReplicaCacheReconciliation(long waitTime) {
        long startTime = 0L;
        if (_logger.isLoggable(Level.FINE)) {
            startTime = System.currentTimeMillis();
        }
        //because sending to all instances
        int numberOfRespondants = ReplicationUtil.getNumberExpectedRespondants();
        getIdsForServletTimerReplicaCacheReconciliationDoneSignal = new CountDownLatch(numberOfRespondants);
        //trigger replicateTo partner(s) to
        //provide owned session ids list(s)
        ownedIdsForServletTimerReplicaCacheReconciliation
            = new ConcurrentHashMap<String, ReplicationState>();       
        doTriggerGetIdsForServletTimerReplicaCacheReconciliation(ReplicationUtil.checkIsInstanceLoadBalancedByCLB());
        ConcurrentHashMap<String, FederatedQueryListElement> result = null;
        try {
            getIdsForServletTimerReplicaCacheReconciliationDoneSignal.await(waitTime, TimeUnit.SECONDS);
            result = processCacheReconciliationResults(ownedIdsForServletTimerReplicaCacheReconciliation);
        } catch(InterruptedException ex) {
            result = new ConcurrentHashMap<String, FederatedQueryListElement>();
        } finally {
            if(getIdsForServletTimerReplicaCacheReconciliationDoneSignal.getCount() != 0) {
                _logger.log(Level.WARNING, "SipTransactionPersistentManager>>triggerGetIdsForServletTimerReplicaCacheReconciliation timed out after "
                    + waitTime + " seconds");
            } else {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("SipTransactionPersistentManager triggerGetIdsForServletTimerReplicaCacheReconciliation successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
                }
            }
            ownedIdsForServletTimerReplicaCacheReconciliation = null;
        }
        return result;
    }

    protected void doTriggerGetIdsForServletTimerReplicaCacheReconciliation(boolean isInstanceLoadBalancedByCLB) {
        //trigger all partners to do
        //replica cache reconciliation
        sendRollingUpgradeGetIdsForServletTimerReplicaCacheReconciliationAdvisory();
    }

    /**
     * broadcast a rolling upgrade getIds
     * for replica cache reconciliation advisory message
     *
     */
    protected void sendRollingUpgradeGetIdsForServletTimerReplicaCacheReconciliationAdvisory() {
        //broadcast rolling upgrade getIds for replica cache reconciliation advisory
        RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_REPLICA_CACHE_RECONCILIATION_ADVISORY);
    }

    public void processRollingupgradegetidsforservlettimerreplicacachereconciliationadvisory(ReplicationState replicationState) {
        String instanceName = getInstanceName();
        String owningInstanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforservlettimerreplicacachereconciliationadvisory:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processRollingupgradegetidsforservlettimerreplicacachereconciliationadvisory:owningInstance=" + owningInstanceName);
        }
        List<FederatedQueryListElement> servletTimerIds = null;
        if(!this.isThirdPartyBackingStoreInUse()) {
            servletTimerIds = getServletTimerIds(owningInstanceName);
        } else {
            servletTimerIds = getServletTimerIdsThirdPartySPI(owningInstanceName);
        }
        sendReplicasList(servletTimerIds, owningInstanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_SERVLET_TIMER_REPLICA_CACHE_RECONCILIATION_RESPONSE);
    }

    public void processRollingupgradegetidsforservlettimerreplicacachereconciliationresponse(ReplicationState replicationState) {
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradegetidsforservlettimerreplicacachereconciliationresponse received from " + instanceName);
        }
        ownedIdsForServletTimerReplicaCacheReconciliation.putIfAbsent(instanceName, replicationState);
        getIdsForServletTimerReplicaCacheReconciliationDoneSignal.countDown();
    }   
   
    void cleanOutZombieReplicas() {
        //FIXME for now issue load acknowledgement for each
        //active cache entry
        //this is functionally correct but not optimal
        //solution will be to improve query for replica
        //ids to track the source instance and then only
        //issue load acks to those ids that are not from
        //our replicate to partner
        cleanOutZombieSipApplicationSessionReplicas();
        cleanOutZombieSipSessionReplicas();
        cleanOutZombieServletTimerReplicas();
    }

    void cleanOutZombieSipApplicationSessionReplicas() {
        HASipApplicationSession sas = null;
        Iterator it = applicationSessions.values().iterator();
        while(it.hasNext()) {
            sas = (HASipApplicationSession)it.next();
            String sasId = sas.getId();
            long version = sas.getVersion();
            this.sendLoadAcknowledgement(sasId, version, MESSAGE_BROADCAST_LOAD_RECEIVED_SAS, sas.getBeKey());
        }
    }

    void cleanOutZombieSipSessionReplicas() {
        HASipSession ss = null;
        Iterator it = sipSessions.values().iterator();
        while(it.hasNext()) {
            ss = (HASipSession)it.next();
            String ssId = ss.getId();
            long version = ss.getVersion();
            String beKey = null;
            String sasId = ss.getParentSASId();
            if(sasId != null) {
                beKey = SipApplicationSessionUtil.getSipApplicationKey(sasId);
            }
            this.sendLoadAcknowledgement(ssId, version, MESSAGE_BROADCAST_LOAD_RECEIVED_SIP_SESSION, beKey);
        }
    }

    void cleanOutZombieServletTimerReplicas() {
        HAServletTimer st = null;
        Iterator it = servletTimers.values().iterator();
        while(it.hasNext()) {
            st = (HAServletTimer)it.next();
            if (!st.isPersistent()) {
                continue;
            }
            String stId = st.getId();
            long version = st.getVersion();
            String beKey = null;
            String sasId = st.getParentSASId();
            if(sasId != null) {
                beKey = SipApplicationSessionUtil.getSipApplicationKey(sasId);
            }
            this.sendLoadAcknowledgement(stId, version, MESSAGE_BROADCAST_LOAD_RECEIVED_SERVLET_TIMER, beKey);
        }
    }
   
    private void reconcileSipApplicationSessionReplicaCache(long waitTime, RollingUpgradeContext ctx) {
        long startTime = System.currentTimeMillis();
        SipApplicationSessionStoreImpl storeImpl = getSingletonSipApplicationSessionStore();
        int sessionsReconciled = RollingUpgradeUtil.doReplicaCacheReconciliation(
                storeImpl, RECONCILE_SAS_REPLICA_REQUEST,
                replicaSasReconcileSignal, waitTime, reconciledReplicaSases);
        long timeTaken = System.currentTimeMillis() - startTime;
        ctx.addMessage(getApplicationId(), "Replica cache reconciliation completed for SipApplicationSession. " +
                " No of sessions reconciled = " + sessionsReconciled +
                ", Size of replica cache = " + getReplicatedSipApplicationSessions().getEntryCount() +
                ", Time taken (ms) = " + timeTaken);

    }
   
    private void reconcileSipSessionReplicaCache(long waitTime, RollingUpgradeContext ctx) {
        long startTime = System.currentTimeMillis();
        SipSessionStoreImpl storeImpl = getSingletonSipSessionStore();
        int sessionsReconciled = RollingUpgradeUtil.doReplicaCacheReconciliation(
                storeImpl, RECONCILE_SIPSESSION_REPLICA_REQUEST,
                replicaSipSessionReconcileSignal, waitTime, reconciledReplicaSipSessions);
        long timeTaken = System.currentTimeMillis() - startTime;
        ctx.addMessage(getApplicationId(), "Replica cache reconciliation completed for SipSession. " +
                " No of sessions reconciled = " + sessionsReconciled +
                ", Size of replica cache = " + getReplicatedSipApplicationSessions().getEntryCount() +
                ", Time taken (ms) = " + timeTaken);
    }
   
    private void reconcileServletTimerReplicaCache(long waitTime, RollingUpgradeContext ctx) {
        long startTime = System.currentTimeMillis();
        ServletTimerStoreImpl storeImpl = getSingletonServletTimerStore();
        int sessionsReconciled = RollingUpgradeUtil.doReplicaCacheReconciliation(
                storeImpl, RECONCILE_SERVLETTIMER_REPLICA_REQUEST,
                replicaServletTimerReconcileSignal, waitTime, reconciledReplicaServletTimers);
        long timeTaken = System.currentTimeMillis() - startTime;
        ctx.addMessage(getApplicationId(), "Replica cache reconciliation completed for ServletTimer. " +
                " No of timers reconciled = " + sessionsReconciled +
                ", Size of replica cache = " + getReplicatedServletTimers().getEntryCount() +
                ", Time taken (ms) = " + timeTaken);
    }

   /**
    * send a load acknowledgement
    *
    * @param state
    * @param beKey
    */
    protected void sendLoadAcknowledgement(ReplicationState state, String beKey) {
        SipApplicationSessionStoreImpl store = null;
        try {
            store = getSipApplicationSessionStore();
            if (store != null) {
                store.sendLoadAcknowledgement(state, beKey);
            }
        }
        finally {
            this.putSipApplicationSessionStore(store);
        }
    }

   protected void sendUnicastLoadAcknowledgementSAS(String id, String instance, String bekey) {
        SipApplicationSessionStoreImpl store = null;
        try {
            store = getSipApplicationSessionStore();
            if (store != null) {
                store.sendUnicastLoadAcknowledgement(id, instance, bekey);
            }
        }
        finally {
            this.putSipApplicationSessionStore(store);
        }
    }

    void sendSasLoadAcks(String instance, HashSet<String> ids) {
        SipApplicationSessionStoreImpl store = null;
        try {
            store = getSipApplicationSessionStore();
            if (store != null) {
                store.sendLoadAcks(instance, ids);
            }
        }
        finally {
            this.putSipApplicationSessionStore(store);
        }

    }

   protected void sendUnicastLoadAcknowledgementST(String id, String instance, String bekey) {
        ServletTimerStoreImpl store = null;
        try {
            store = getServletTimerStore();
            if (store != null) {
                store.sendUnicastLoadAcknowledgement(id, instance, bekey);
            }
        }
        finally {
            putServletTimerStore(store);
        }
    }

    protected void sendLoadAcknowledgement(String id, long version, String command, String beKey) {
        JxtaReplicationSender sender
            = JxtaReplicationSender.createInstance();
        ReplicationState loadReceivedState =
            ReplicationState.createBroadcastLoadReceivedState(MODE_SIP, id, this.getApplicationId(), version, getInstanceName(), command);
        if ((beKey != null) && replicationUtil.isInstanceLoadBalancedByCLB()){
            loadReceivedState.setProperty(ReplicationState.IGNORE_REMOVE_INSTANCE_NAME,
                replicationUtil.getFailoverServerInstanceForBeKey(beKey));
        } else {
            ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
            String currentReplicaPartner = healthChecker.getCurrentPartnerInstanceName();
                loadReceivedState.setProperty(ReplicationState.IGNORE_REMOVE_INSTANCE_NAME,
                currentReplicaPartner);
        }
        sender.sendBroadcastQuery(loadReceivedState);
    }
   
    protected void readSipApplicationSessions(ObjectInputStream ois)
        throws ClassNotFoundException, IOException {
        int count = ois.readInt();
        for(int i=0; i<count; i++) {
            HASipApplicationSession nextSas = (HASipApplicationSession)ois.readObject();
            applicationSessions.put(nextSas.getId(), nextSas);
        }
    }   
   
    protected void readReplicatedSipApplicationSessionUpdates(ObjectInputStream ois)
        throws ClassNotFoundException, IOException {
        sipApplicationSessionReplicaCache.readReplicatedSessionUpdates(ois);
    }
   
    protected void readSipSessions(ObjectInputStream ois)
        throws ClassNotFoundException, IOException {
        int count = ois.readInt();
        for(int i=0; i<count; i++) {
            HASipSession nextSipSession = (HASipSession)ois.readObject();
            sipSessions.put(nextSipSession.getId(), nextSipSession);
        }
    }   
   
    protected void readReplicatedSipSessionUpdates(ObjectInputStream ois)
        throws ClassNotFoundException, IOException {
        sipSessionReplicaCache.readReplicatedSessionUpdates(ois);
   
   
    protected void readServletTimers(ObjectInputStream ois)
        throws ClassNotFoundException, IOException {
        int count = ois.readInt();
        for(int i=0; i<count; i++) {
            HAServletTimer nextServletTimer = (HAServletTimer)ois.readObject();
            servletTimers.put(nextServletTimer.getId(), nextServletTimer);
        }
    }   
   
    protected void readReplicatedServletTimerUpdates(ObjectInputStream ois)
        throws ClassNotFoundException, IOException {
        servletTimerReplicaCache.readReplicatedSessionUpdates(ois);
    }     
   
    protected void writeSipApplicationSessions(ObjectOutputStream oos)
        throws IOException {
        ReplicationUtil.writeHashMap((AbstractMap)applicationSessions, oos);
    }    
   
    protected void writeReplicatedSipApplicationSessionUpdates(ObjectOutputStream oos)
        throws IOException {
        sipApplicationSessionReplicaCache.writeReplicatedSessionUpdates(oos);
   
   
    protected void writeSipSessions(ObjectOutputStream oos)
        throws IOException {
        ReplicationUtil.writeHashMap((AbstractMap)sipSessions, oos);
    }    
   
    protected void writeReplicatedSipSessionUpdates(ObjectOutputStream oos)
        throws IOException {
        sipSessionReplicaCache.writeReplicatedSessionUpdates(oos);
    }
   
    protected void writeServletTimers(ObjectOutputStream oos)
        throws IOException {
        ReplicationUtil.writeHashMap((AbstractMap)servletTimers, oos);
    }    
   
    protected void writeReplicatedServletTimerUpdates(ObjectOutputStream oos)
        throws IOException {
        servletTimerReplicaCache.writeReplicatedSessionUpdates(oos);
    }

    public HashSet<ExpatListElement> getExpatListFor(String instanceName,
                                                     String command) {
        boolean isRemoteInstance = !getInstanceName().equals(instanceName);
        if (MESSAGE_BROADCAST_EXPAT_QUERY_SAS.equals(command)) {
            return isRemoteInstance ? getSASExpatIdsFromActive(instanceName)
                    : new HashSet<ExpatListElement>();
//            return getSASExpatIds(instanceName, isRemoteInstance);
        }
        if (MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION.equals(command)) {
            return isRemoteInstance ? getSipSessionExpatIdsFromActive(instanceName)
                    : new HashSet<ExpatListElement>();
//            return getSipSessionExpatIds(instanceName, isRemoteInstance);
        }
        if (MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER.equals(command)) {
            return isRemoteInstance ? getServletTimerExpatIdsFromActive(instanceName)
                    : new HashSet<ExpatListElement>();
//            return getServletTimerExpatIds(instanceName, isRemoteInstance);
        }

        /**
         * Added on behalf of __synchronizeKeys
         */
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SAS_REPLICA.equals(command)) {
            return getSASExpatIdsFromReplica(instanceName);
        }
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION_REPLICA.equals(command)) {
            return getSipSessionExpatIdsFromReplica(instanceName);
        }
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER_REPLICA.equals(command)) {
            return getServletTimerExpatIdsFromReplica(instanceName);
        }
        throw new IllegalArgumentException("Invalid command " + command);
    }

    public void getExpatLists(String command, ExpatListQueryResults result) {
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SAS.equals(command)) {
//            getAllSASExpatIds(result);
            getSASExpatIdsFromActive(result);
        } else if(MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION.equals(command)) {
//            getAllSipSessionExpatIds(result);
            getSipSessionExpatIdsFromActive(result);
        } else if(MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER.equals(command)) {
//            getAllServletTimerExpatIds(result);
            getServletTimerExpatIdsFromActive(result);
        } else if(MESSAGE_BROADCAST_EXPAT_QUERY_SAS_REPLICA.equals(command)) {
            getSASExpatIdsFromReplica(result);
        } else if(MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION_REPLICA.equals(command)) {
            getSipSessionExpatIdsFromReplica(result);
        } else if(MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER_REPLICA.equals(command)) {
            getServletTimerExpatIdsFromReplica(result);
        } else {
            throw new IllegalArgumentException("Invalid command " + command);
        }
    }

    // TODO :: since there is no pruning done in this method, rename it to getCurrentExpatList
    public HashMap<String, ExpatListElement> pruneExpatList(String command) {
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SAS.equals(command)) {
            // don't prune, otherwise multiple failure + restart with
            // load-factor < 1 will not work. Until load-factor becomes 1,
            // the requests will continue to land in the earlier instance. So,
            // the expat elements are necessary until then.
            return sasExpatIdsMap;
        }
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION.equals(command)) {
            // TODO :: how to prune???
            return sipSessionExpatIdsMap;
        }
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER.equals(command)) {
            // TODO :: how to prune???
            return servletTimerExpatIdsMap;
        }
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SAS_REPLICA.equals(command) ||
                MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION_REPLICA.equals(command) ||
                MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER_REPLICA.equals(command)) {
            return new HashMap<String, ExpatListElement>();
        }
        throw new IllegalArgumentException("Invalid command " + command);
    }
   
    public String getExpatPushCommandFor(String expatQueryCommand) {
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SAS.equals(expatQueryCommand)) {
            return MESSAGE_BROADCAST_EXPAT_RECEIVE_SAS;
        }
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION.equals(expatQueryCommand)) {
            return MESSAGE_BROADCAST_EXPAT_RECEIVE_SIP_SESSION;
        }
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER.equals(expatQueryCommand)) {
            return MESSAGE_BROADCAST_EXPAT_RECEIVE_SERVLET_TIMER;
        }
        /**
         * Added on behalf of __synchronizeKeys implementation
         */
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SAS_REPLICA.equals(expatQueryCommand)) {
            return MESSAGE_BROADCAST_EXPAT_RECEIVE_SAS_REPLICA;
        }
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SIP_SESSION_REPLICA.equals(expatQueryCommand)) {
            return MESSAGE_BROADCAST_EXPAT_RECEIVE_SIP_SESSION_REPLICA;
        }
        if(MESSAGE_BROADCAST_EXPAT_QUERY_SERVLET_TIMER_REPLICA.equals(expatQueryCommand)) {
            return MESSAGE_BROADCAST_EXPAT_RECEIVE_SERVLET_TIMER_REPLICA;
        }

        throw new IllegalArgumentException("Invalid command " + expatQueryCommand);
    }

    public void processBroadcastreceivesasexpatids(
            ReplicationState expatListState) {
        ExpatListListener expatListener =
                sasExpatListHandler.getListener();
        if(expatListener != null) {
            expatListener.expatListReceived(expatListState);
        }
    }

    public void processBroadcastreceivesipsessionexpatids(
            ReplicationState expatListState) {
        ExpatListListener expatListener =
                sipSessionExpatListHandler.getListener();
        if(expatListener != null) {
            expatListener.expatListReceived(expatListState);
        }
    }

    public void processBroadcastreceiveservlettimerexpatids(
            ReplicationState expatListState) {
        ExpatListListener expatListener =
                servletTimerExpatListHandler.getListener();
        if(expatListener != null) {
            expatListener.expatListReceived(expatListState);
        }
    }

    private void expatListReceived(ReplicationState expatListState,
                                                 ExpatListHandler expatHandler) {
        if(expatHandler != null) {
            ExpatListListener expatListener =
                    expatHandler.getListener();
            if (expatListener != null) {
                expatListener.expatListReceived(expatListState);
            }
        }
    }

    public void processBroadcastreceivesasreplicaexpatids(
            ReplicationState expatListState) {
        expatListReceived(expatListState,  sasReplicaExpatHandler);
    }

    public void processBroadcastreceivesipsessionreplicaexpatids(
            ReplicationState expatListState) {
        expatListReceived(expatListState, ssReplicaExpatHandler);
    }

    public void processBroadcastreceiveservlettimerreplicaexpatids(
            ReplicationState expatListState) {
        expatListReceived(expatListState, stReplicaExpatHandler);
    }

    //SipApplicationSession related
   
    List<FederatedQueryListElement> getSipApplicationSessionIds(String owningInstanceName) {
        List<FederatedQueryListElement> sessionIds = new ArrayList();
        //using set to avoid dups
        HashSet sessionIdsSet = new HashSet();
        List replicasToRemove = new ArrayList();
        ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
        String correctBuddyReplicaName
            = healthChecker.getReshapeReplicateToInstanceName(null, owningInstanceName, 0L);
        //iterate over http replicas
        BaseCache replicatedSipApplicationSessionsCache = getReplicatedSipApplicationSessions();
        Iterator it = replicatedSipApplicationSessionsCache.values();
        while(it.hasNext()) {
            ReplicationState nextState
                = (ReplicationState)it.next();
            if(!RollingUpgradeUtil.filterOwnership(owningInstanceName, correctBuddyReplicaName, nextState, sessionIdsSet)) {
                //we remove this entry if it is not on the correct replica partner - i.e. it is a zombie
                replicasToRemove.add(nextState.getId());
            }
        }
        for(int i=0; i<replicasToRemove.size(); i++) {
            String nextId = (String)replicasToRemove.get(i);
            if(nextId != null) {
                removeFromSipApplicationSessionReplicationCache(nextId);
            }
        }
        sessionIds.addAll(sessionIdsSet);
        return sessionIds;
    }
   
    /**
     * process the broadcastfindsipapplicationsessionids for SipApplicationSession
     * @param queryState
     */    
    public ReplicationState processBroadcastfindsipapplicationsessionids(ReplicationState queryState) {
        //complete query and send back response
        String instanceName = getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsipapplicationsessionids:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsipapplicationsessionids:owningInstance=" + queryState.getInstanceName());                       
        }        
        String owningInstanceName = queryState.getInstanceName();
        List sessionIds = null;
        if(this.isThirdPartyBackingStoreInUse()) {
            sessionIds
                = getSipApplicationSessionIdsThirdPartySPI(owningInstanceName);
        } else {
            sessionIds
                = getSipApplicationSessionIds(owningInstanceName);
        }
        byte[] resultState = null;
        try {
            resultState = ReplicationUtil.getByteArray((ArrayList)sessionIds);
        } catch (IOException ex) {
            //deliberate no-op
            ;
        }
        //first check for none found in either active or replica caches
        if(sessionIds == null || sessionIds.isEmpty()) {
            //return nack
            return ReplicationState.createQueryResponseFrom(queryState, true);
        } else {
            return ReplicationState.createQueryResponseFrom(queryState, resultState);
        }
    }
   
    //SipSession related
   
    List<FederatedQueryListElement> getSipSessionIds(String owningInstanceName) {
        List<FederatedQueryListElement> sessionIds = new ArrayList();
        //using set to avoid dups
        HashSet sessionIdsSet = new HashSet();
        List replicasToRemove = new ArrayList();
        ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
        String correctBuddyReplicaName
            = healthChecker.getReshapeReplicateToInstanceName(null, owningInstanceName, 0L);
        //iterate over http replicas
        BaseCache replicatedSipSessionsCache = getReplicatedSipSessions();
        Iterator it = replicatedSipSessionsCache.values();
        while(it.hasNext()) {
            ReplicationState nextState
                = (ReplicationState)it.next();
            if(!RollingUpgradeUtil.filterOwnership(owningInstanceName, correctBuddyReplicaName, nextState, sessionIdsSet)) {
                //we remove this entry if it is not on the correct replica partner - i.e. it is a zombie
                replicasToRemove.add(nextState.getId());
            }
        }
        for(int i=0; i<replicasToRemove.size(); i++) {
            String nextId = (String)replicasToRemove.get(i);
            if(nextId != null) {
                removeFromSipSessionReplicationCache(nextId);
            }
        }
        sessionIds.addAll(sessionIdsSet);
        return sessionIds;
    }

    List<FederatedQueryListElement> getSipApplicationSessionIdsThirdPartySPI(String owningInstanceName) {
        BackingStore backingStore
                = this.getSipApplicationSessionBackingStore();
        SipApplicationSessionExtraParams sasExtraParamCriteria
                = SipApplicationSessionExtraParams.createSearchCriteria(
                this, this.getApplicationId(), owningInstanceName);
        Collection<SipApplicationSessionExtraParams> sasColl
                = backingStore.findByCriteria(null, sasExtraParamCriteria);

        List<FederatedQueryListElement> sessionIds = new ArrayList();
        //using set to avoid dups
        HashSet sessionIdsSet = new HashSet();
        Iterator<SipApplicationSessionExtraParams> sasResults =
                (Iterator<SipApplicationSessionExtraParams>) sasColl.iterator();
        while (sasResults.hasNext()) {
            SipApplicationSessionExtraParams eParam = sasResults.next();
            if (owningInstanceName.equals(eParam.getCurrentOwnerInstanceName())) {
                sessionIdsSet.add(new FederatedQueryListElement((String) eParam.getId(), -1L, getInstanceName()));
            }
        }
        sessionIds.addAll(sessionIdsSet);
        return sessionIds;
    }

    /**
     * process the broadcastfindsipsessionids for SipSession
     * @param queryState
     */    
    public ReplicationState processBroadcastfindsipsessionids(ReplicationState queryState) {
        //complete query and send back response
        String instanceName = getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsipsessionids:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindsipsessionids:owningInstance=" + queryState.getInstanceName());                       
        }        
        String owningInstanceName = queryState.getInstanceName();
        List sessionIds = null;
        if(this.isThirdPartyBackingStoreInUse()) {
            sessionIds
                = getSipSessionIdsThirdPartySPI(owningInstanceName);
        } else {
            sessionIds
                = getSipSessionIds(owningInstanceName);
        }
        byte[] resultState = null;
        try {
            resultState = ReplicationUtil.getByteArray((ArrayList)sessionIds);
        } catch (IOException ex) {
            //deliberate no-op
            ;
        }
        //first check for none found in either active or replica caches
        if(sessionIds == null || sessionIds.isEmpty()) {
            //return nack
            return ReplicationState.createQueryResponseFrom(queryState, true);
        } else {
            return ReplicationState.createQueryResponseFrom(queryState, resultState);
        }
    } 
   
    List<FederatedQueryListElement> getSipSessionIdsThirdPartySPI(String owningInstanceName) {
        BackingStore backingStore
            = this.getSipSessionBackingStore();
        SipSessionExtraParams ssExtraParamCriteria
            = SipSessionExtraParams.createSearchCriteria(this, owningInstanceName);
        Collection<SipSessionExtraParams> ssColl
            = backingStore.findByCriteria(null, ssExtraParamCriteria);

        List<FederatedQueryListElement> sessionIds = new ArrayList();
        //using set to avoid dups
        HashSet sessionIdsSet = new HashSet();
        Iterator<SipSessionExtraParams> ssResults =
            (Iterator<SipSessionExtraParams>) ssColl.iterator();
        while (ssResults.hasNext()) {
            SipSessionExtraParams eParam = ssResults.next();
            if (owningInstanceName.equals(eParam.getCurrentOwnerInstanceName())) {
                sessionIdsSet.add(new FederatedQueryListElement((String)eParam.getId(), -1L, getInstanceName()));
            }
        }
        sessionIds.addAll(sessionIdsSet);
        return sessionIds;
    }      
   
    //ServletTimer related
   
    List<FederatedQueryListElement> getServletTimerIds(String owningInstanceName) {
        List<FederatedQueryListElement> servletTimerIds = new ArrayList();
        //using set to avoid dups
        HashSet servletTimerIdsSet = new HashSet();
        List replicasToRemove = new ArrayList();
        ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
        String correctBuddyReplicaName
            = healthChecker.getReshapeReplicateToInstanceName(null, owningInstanceName, 0L);
        //iterate over http replicas
        BaseCache replicatedServletTimersCache = getReplicatedServletTimers();
        Iterator it = replicatedServletTimersCache.values();
        while(it.hasNext()) {
            ReplicationState nextState
                = (ReplicationState)it.next();
            if(!RollingUpgradeUtil.filterOwnership(owningInstanceName, correctBuddyReplicaName, nextState, servletTimerIdsSet)) {
                //we remove this entry if it is not on the correct replica partner - i.e. it is a zombie
                replicasToRemove.add(nextState.getId());
            }
        }
        for(int i=0; i<replicasToRemove.size(); i++) {
            String nextId = (String)replicasToRemove.get(i);
            if(nextId != null) {
                removeFromServletTimerReplicationCache(nextId);
            }
        }
        servletTimerIds.addAll(servletTimerIdsSet);
        return servletTimerIds;
    }
   
    /**
     * process the broadcastfindservlettimerids for ServletTimer
     * @param queryState
     */    
    public ReplicationState processBroadcastfindservlettimerids(ReplicationState queryState) {
        //complete query and send back response
        String instanceName = getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindservlettimerids:instance: " + instanceName);
            _logger.fine("in " + this.getClass().getName() + ">>processBroadcastfindservlettimerids:owningInstance=" + queryState.getInstanceName());                       
        }       
        String owningInstanceName = queryState.getInstanceName();
        List servletTimerIds = null;
        if(this.isThirdPartyBackingStoreInUse()) {
            servletTimerIds
                = getServletTimerIdsThirdPartySPI(owningInstanceName);
        } else {
            servletTimerIds
                = getServletTimerIds(owningInstanceName);
        }
        byte[] resultState = null;
        try {
            resultState = ReplicationUtil.getByteArray((ArrayList)servletTimerIds);
        } catch (IOException ex) {
            //deliberate no-op
            ;
        }
        //first check for none found in either active or replica caches
        if(servletTimerIds == null || servletTimerIds.isEmpty()) {
            //return nack
            return ReplicationState.createQueryResponseFrom(queryState, true);
        } else {
            return ReplicationState.createQueryResponseFrom(queryState, resultState);
        }
    } 
   
    List<FederatedQueryListElement> getServletTimerIdsThirdPartySPI(String owningInstanceName) {
        BackingStore backingStore
            = this.getServletTimerBackingStore();
        ServletTimerExtraParams stExtraParamCriteria
            = ServletTimerExtraParams.createSearchCriteria(this, owningInstanceName);
        Collection<ServletTimerExtraParams> stColl
            = backingStore.findByCriteria(null, stExtraParamCriteria);

        List<FederatedQueryListElement> servletTimerIds = new ArrayList();
        //using set to avoid dups
        HashSet servletTimerIdsSet = new HashSet();
        Iterator<ServletTimerExtraParams> stResults =
            (Iterator<ServletTimerExtraParams>) stColl.iterator();
        while (stResults.hasNext()) {
            ServletTimerExtraParams eParam = stResults.next();
            if (owningInstanceName.equals(eParam.getCurrentOwnerInstanceName())) {
                servletTimerIdsSet.add(new FederatedQueryListElement((String)eParam.getId(), -1L, getInstanceName()));
            }
        }
        servletTimerIds.addAll(servletTimerIdsSet);
        return servletTimerIds;
    }
   
    /**
     * send a rolling upgrade advisory message to instance to trigger
     * it to do rolling upgrade reconciliation for the sending
     * instance
     *
     * @param waitTime the waitTime
     * @param instanceName the instance to be sent the rolling upgrade advisory
     */
    public void sendRollingUpgradeAdvisory(long waitTime, String instanceName) {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager",
                             "sendRollingUpgradeAdvisory",
                             new Object[] {instanceName});
        }
        try {
            RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, MESSAGE_BROADCAST_ROLLING_UPGRADE_ADVISORY, instanceName, waitTime);
        } catch (IOException ex) {}
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager",
                            "sendRollingUpgradeAdvisory");
        }
    }

    /**
     * broadcast a rolling upgrade advisory message to trigger
     * rolling upgrade reconciliation for the sending
     * instance
     */
    protected void sendRollingUpgradeAdvisory(long waitTime) {
        //broadcast rolling upgrade advisory
        RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, MESSAGE_BROADCAST_ROLLING_UPGRADE_ADVISORY, waitTime);
    }

    /**
     * send a rolling upgrade advisory message to instance to trigger
     * it to do rolling upgrade active cache restoration for the sending
     * instance
     *
     * @param instanceName the instance to be sent the rolling upgrade advisory
     * @param command the command
     */
    public void sendRollingUpgradeActiveCacheRestorationAdvisory(String command, String instanceName) {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager",
                             "sendRollingUpgradeActiveCacheRestorationAdvisory",
                             new Object[] {instanceName});
        }
        try {
            RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, command, instanceName);
        } catch (IOException ex) {}
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager",
                            "sendRollingUpgradeActiveCacheRestorationAdvisory");
        }
    }

    /**
     * broadcast a rolling upgrade active cache restoration advisory message to trigger
     * rolling upgrade replica cache restoration for the sending
     * instance
     * @param command the command
     */
    protected void sendRollingUpgradeReplicaCacheRestorationAdvisory(String command) {
        //broadcast rolling upgrade active cache restoration advisory
        RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, command);
    }

    /**
     * send a rolling upgrade advisory message to instance to trigger
     * it to do rolling upgrade replica cache restoration for the sending
     * instance
     *
     * @param instanceName the instance to be sent the rolling upgrade advisory
     * @param command the command
     */
    public void sendRollingUpgradeReplicaCacheRestorationAdvisory(String command, String instanceName) {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager",
                             "sendRollingUpgradeReplicaCacheRestorationAdvisory",
                             new Object[] {instanceName});
        }
        try {
            RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, command, instanceName);
        } catch (IOException ex) {}
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager",
                            "sendRollingUpgradeReplicaCacheRestorationAdvisory");
        }
    }

    /**
     * broadcast a rolling upgrade active cache restoration advisory message to trigger
     * rolling upgrade active cache restoration for the sending
     * instance
     * @param command the command
     */
    protected void sendRollingUpgradeActiveCacheRestorationAdvisory(String command) {
        //broadcast rolling upgrade active cache restoration advisory
        RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, command);
    }

    /**
     * send a rolling upgrade reconciliation complete advisory message to instance to signal
     * to the original caller instance that replica reconciliation is complete
     *
     * @param instanceName the instance to be sent the rolling upgrade reconciliation complete advisory
     */
    public void sendRollingUpgradeReplicaReconciliationCompleteAdvisory(String instanceName) {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering("SipTransactionPersistentManager",
                             "sendRollingUpgradeReplicaReconciliationCompleteAdvisory",
                             new Object[] {instanceName});
        }
        try {
            RollingUpgradeUtil.sendRollingUpgradeAdvisory((ReplicationManager)this, MODE_SIP, MESSAGE_BROADCAST_ROLLING_UPGRADE_REPLICA_RECONCILIATION_COMPLETE_ADVISORY, instanceName);
        } catch (IOException ex) {}
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting("SipTransactionPersistentManager",
                            "sendRollingUpgradeReplicaReconciliationCompleteAdvisory");
        }
    }
   
    public void processRollingupgradeadvisory(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradeadvisory received from " + instanceName);
        }
        long waitTime = ((Long)replicationState.getProperty(ReplicationState.WAIT_TIME)).longValue();
        //we have been triggered to do replica
        //cache reconciliation for our replicateTo partner
        doReplicaCacheReconciliation(waitTime, null); // TODO :: check last param, this whole method is unused -- remove it later.
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradeadvisory sending reconciliation completed advisory to: " + instanceName);
        }
        sendRollingUpgradeReplicaReconciliationCompleteAdvisory(instanceName);
    }

    public void processRollingupgradesipapplicationsessionactivecacherestorationadvisory(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradesipapplicationsessionactivecacherestorationadvisory received from " + instanceName);
        }
        List<ReplicationState> ownedReplicas = getSipApplicationSessionReplicas(instanceName);
        sendReplicationStateList(ownedReplicas, instanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_ACTIVE_CACHE_RESTORATION_RESPONSE);

    }

    public void processRollingupgradesipapplicationsessionactivecacherestorationresponse(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradesipapplicationsessionactivecacherestorationresponse received from " + instanceName);
        }
        ownedReplicaListsReceivedForSipApplicationSessionActiveCacheRestoration.putIfAbsent(replicationState.getInstanceName(), replicationState);
        restoreSipApplicationSessionActiveCacheDoneSignal.countDown();
    }

    public void processRollingupgradesipapplicationsessionreplicacacherestorationadvisory(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradesipapplicationsessionreplicacacherestorationadvisory received from " + instanceName);
        }
        List<ReplicationState> ownedReplicas = getActiveSipApplicationSessionsToReplicateTo(instanceName);
        sendReplicationStateList(ownedReplicas, instanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_APPLICATION_SESSION_REPLICA_CACHE_RESTORATION_RESPONSE);

    }

    public void processRollingupgradesipapplicationsessionreplicacacherestorationresponse(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradesipapplicationsessionreplicacacherestorationresponse received from " + instanceName);
        }
        ownedReplicaListsReceivedForSipApplicationSessionReplicaCacheRestoration.putIfAbsent(replicationState.getInstanceName(), replicationState);
        restoreSipApplicationSessionReplicaCacheDoneSignal.countDown();
    }

    public void processRollingupgradesipsessionactivecacherestorationadvisory(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradesipsessionactivecacherestorationadvisory received from " + instanceName);
        }
        List<ReplicationState> ownedReplicas = getSipSessionReplicas(instanceName);
        sendReplicationStateList(ownedReplicas, instanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_ACTIVE_CACHE_RESTORATION_RESPONSE);

    }

    public void processRollingupgradesipsessionactivecacherestorationresponse(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradesipsessionactivecacherestorationresponse received from " + instanceName);
        }
        ownedReplicaListsReceivedForSipSessionActiveCacheRestoration.putIfAbsent(replicationState.getInstanceName(), replicationState);
        restoreSipSessionActiveCacheDoneSignal.countDown();
    }

    public void processRollingupgradesipsessionreplicacacherestorationadvisory(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradesipsessionreplicacacherestorationadvisory received from " + instanceName);
        }
        List<ReplicationState> ownedReplicas = getActiveSipSessionsToReplicateTo(instanceName);
        sendReplicationStateList(ownedReplicas, instanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_SIP_SESSION_REPLICA_CACHE_RESTORATION_RESPONSE);

    }

    public void processRollingupgradesipsessionreplicacacherestorationresponse(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradesipsessionreplicacacherestorationresponse received from " + instanceName);
        }
        ownedReplicaListsReceivedForSipSessionReplicaCacheRestoration.putIfAbsent(replicationState.getInstanceName(), replicationState);
        restoreSipSessionReplicaCacheDoneSignal.countDown();
    }

    public void processRollingupgradeservlettimeractivecacherestorationadvisory(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradeservlettimeractivecacherestorationadvisory received from " + instanceName);
        }
        List<ReplicationState> ownedReplicas = getServletTimerReplicas(instanceName);
        sendReplicationStateList(ownedReplicas, instanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_ACTIVE_CACHE_RESTORATION_RESPONSE);

    }

    public void processRollingupgradeservlettimeractivecacherestorationresponse(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradeservlettimeractivecacherestorationresponse received from " + instanceName);
        }
        ownedReplicaListsReceivedForServletTimerActiveCacheRestoration.putIfAbsent(replicationState.getInstanceName(), replicationState);
        restoreServletTimerActiveCacheDoneSignal.countDown();
    }

    public void processRollingupgradeservlettimerreplicacacherestorationadvisory(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradeservlettimerreplicacacherestorationadvisory received from " + instanceName);
        }
        List<ReplicationState> ownedReplicas = getActiveServletTimersToReplicateTo(instanceName);
        sendReplicationStateList(ownedReplicas, instanceName, MESSAGE_BROADCAST_ROLLING_UPGRADE_SERVLET_TIMER_REPLICA_CACHE_RESTORATION_RESPONSE);

    }

    public void processRollingupgradeservlettimerreplicacacherestorationresponse(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        String instanceName = replicationState.getInstanceName();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradeservlettimerreplicacacherestorationresponse received from " + instanceName);
        }
        ownedReplicaListsReceivedForServletTimerReplicaCacheRestoration.putIfAbsent(replicationState.getInstanceName(), replicationState);
        restoreServletTimerReplicaCacheDoneSignal.countDown();
    }


    public void processRollingupgradereplicareconciliationcompleteadvisory(ReplicationState replicationState) {
        if(replicationState == null) {
            return;
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("IN " + this.getClass().getName() + ">>processRollingupgradereplicareconciliationcompleteadvisory received from " + replicationState.getInstanceName());
        }
        reconcileReplicaCacheDoneSignal.countDown();
    }

    List<ReplicationState> getSipApplicationSessionReplicas(String owningInstanceName) {
        List<ReplicationState> sessionIds = new ArrayList();
        //using set to avoid dups
        HashSet sessionIdsSet = new HashSet();
        //iterate over sip application session replicas
        BaseCache replicatedSipApplicationSessionsCache = getReplicatedSipApplicationSessions();
        Iterator it = replicatedSipApplicationSessionsCache.values();
        while(it.hasNext()) {
            ReplicationState nextState
                = (ReplicationState)it.next();
            RollingUpgradeUtil.filterOwnershipOfReplicas(owningInstanceName, nextState, sessionIdsSet);
        }
        sessionIds.addAll(sessionIdsSet);
        return sessionIds;
    }

    List<ReplicationState> getActiveSipApplicationSessionsToReplicateTo(String owningInstanceName) {
        SipApplicationSessionStoreImpl store = this.getSingletonSipApplicationSessionStore();
        List<ReplicationState> sessionIds = new ArrayList();
        //using set to avoid dups
        HashSet sessionIdsSet = new HashSet();
        //iterate over active sessions
        Iterator it = applicationSessions.values().iterator();
        while(it.hasNext()) {
            HASipApplicationSession nextSession = (HASipApplicationSession)it.next();
            String beKey = nextSession.getBeKey();
            if(RollingUpgradeUtil.shouldReplicateTo(beKey, owningInstanceName)) {
                ReplicationState nextState = null;
                try {
                    nextState = store.getTransmitState(nextSession);
                } catch (IOException ex) {}
                if(nextState != null) {
                    sessionIdsSet.add(nextState);
                }
            }

        }
        sessionIds.addAll(sessionIdsSet);
        return sessionIds;
    }

    List<ReplicationState> getSipSessionReplicas(String owningInstanceName) {
        List<ReplicationState> sessionIds = new ArrayList();
        //using set to avoid dups
        HashSet sessionIdsSet = new HashSet();
        //iterate over sip session replicas
        BaseCache replicatedSipSessionsCache = getReplicatedSipSessions();
        Iterator it = replicatedSipSessionsCache.values();
        while(it.hasNext()) {
            ReplicationState nextState
                = (ReplicationState)it.next();
            RollingUpgradeUtil.filterOwnershipOfReplicas(owningInstanceName, nextState, sessionIdsSet);
        }
        sessionIds.addAll(sessionIdsSet);
        return sessionIds;
    }

    List<ReplicationState> getActiveSipSessionsToReplicateTo(String owningInstanceName) {
        SipSessionStoreImpl store = this.getSingletonSipSessionStore();
        List<ReplicationState> sessionIds = new ArrayList();
        //using set to avoid dups
        HashSet sessionIdsSet = new HashSet();
        //iterate over active sessions
        Iterator it = sipSessions.values().iterator();
        while(it.hasNext()) {
            HASipSession nextSession = (HASipSession)it.next();
            String beKey = null;
            if(nextSession.getParentSASId() != null) {
                beKey = SipApplicationSessionUtil.getSipApplicationKey(nextSession.getParentSASId());
            }           
            if(RollingUpgradeUtil.shouldReplicateTo(beKey, owningInstanceName)) {
                ReplicationState nextState = null;
                try {
                    nextState = store.getTransmitState(nextSession);
                } catch (IOException ex) {}
                if(nextState != null) {
                    sessionIdsSet.add(nextState);
                }
            }

        }
        sessionIds.addAll(sessionIdsSet);
        return sessionIds;
    }

    List<ReplicationState> getServletTimerReplicas(String owningInstanceName) {
        List<ReplicationState> sessionIds = new ArrayList();
        //using set to avoid dups
        HashSet timerIdsSet = new HashSet();
        //iterate over servlet timer replicas
        BaseCache replicatedServletTimersCache = getReplicatedServletTimers();
        Iterator it = replicatedServletTimersCache.values();
        while(it.hasNext()) {
            ReplicationState nextState
                = (ReplicationState)it.next();
            RollingUpgradeUtil.filterOwnershipOfReplicas(owningInstanceName, nextState, timerIdsSet);
        }
        sessionIds.addAll(timerIdsSet);
        return sessionIds;
    }

    List<ReplicationState> getActiveServletTimersToReplicateTo(String owningInstanceName) {
        ServletTimerStoreImpl store = this.getSingletonServletTimerStore();
        List<ReplicationState> timerIds = new ArrayList();
        //using set to avoid dups
        HashSet timerIdsSet = new HashSet();
        //iterate over active timers
        Iterator it = servletTimers.values().iterator();
        while(it.hasNext()) {
            HAServletTimer nextTimer = (HAServletTimer)it.next();
            String beKey = null;
            if(nextTimer.getParentSASId() != null) {
                beKey = SipApplicationSessionUtil.getSipApplicationKey(nextTimer.getParentSASId());
            }
            if(RollingUpgradeUtil.shouldReplicateTo(beKey, owningInstanceName)) {
                ReplicationState nextState = null;
                try {
                    nextState = store.getTransmitState(nextTimer);
                } catch (IOException ex) {}
                if(nextState != null) {
                    timerIdsSet.add(nextState);
                }
            }

        }
        timerIds.addAll(timerIdsSet);
        return timerIds;
    }

    private void sendReplicationStateList(Collection<ReplicationState> ownedReplicas,
                               String instanceName, String command) {
        byte[] ownedReplicasState = null;
        try {
            ownedReplicasState = ReplicationUtil.getByteArray((Serializable)ownedReplicas);
        } catch (IOException ex) {}      
        //need a unique pseudo-id for this query
        String appId = getApplicationId();
        String id = appId + unique.getAndIncrement();
        ReplicationState ownedReplicasListState = new ReplicationState(MODE_SIP,
                id, appId, 0L, 0L, 0L, null, null, getInstanceName(),
                command, ownedReplicasState, null, null);
        if (ownedReplicas == null || ownedReplicas.isEmpty()) {
            ownedReplicasListState.setNack(true);
        }
        JxtaSocketChannel channel = JxtaSocketChannel.getInstance();
        channel.send(ownedReplicasListState, instanceName);
    }

    private void sendReplicasList(Collection ownedReplicas,
                               String instanceName, String command) {
        byte[] ownedReplicasState = null;
        try {
            ownedReplicasState = ReplicationUtil.getByteArray((Serializable)ownedReplicas);
        } catch (IOException ex) {}
        //need a unique pseudo-id for this query
        String appId = getApplicationId();
        String id = appId + unique.getAndIncrement();
        ReplicationState ownedReplicasListState = new ReplicationState(MODE_SIP,
                id, appId, 0L, 0L, 0L, null, null, getInstanceName(),
                command, ownedReplicasState, null, null);
        if (ownedReplicas == null || ownedReplicas.isEmpty()) {
            ownedReplicasListState.setNack(true);
        }
        JxtaSocketChannel channel = JxtaSocketChannel.getInstance();
        channel.send(ownedReplicasListState, instanceName);
    }   

    private class ReconcileActiveSipApplicationSession implements Runnable {

        SipTransactionPersistentManager _mgr = null;
        long _waitTime = -1L;
        CountDownLatch _doneSignal = null;
        RollingUpgradeContext _ctx = null;

        public ReconcileActiveSipApplicationSession(SipTransactionPersistentManager mgr, long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
            _mgr = mgr;
            _waitTime = waitTime;
            _doneSignal = doneSignal;
            _ctx = ctx;
        }

        public void run() {
            try {
                _mgr.doSipApplicationSessionActiveCacheReconciliation(_waitTime, _ctx);
            } catch (Exception ex) {
                _logger.log(Level.WARNING, ex.getMessage(), ex);
            } finally {
                _doneSignal.countDown();
            }
        }

    }

    private class ReconcileActiveSipSession implements Runnable {

        SipTransactionPersistentManager _mgr = null;
        long _waitTime = -1L;
        CountDownLatch _doneSignal = null;
        RollingUpgradeContext _ctx = null;

        public ReconcileActiveSipSession(SipTransactionPersistentManager mgr, long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
            _mgr = mgr;
            _waitTime = waitTime;
            _doneSignal = doneSignal;
            _ctx = ctx;
        }

        public void run() {
            try {
                _mgr.doSipSessionActiveCacheReconciliation(_waitTime, _ctx);
            } catch (Exception ex) {
                _logger.log(Level.WARNING, ex.getMessage(), ex);
            } finally {
                _doneSignal.countDown();
            }
        }

    }

    private class ReconcileActiveServletTimer implements Runnable {

        SipTransactionPersistentManager _mgr = null;
        long _waitTime = -1L;
        CountDownLatch _doneSignal = null;
        RollingUpgradeContext _ctx = null;

        public ReconcileActiveServletTimer(SipTransactionPersistentManager mgr, long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
            _mgr = mgr;
            _waitTime = waitTime;
            _doneSignal = doneSignal;
            _ctx = ctx;
        }

        public void run() {
            try {
                _mgr.doServletTimerActiveCacheReconciliation(_waitTime, _ctx);
            } catch (Exception ex) {
                _logger.log(Level.WARNING, ex.getMessage(), ex);
            } finally {
                _doneSignal.countDown();
            }
        }

    }


    private class ReconcileReplicaSipApplicationSession implements Runnable {

        SipTransactionPersistentManager _mgr = null;
        long _waitTime = -1L;
        CountDownLatch _doneSignal = null;
        RollingUpgradeContext _ctx = null;

        public ReconcileReplicaSipApplicationSession(SipTransactionPersistentManager mgr, long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
            _mgr = mgr;
            _waitTime = waitTime;
            _doneSignal = doneSignal;
            _ctx = ctx;
        }

        public void run() {
            try {
                _mgr.doSipApplicationSessionReplicaCacheReconciliation(_waitTime, _ctx);
            } catch (Exception ex) {
                _logger.log(Level.WARNING, ex.getMessage(), ex);
            } finally {
                _doneSignal.countDown();
            }
        }

    }

    private class ReconcileReplicaSipSession implements Runnable {

        SipTransactionPersistentManager _mgr = null;
        long _waitTime = -1L;
        CountDownLatch _doneSignal = null;
        RollingUpgradeContext _ctx = null;

        public ReconcileReplicaSipSession(SipTransactionPersistentManager mgr, long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
            _mgr = mgr;
            _waitTime = waitTime;
            _doneSignal = doneSignal;
            _ctx = ctx;
        }

        public void run() {
            try {
                _mgr.doSipSessionReplicaCacheReconciliation(_waitTime, _ctx);
            } catch (Exception ex) {
                _logger.log(Level.WARNING, ex.getMessage(), ex);
            } finally {
                _doneSignal.countDown();
            }
        }

    }

    private class ReconcileReplicaServletTimer implements Runnable {

        SipTransactionPersistentManager _mgr = null;
        long _waitTime = -1L;
        CountDownLatch _doneSignal = null;
        RollingUpgradeContext _ctx = null;

        public ReconcileReplicaServletTimer(SipTransactionPersistentManager mgr, long waitTime, CountDownLatch doneSignal, RollingUpgradeContext ctx) {
            _mgr = mgr;
            _waitTime = waitTime;
            _doneSignal = doneSignal;
            _ctx = ctx;
        }

        public void run() {
            try {
                _mgr.doServletTimerReplicaCacheReconciliation(_waitTime, _ctx);
            } catch (Exception ex) {
                _logger.log(Level.WARNING, ex.getMessage(), ex);
            } finally {
                _doneSignal.countDown();
            }
        }

    }
   
    // end rolling upgrade related code
   
    private class PrivilegedStoreLoadSipApplicationSession
        implements PrivilegedExceptionAction {

        private String id;
        private String version;
        private SipApplicationSessionStoreImpl store;
           
        PrivilegedStoreLoadSipApplicationSession(String id, String version, SipApplicationSessionStoreImpl store) {    
            this.id = id;
            this.version = version;
            this.store = store;
        }

        public Object run() throws Exception{
           return store.load(id, version);
        }                      
    }
   
    private class PrivilegedStoreLoadSipSession
        implements PrivilegedExceptionAction {

        private String id;
        private String version;
        private boolean loadDependencies;
        private SipSessionStoreImpl store;
           
        PrivilegedStoreLoadSipSession(String id, String version,
                                      boolean loadDependencies,
                                      SipSessionStoreImpl store) {    
            this.id = id;
            this.version = version;
            this.loadDependencies = loadDependencies;
            this.store = store;
        }

        public Object run() throws Exception{
           return store.load(id, version, loadDependencies);
        }                      
    }
   
    private class PrivilegedStoreLoadServletTimer
        implements PrivilegedExceptionAction {

        private String id;
        private String version;
        private boolean loadDependencies;
        private ServletTimerStoreImpl store;
           
        PrivilegedStoreLoadServletTimer(String id, String version,
                                        boolean loadDependencies,
                                        ServletTimerStoreImpl store) {
            this.id = id;
            this.version = version;
            this.loadDependencies = loadDependencies;
            this.store = store;
        }

        public Object run() throws Exception{
           return store.load(id, version, loadDependencies);
        }                      
    }   

}
//
TOP

Related Classes of org.jvnet.glassfish.comms.replication.sessmgmt.SipTransactionPersistentManager$PrivilegedStoreLoadSipSession

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.