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

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

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

import com.sun.appserv.util.cache.BaseCache;
import com.sun.appserv.ha.uow.ReplicableEntity;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.IOException;
import java.io.Serializable;

/**
*
* @author Larry White
*/
public class RollingUpgradeUtil {

    public final static String LOGGER_MEM_REP
        = ReplicationState.LOGGER_MEM_REP;

    /**
     * The logger to use for logging ALL web container related messages.
     */
    private static final Logger _logger
        = Logger.getLogger(LOGGER_MEM_REP);

    private static ReplicationUtil replicationUtil = ReplicationUtil.createReplicationUtil();
    public final static String BEKEY
        = ReplicationState.BEKEY;

    /**
     * The logger to use for logging ALL web container related messages.
     * @param owningInstanceName the owning instance name
     * @param correctBuddyReplicaName the correct buddy replica name (for non-CLB case)
     * @param state the ReplicationState to filter
     * @param idsSet the set in which to collect filtered states
     * @return true if this instance is the correct instance for this replica; otherwise false
     */
    public static boolean filterOwnership(String owningInstanceName, String correctBuddyReplicaName, ReplicationState state, HashSet idsSet) {
        boolean result = true;
        long nextVersion = -1L;
        String thisInstanceName = ReplicationUtil.getInstanceName();
        String nextOwnerInstanceName = null;
        String nextCorrectReplicaPartnerInstanceName = null;
        String nextId = (String)state.getId();
        if(replicationUtil.isInstanceLoadBalancedByCLB()) {
            //CLB case
            //use beKey for mapping instance ownership
            String nextBeKey = (String)state.getProperty(BEKEY);
            if(nextBeKey != null) {
                nextOwnerInstanceName
                    = replicationUtil.getActualServerInstanceForBeKey(nextBeKey);
                nextCorrectReplicaPartnerInstanceName
                    = replicationUtil.getFailoverServerInstanceForBeKey(nextBeKey);
                if(nextOwnerInstanceName != null
                    && nextOwnerInstanceName.equalsIgnoreCase(owningInstanceName)) {
                    //return false if we are not the correct replica partner for this beKey
//                    if (nextCorrectReplicaPartnerInstanceName.equalsIgnoreCase(thisInstanceName)) {
                        nextVersion = state.getVersion();
                        idsSet.add(new FederatedQueryListElement(nextId, nextVersion, thisInstanceName, nextBeKey));
//                    } else {
//                        result = false;
//                    }
                }
            }
        } else {
            //non-CLB case
            nextOwnerInstanceName = (String)state.getProperty(ReplicationState.ORIGINATING_INSTANCE_NAME);
            if(nextOwnerInstanceName != null
                && nextOwnerInstanceName.equalsIgnoreCase(owningInstanceName)) {
                nextVersion = state.getVersion();
                idsSet.add(new FederatedQueryListElement(nextId, nextVersion, ReplicationUtil.getInstanceName()));
                //if we are a valid replica for owningInstanceName
                // but not the correctBuddyReplica then return false
                if(correctBuddyReplicaName != null &&
                        !correctBuddyReplicaName.equalsIgnoreCase(thisInstanceName)) {
                    result = false;
                }
            }
        }
        return result;
    }

    public static void filterOwnershipOfReplicas(String owningInstanceName,
                                                 ReplicationState state,
                                                 HashSet idsSet) {
        String nextOwnerInstanceName = (String) state.getProperty(
                ReplicationState.ORIGINATING_INSTANCE_NAME);
        if (nextOwnerInstanceName != null
                && nextOwnerInstanceName.equalsIgnoreCase(owningInstanceName)) {
            idsSet.add(state);
        }
    }

    public static ConcurrentHashMap mergeQueryListIntoMap(List localSessionIdsList, ConcurrentHashMap sessionIdsMap) {
        for(int i=0; i<localSessionIdsList.size(); i++) {
            FederatedQueryListElement nextElement = (FederatedQueryListElement)localSessionIdsList.get(i);
            if(nextElement != null) {
                //get any existing element in the map
                FederatedQueryListElement existingElement
                    = (FederatedQueryListElement)sessionIdsMap.get(nextElement.getId());
                if(existingElement == null || existingElement.getVersion() < nextElement.getVersion()) {
                    sessionIdsMap.put(nextElement.getId(), nextElement);
                }
            }
        }
        return sessionIdsMap;
    }

    public static boolean isElementFromReplicationPartner(FederatedQueryListElement nextElement, String buddyInstanceName) {
        String nextOwnerInstanceName = null;
        boolean result = false;
        String sourceInstance = nextElement.getSourceInstance();
        if(sourceInstance == null) {
            return result;
        }
        if(replicationUtil.isInstanceLoadBalancedByCLB()) {
            /**
             * The check below is wrong. getActualServerInstanceForBeKey(nextBeKey)
             * will always return the name of our own instance, it will not be
             * the name of replica partner.
             *
             * Probably the intention was to use getFailoverServerInstanceForBeKey(nextBeKey),
             * but doing that is also wrong because the 'nextElement' would have come from somewhere else
             * which need not necessarily be the current replica partner for this instance.
             *
             * Hence commenting it out, and setting the result to true always.
             */
/*
            //CLB case
            //use beKey for mapping instance ownership - compare to sourceInstance
            String nextBeKey = nextElement.getBeKey();
            if(nextBeKey != null) {
                nextOwnerInstanceName
                    = replicationUtil.getActualServerInstanceForBeKey(nextBeKey);
                if(nextOwnerInstanceName != null
                    && nextOwnerInstanceName.equalsIgnoreCase(sourceInstance)) {
                    result=true;
                }
            }
*/
            result = true;
        } else {
            //non-CLB case
            if(sourceInstance.equals(buddyInstanceName)) {
                result = true;
            }
        }
        return result;
    }


    public static boolean shouldReplicateTo(String beKey, String owningInstanceName) {
        if(replicationUtil.isInstanceLoadBalancedByCLB()) {
            //use CLB beKey semantics
            return owningInstanceName.equalsIgnoreCase(replicationUtil.getFailoverServerInstanceForBeKey(beKey));
        } else {
            //use ring topology semantics
            ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
            return owningInstanceName.equalsIgnoreCase(healthChecker.getReshapeReplicateToInstanceName(null, 0L));
        }
    }

    /**
     * send a rolling upgrade advisory message to a given instance
     *
     * @param mgr the ReplicationManager
     * @param mode the mode
     * @param command the command
     * @param instanceName the instance to be sent the rolling upgrade advisory
     */
    public static void sendRollingUpgradeAdvisory(ReplicationManager mgr, String mode, String command, String instanceName)
        throws IOException {
        //send rolling upgrade advisory to instanceName
        sendRollingUpgradeAdvisory(mgr, mode, command, instanceName, -1L);
    }

    /**
     * send a rolling upgrade advisory message to a given instance
     *
     * @param mgr the ReplicationManager
     * @param mode the mode
     * @param command the command
     * @param instanceName the instance to be sent the rolling upgrade advisory
     * @param waitTime the waitTime
     */
    public static void sendRollingUpgradeAdvisory(ReplicationManager mgr, String mode, String command, String instanceName, long waitTime)
        throws IOException {
        //send rolling upgrade advisory to instanceName
        ReplicationState loadAdvisoryState
            = ReplicationState.createUnicastLoadAdvisoryState(mode, "id", mgr.getApplicationId(), 0L, ReplicationUtil.getInstanceName(), command);
        if(waitTime != -1L) {
            loadAdvisoryState.setProperty(ReplicationState.WAIT_TIME, new Long(waitTime));
        }
        JxtaReplicationSender sender
            = JxtaReplicationSender.createInstance();
        sender.sendOverPropagatedPipe(loadAdvisoryState, instanceName, false);
    }

    /**
     * send a rolling upgrade advisory message to instance to trigger
     * it to do rolling upgrade active cache restoration for the sending
     * instance
     *
     * @param mode the mode of the manager
     * @param command the command (message)
     * @param className to be used in logging message
     * @param methodName to be used in logging message
     * @param instanceName the instance to be sent the rolling upgrade advisory
     */
    public static void sendRollingUpgradeAdvisory(ReplicationManager mgr, String mode, String command, String className, String methodName, String instanceName) {

        if(_logger.isLoggable(Level.FINE)) {
            _logger.entering(className,
                             methodName,
                             new Object[] {instanceName});
        }
        try {
            RollingUpgradeUtil.sendRollingUpgradeAdvisory(mgr, mode, command, instanceName);
        } catch (IOException ex) {}
        if(_logger.isLoggable(Level.FINE)) {
            _logger.exiting(className,
                            methodName);
        }
    }

    /**
     * broadcast a rolling upgrade advisory message
     *
     * @param mgr the ReplicationManager
     * @param mode the mode
     * @param command the command
     */
    public static void sendRollingUpgradeAdvisory(ReplicationManager mgr, String mode, String command) {
        //broadcast rolling upgrade advisory
        sendRollingUpgradeAdvisory(mgr, mode, command, -1L);
    }

    /**
     * broadcast a rolling upgrade advisory message
     *
     * @param mgr the ReplicationManager
     * @param mode the mode
     * @param command the command
     * @param waitTime the waitTime
     */
    public static void sendRollingUpgradeAdvisory(ReplicationManager mgr, String mode, String command, long waitTime) {
        //broadcast rolling upgrade advisory
        JxtaReplicationSender sender
            = JxtaReplicationSender.createInstance();
        //ok to use this method even while sending via broadcast in this case
        ReplicationState rollingUpgradeAdvisoryState
            = ReplicationState.createUnicastLoadAdvisoryState(mode, "id", mgr.getApplicationId(), 0L, ReplicationUtil.getInstanceName(), command);
        if(waitTime != -1L) {
            rollingUpgradeAdvisoryState.setProperty(ReplicationState.WAIT_TIME, new Long(waitTime));
        }
        sender.sendBroadcastQuery(rollingUpgradeAdvisoryState);
    }

    /**
     * get the number of expected respondants
     * for non-CLB case it will be one
     * for CLB case it will be one less than the current cluster size
     *
     */
    public static int getNumberOfExpectedRespondants() {
        int numberOfRespondants = 1;
        if(ReplicationUtil.checkIsInstanceLoadBalancedByCLB()) {
            numberOfRespondants = ReplicationUtil.getNumberExpectedRespondants();
        }
        return numberOfRespondants;
    }

    public static Object getObject(byte[] b) {
        try {
            return ReplicationState.getObjectValue(b);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }   

    public static int doActiveCacheReconciliation(SessionStoreInterface storeInterface,
                                                   String reconcileCommand,
                                                   AtomicReference<CountDownLatch> signalReference,
                                                   long waitTime,
                                                   Map<String, ReplicationState> queryResponses) {
        Set<ReplicationState> reconcilableActiveSessions =
                sendSynchronousQuery(reconcileCommand, storeInterface.getMode(),
                        storeInterface.getApplicationId(), signalReference,
                        waitTime, queryResponses);
        int sessionsActivated = activateSessions(reconcilableActiveSessions, storeInterface);
        return sessionsActivated;
    }

    public static int doReplicaCacheReconciliation(SessionStoreInterface storeInterface,
                                                    String reconcileCommand,
                                                    AtomicReference<CountDownLatch> signalReference,
                                                    long waitTime,
                                                    Map<String, ReplicationState> queryResponses) {
        Set<ReplicationState> reconcilableReplicaSessions =
                sendSynchronousQuery(reconcileCommand, storeInterface.getMode(),
                        storeInterface.getApplicationId(), signalReference,
                        waitTime, queryResponses);
        int savedReplicas = saveReplicas(reconcilableReplicaSessions, storeInterface);
        // the ongoing transaction on the remote instance might have replicated
        // the session to reconciling instance's replica cache which need to be purged.
        // removeStaleReplicas(ReplicationUtil.getInstanceName(), storeInterface);
        return savedReplicas;
    }


    public static int doPostActiveCacheReconcilation(SessionStoreInterface storeInterface,
                                                      String reconcileCommand,
                                                      AtomicReference<CountDownLatch> signalReference,
                                                      long waitTime,
                                                      Map<String, ReplicationState> queryResponses) {
        Set<String> remotelyLockedSessions = sendSynchronousQuery(reconcileCommand, storeInterface.getMode(),
                storeInterface.getApplicationId(), signalReference, waitTime, queryResponses);
        int suspectSessions = 0;
        for (ReplicableEntity session : storeInterface.getActiveCache().values()) {
            if (session.isSuspect()) {
                if (!remotelyLockedSessions.contains(session.getId())) {
                    session.setSuspect(false);
                } else {
                    ++suspectSessions;
                }
            }
        }
        return suspectSessions;
    }

    public static int activateSessions(Set<ReplicationState> reconcilableSessions,
                                 SessionStoreInterface storeInterface) {
        Iterator<ReplicationState> iter = reconcilableSessions.iterator();
        int sessionsActivated = reconcilableSessions.size();
        while (iter.hasNext()) {
            ReplicationState state = iter.next();
            ReplicableEntity session = storeInterface.deserialize(state);
            storeInterface.activate(session); // activate will take care of checking the version.
            iter.remove();
        }
        return sessionsActivated;
    }

    public static int saveReplicas(Set<ReplicationState> reconcilableSessions,
                                    SessionStoreInterface storeInterface) {
        Iterator<ReplicationState> iter = reconcilableSessions.iterator();
        int savedReplicas = reconcilableSessions.size();
        while (iter.hasNext()) {
            ReplicationState state = iter.next();
            storeInterface.putInReplicaCache(state);
            iter.remove();
        }
        return savedReplicas;
    }

    public static int removeStaleReplicas(String reconcilingInstance,
                                           SessionStoreInterface storeInterface) {
        Set<String> replicasToBePurged = new HashSet<String>();
        BaseCache replicaCache = storeInterface.getReplicaCache();
        Iterator<ReplicationState> replicatedSessions = replicaCache.values();
        List lbEnabledList = getLbEnabledList();
        while (replicatedSessions.hasNext()) {
            ReplicationState replica = replicatedSessions.next();
            if (canRemoveReplica(replica, reconcilingInstance, lbEnabledList)) {
                replicasToBePurged.add((String) replica.getId());
            }
        }
        for (String id : replicasToBePurged) {
            storeInterface.removeFromReplicaCache(id);
        }
        return replicasToBePurged.size();
    }
   
    // this method is executed by all other instances, in order to reconcile the
    // active cache of the instance who issued the reconcileRequest.
    public static Set<String> processActiveCacheReconciliationRequest(ReplicationState reconcileRequest,
                                         SessionStoreInterface storeInterface,
                                         String responseCommand,
                                         boolean compress) {
        Set<String> migratedActiveSessionIds = new HashSet<String>();
        Set<ReplicationState> result = new HashSet<ReplicationState>();
        if (replicationUtil.isInstanceLoadBalancedByCLB()) {
            String reconilingInstance = reconcileRequest.getInstanceName();
            Collection<ReplicableEntity> sessions = storeInterface.getActiveCache().values();
            for (ReplicableEntity session : sessions) {
                String beKey = session.getBeKey();
                if(!session.isForegroundLocked() && // don't migrate if it is foreground locked. locked sessions will be lazily migrated.
                        isRightfulOwner(reconilingInstance, beKey)) {
                    /**
                     * Do not passivate the session now until it is activated in
                     * the reconciling instance. Otherwise, if the load is issued
                     * by the reconciling instance when the reconciliation is in progress
                     * then the load will return null because session would have
                     * been removed from the session manager after the passivation.
                     */
//                    ReplicableEntity haSas = storeInterface.findSessionAndPassivate(session.getId());

                    ReplicableEntity haSas = session;
                        ReplicationState state = ReplicationState.createQueryResponseFrom(
                                haSas, reconcileRequest.getAppId(), reconcileRequest.getCommand(),
                                responseCommand, // TODO :: revisit this arg - should it be LOAD_SAS_COMMAND or something?
                                reconilingInstance, // origin is deliberately set to reconcilingInstance, so that we can copy this active session to our own replica.
                                compress, true);
                        result.add(state);
                        migratedActiveSessionIds.add(session.getId());
                }
            }
            // If some other instance has failed during the rolling upgrade of an instance,
            // then we should take care of that.
            int reconciledFromReplica = 0;
            BaseCache replicaCache = storeInterface.getReplicaCache();
            Iterator<ReplicationState> replicatedSessions = replicaCache.values();
            List lbEnabledList = getLbEnabledList();
            while(replicatedSessions.hasNext()) {
                ReplicationState replica = replicatedSessions.next();
                String beKey = (String)replica.getProperty(ReplicationState.BEKEY);
                if(isRightfulOwner(reconilingInstance, beKey) &&
                        !isOriginatingInstanceAlive(replica, lbEnabledList)) {
                    replica.setProperty(ReplicationState.ORIGINATING_INSTANCE_NAME,
                            reconilingInstance);
                    result.add(replica);
                    ++reconciledFromReplica;
                }
            }
            send(result,
                    reconcileRequest.getAppId(), reconcileRequest.getMode(),
                    responseCommand,
                    reconcileRequest.getInstanceName());
        } else {
            // TODO :: handle non clb case.
        }
        return migratedActiveSessionIds;
    }

    // this method is executed by all other instances, in order to reconcile the
    // replica cache of the instance who issued the reconcileRequest.
    public static void processReplicaCacheReconciliationRequest(ReplicationState reconcileRequest,
                                                                Map activeCache, String responseCommand, boolean compress) {
        Set<ReplicationState> result = new HashSet<ReplicationState>();
        if (replicationUtil.isInstanceLoadBalancedByCLB()) {
            String reconilingInstance = reconcileRequest.getInstanceName();
            Collection<ReplicableEntity> sessions = activeCache.values();
            for (ReplicableEntity session : sessions) {
                String beKey = session.getBeKey();
                if (!session.isForegroundLocked() && // don't replicate the foreground locked sessions. The locked sessions will anyway be replicated duing UOW.saveAndUnlock();
                        isReplicaPartner(reconilingInstance, beKey)) {
                    ReplicationState state = ReplicationState.createQueryResponseFrom(
                            session, reconcileRequest.getAppId(), reconcileRequest.getMode(),
                            responseCommand, // TODO :: revisit this arg, should it be LOAD_SAS_COMMAND or something?
                            ReplicationUtil.getInstanceName(),
                            compress, true);
                    result.add(state);
                }
            }
        }
        send(result, reconcileRequest.getAppId(),
                reconcileRequest.getMode(), responseCommand, reconcileRequest.getInstanceName());
    }

    public static void processPostActiveCacheReconciliationRequest(ReplicationState reconcileRequest,
                                                                   SessionStoreInterface storeInterface,
                                                                   Set<String> migratedActiveSessionIds,
                                                                   boolean saveMigratedSessionToReplicCache,
                                                                   String responseCommand) {
        /**
         * The following two steps should be only for in-mememory store.
         * Also, this step should be performed after the reconciling instance has
         * cleared the 'suspect' flag.
         */
        String reconcilingInstance = reconcileRequest.getInstanceName();

        int count = 0;
        if (migratedActiveSessionIds != null) {
            for (String id : migratedActiveSessionIds) {
                ReplicableEntity session = storeInterface.findSessionAndPassivate(id);
                if (session != null && saveMigratedSessionToReplicCache) {
                    ReplicationState state = ReplicationState.createQueryResponseFrom(
                            session, reconcileRequest.getAppId(), reconcileRequest.getCommand(),
                            responseCommand, // TODO :: revisit this arg - should it be LOAD_SAS_COMMAND or something?
                            reconcilingInstance, // origin is deliberately set to reconcilingInstance, so that we can copy this active session to our own replica.
                            false, // TODO :: revisit this param.
                            true);
                    storeInterface.putInReplicaCache(state);
                    ++count;
                }
            }
        }

        int purgedStaleReplicas = removeStaleReplicas(reconcilingInstance, storeInterface);
       
        send(new HashSet(),
                reconcileRequest.getAppId(), reconcileRequest.getMode(),
                responseCommand,
                reconcileRequest.getInstanceName());
    }


    public static Set sendSynchronousQuery(
            String command, String mode, String appId,
            AtomicReference<CountDownLatch> signalReference, long waitTime,
            Map<String, ReplicationState> remoteResponses) {
        remoteResponses.clear();
        ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
        List<String> instances = healthChecker.getLbEnabledList();
        CountDownLatch signal = new CountDownLatch(instances.size()-1);
        signalReference.set(signal);
        for(String destination : instances) {
            if(!ReplicationUtil.getInstanceName().equalsIgnoreCase(destination)) {
                send(new HashSet(), appId, mode, command, destination);
            }
        }
        try {
            // Wait till all the bulk road responses are received. The remote
            // responses received will be available in the remoteResponses map.
            signal.await(waitTime, TimeUnit.SECONDS);
        } catch (Exception ex) {
            // TODO :: handle exception
        }
        // process the remote responses
        Set reconcilableSessions = new HashSet();
        for (ReplicationState state : remoteResponses.values()) {
            mergeQueryResponses(state, reconcilableSessions);
        }
        remoteResponses.clear();
        return reconcilableSessions;
    }

    // send collection of objects via jxtasocketchannel.
    public static void send(Collection object, String appId, String mode,
                                String command, String instanceName) {
        byte[] byteArray = null;
        try {
            byteArray = ReplicationUtil.getByteArray((Serializable)object);
        } catch (Exception ex) {
            _logger.log(Level.WARNING, "Unable to serialize " + object +
                    ", error = " + ex.getMessage());
        }
        //need a unique pseudo-id for this query
        String id = appId + System.currentTimeMillis();
        ReplicationState state = new ReplicationState(mode,
                id, appId, 0L, 0L, 0L, null, null, ReplicationUtil.getInstanceName(),
                command, byteArray, null, null);
        if (object == null || object.isEmpty()) {
            state.setNack(true);
        }
        JxtaSocketChannel channel = JxtaSocketChannel.getInstance();
        channel.send(state, instanceName);
    }
   
    public static void mergeQueryResponses(ReplicationState queryResponse,
                                                Set targetSet) {
        Set values = (Set) getObject(queryResponse.getState());
        Iterator iter = values.iterator();
        while(iter.hasNext()) {
            Object next = iter.next();
            targetSet.add(next);
            iter.remove();
        }
    }
   
    /**
     * @param instance Proposed replica partner.
     * @param beKey beKey
     * @return true if the beKey is owned by this instance AND the failoverInstance
     * for the beKey is replicaPartner. Return false otherwise.
     */
    public static boolean isReplicaPartner(String instance, String beKey) {
        if (replicationUtil.isInstanceLoadBalancedByCLB()) {
            if (beKey != null && instance.equalsIgnoreCase(
                    replicationUtil.getFailoverServerInstanceForBeKey(beKey)) &&
                    ReplicationUtil.getInstanceName().equalsIgnoreCase(
                            replicationUtil.getActualServerInstanceForBeKey(beKey))) {
                return true;
            } else {
                return false;
            }
        } else {
            // TODO :: handle non clb case.
            return true;
        }
    }



    // Return true if the stale replica can be removed.
    // This method should be called only after ensuring that the reconcilingInstance
    // has activated the sesson in its active cache.
    public static boolean canRemoveReplica(ReplicationState state,
                                           String reconcilingInstance,
                                           List lbEnabledList) {
        if (replicationUtil.isInstanceLoadBalancedByCLB()) {
            String origin = (String) state.getProperty(
                    ReplicationState.ORIGINATING_INSTANCE_NAME);
            String beKey = (String) state.getProperty(
                    ReplicationState.BEKEY);
            if (isRightfulOwner(reconcilingInstance, beKey) &&
                    !reconcilingInstance.equalsIgnoreCase(origin) &&
                    isOriginatingInstanceAlive(state, lbEnabledList)) {
                return true;
            } else {
                // TODO :: if the origin is not alive, then ideally we should
                // TODO :: transfer those sessions to reconcilingInstance's active cache.
                return false;
            }
        } else {
            ReplicationHealthChecker healthChecker =
                    ReplicationHealthChecker.getInstance();
            String replicatedFromInstanceName
                = healthChecker.getReshapeReplicateFromInstanceName();
            if(replicatedFromInstanceName != null &&
                    replicatedFromInstanceName.equalsIgnoreCase(reconcilingInstance)) {
                return false;
            } else {
                return true;
            }
        }
    }

    public static boolean isRightfulOwner(String instance, String beKey) {
        if (replicationUtil.isInstanceLoadBalancedByCLB()) {
            if (beKey != null && instance.equalsIgnoreCase(
                    replicationUtil.getActualServerInstanceForBeKey(beKey))) {
                return true;
            } else {
                return false;
            }
        } else {
            // TODO :: handle non clb case.
            return true;
        }
    }

    public static List getLbEnabledList() {
        ReplicationHealthChecker healthChecker =
                ReplicationHealthChecker.getInstance();
        return healthChecker.getLbEnabledList();
    }

    public static boolean isOriginatingInstanceAlive(ReplicationState state,
                                                     List lbEnabledList) {
        String origin = (String) state.getProperty(
                ReplicationState.ORIGINATING_INSTANCE_NAME);
        if(lbEnabledList.contains(origin)) {
            return true;
        } else {
            return false;
        }
    }
   
    public static boolean canUseSuspectSession(ReplicableEntity session,
                                                        Map<String, ExpatListElement> expatMap,
                                                        ReentrantReadWriteLock expatLock
                                                        ) {
        if (session != null && expatMap != null && expatLock != null) {
            ReentrantReadWriteLock.ReadLock readLock = expatLock.readLock();
            if (readLock.tryLock()) {
                try {
                    ExpatListElement expat = expatMap.get(session.getId());
                    if (expat != null && !expat.isFromActive() &&
                            session.getVersion() >= expat.getVersion()) {
                        session.setSuspect(false);
                        return true;
                    }
                } finally {
                    readLock.unlock();
                }
            }
        }
        return false;
    }
}
TOP

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

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.