Package com.ericsson.ssa.sip

Source Code of com.ericsson.ssa.sip.SipSessionManagerBase$ObsoleteSessionHandler$BackOffTimerListener

/*
* 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 com.ericsson.ssa.sip;

import com.ericsson.ssa.config.ConvergedContext;
import com.ericsson.ssa.config.ConvergedContextImpl;
import com.ericsson.ssa.container.datacentric.DataCentricUtilHolder;
import com.ericsson.ssa.sip.PathNode.Type;
import com.ericsson.ssa.sip.SipApplicationSessionImpl;
import com.ericsson.ssa.sip.SipFactoryImpl;
import com.ericsson.ssa.sip.SipSessionsUtilImpl;
import com.ericsson.ssa.sip.timer.GeneralTimer;
import com.ericsson.ssa.sip.timer.GeneralTimerListener;
import com.ericsson.ssa.sip.timer.ServletTimerImpl;
import com.ericsson.ssa.sip.timer.TimerServiceImpl;
import com.ericsson.ssa.utils.UUIDUtil;

import com.sun.enterprise.config.ConfigContext;
import com.sun.enterprise.config.ConfigException;
import com.sun.enterprise.config.serverbeans.Cluster;
import com.sun.enterprise.config.serverbeans.ClusterHelper;
import com.sun.enterprise.ee.web.sessmgmt.EEPersistenceTypeResolver;
import com.sun.enterprise.server.ServerContext;
import com.sun.enterprise.web.ServerConfigLookup;

import org.apache.catalina.Container;
import org.apache.catalina.Globals;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.util.LifecycleSupport;

import org.glassfish.comms.api.datacentric.DataCentricUtil;

import org.jvnet.glassfish.comms.deployment.backend.SipApplicationListeners;
import org.jvnet.glassfish.comms.gms.EventListener;
import org.jvnet.glassfish.comms.util.LogUtil;

import java.io.Serializable;

import java.security.AccessController;
import java.text.SimpleDateFormat;

import java.util.*;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.sip.Address;
import javax.servlet.sip.ServletTimer;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipApplicationSessionEvent;
import javax.servlet.sip.SipApplicationSessionListener;
import javax.servlet.sip.SipSession;
import javax.servlet.sip.TimerListener;


/**
* Base implementation of the SipSessionManager interface.
*
* @author jluehe
*/
public class SipSessionManagerBase implements SipSessionManager, Lifecycle {
  protected static final Logger logger = LogUtil.SIP_LOGGER.getLogger();
    protected SipFactoryImpl sipFactory = null;

    // Has this SipSessionManager been started?
    protected boolean started;

    // Has this SipSessionManager been initialized?
    protected boolean initialized;
    protected int sessionTimeout;

    // The associated converged context   
    protected ConvergedContextImpl convergedContext;

    // The lifecycle event support.
    protected LifecycleSupport lifecycle = new LifecycleSupport(this);

    /** Handler for managing obsolote sessions. */
    private EventListener obsoleteSessionHandler;

    /*
     * Active cache of SipApplicationSessions.
     *
     * 2-arg (<initialCapacity, loadFactor>) constructor not available on
     * Java 5, specify DEFAULT_CONCURRENCY_LEVEL as 3rd argument
     */
    protected ConcurrentHashMap<String, SipApplicationSessionImpl> applicationSessions = new ConcurrentHashMap<String, SipApplicationSessionImpl>(100, 0.75f, 16);

    // Active cache of SipSessions
    protected Map<String, SipSessionDialogImpl> sipSessions = new ConcurrentHashMap<String, SipSessionDialogImpl>();

    // Active cache of ServletTimers
    protected Map<String, ServletTimerImpl> servletTimers = new ConcurrentHashMap<String, ServletTimerImpl>();
    protected boolean isRepairDuringFailure = true;

    // The application id
    protected String applicationId = null;

    // The cluster id
    protected String clusterId = null;

    protected boolean isBeingReleased = false;


    /**
     * Attach to the Group Membership Service subsystem.
     * Attachment to the GMS subsystem is only if data centric balancing is enabled and Session Replication is not enabled.
     */
    private void attachEventListener() {
        if (EEPersistenceTypeResolver.MEMORY_TYPE.equals(getPersistenceType()) &&
                DataCentricUtilHolder.getInstance().isDataCentricEnabled()) {
            obsoleteSessionHandler = new ObsoleteSessionHandler();
            DataCentricUtilHolder.addEventListener(obsoleteSessionHandler);
        }
    }

    /**
     * Associates the given ConvergedContext with this SipSessionManager.
     *
     * @param context The ConvergedContext with which to associate this
     * SipSessionManager
     */
    public void setContext(ConvergedContext context) {
        convergedContext = (ConvergedContextImpl) context;
    }

    /**
     * Gets the ConvergedContext with which this SipSessionManager has been
     * associated.
     *
     * @return The ConvergedContext with which this SipSessionManager has
     * been associated.
     */
    public ConvergedContext getContext() {
        return convergedContext;
    }

    /**
     * Creates a new SipApplicationSession, and adds it to this session
     * manager's active cache.
     *
     * @param sipApplicationListeners The SipApplicationListeners whose
     * SipApplicationSessionListeners need to be notified of the session
     * creation
     *
     * @return The new SipApplicationSession
     */
    public SipApplicationSessionImpl createSipApplicationSession(
            SipApplicationListeners sipApplicationListeners) {
        String bekey = DataCentricUtilHolder.getInstance().getLocalKey();
        String id = SipApplicationSessionUtil.createSasId(
                bekey, convergedContext.getAppName(), UUIDUtil.randomUUID());
        SipApplicationSessionImpl sess = createNewSipApplicationSession(id);
        // Add to active cache
        initSipApplicationSession(sess, sipApplicationListeners);
        addSipApplicationSession(sess);       
        return sess;
    }

    /**
     * Creates a new SipApplicationSession with the given id, and adds it to
     * this session manager's active cache.
     *
     * @param id The id to assign to the new SipApplicationSession
     * @param sipApplicationListeners The SipApplicationListeners whose
     * SipApplicationSessionListeners need to be notified of the session
     * creation
     *
     * @return The new SipApplicationSession
     */
    public SipApplicationSessionImpl createSipApplicationSession(
            String id, SipApplicationListeners sipApplicationListeners) {
        if (id == null) {
            return createSipApplicationSession(sipApplicationListeners);
        }
        SipApplicationSessionImpl sess = null;

        sess = applicationSessions.get(id);
        if (sess == null) {
            sess = createNewSipApplicationSession(id);
            SipApplicationSessionImpl newsess =
                    applicationSessions.putIfAbsent(id, sess);
            if (newsess != null) {
                sess = newsess;
            }
        }
        initSipApplicationSession(sess, sipApplicationListeners);
        return sess;
    }

    /**
     * Gets the SipApplicationSession with the given id.
     *
     * @return The SipApplicationSession with the given id, or null if not
     * found
     * @throws RemoteLockException
     */
    public SipApplicationSessionImpl findSipApplicationSession(String id) throws RemoteLockException {
        SipApplicationSessionImpl appSessImpl = applicationSessions.get(id);
        if (appSessImpl == null)
            return null;
        initSipApplicationSession(appSessImpl, null);
        return appSessImpl;
       
    }

    /**
     * Gets the SipApplicationSession with the given id.
     *
     * @return The SipApplicationSession with the given id, or null if not
     * found
     * @throws RemoteLockException
     */
    public SipApplicationSessionImpl findSipApplicationSession(String id, boolean force) throws RemoteLockException {
        return findSipApplicationSession(id);
    }

    /**
     * Removes the given SipApplicationSession from this session manager's
     * active cache.
     *
     * @param sas The SipApplicationSession to be removed
     */
    public void removeSipApplicationSession(SipApplicationSessionImpl sas) {
        SipApplicationSessionImpl appSessImpl = applicationSessions.get(sas.getId());

        if (sas == appSessImpl) {
            SipApplicationSessionImpl val = applicationSessions.remove(sas.getId());
            if (logger.isLoggable(Level.FINEST)) {
                logger.log(Level.FINEST, "The application session with ID=" + sas.getId() + " has been removed from the active cache ref:"
                        + sas.getObjectRefString());
            }
        } else {
            // With sessionKey (SAK) feature of jsr289 it is possible to recreate a sas with a given ID
            // When a sas is invalidated and requests targets same sas then ServletDispatcher may find the invalidated sas.
            // In this case it removes the sas from manager and re-create a new sas instance with same ID.
            // But the invalidated sas is also supervised by DialogCleaner.
            // This fix checks that a removal via DialogCleaner only removes the instance that was invalidated
            // and not the newly created one.
            // Note. This class also has potensial non-atomic check-than-act issues but it was decided not to change synchronization policy for resolution of
            // this Issue.

            if (logger.isLoggable(Level.FINEST)) {
                logger.log(Level.FINEST, "Ignore removal of sas with id {0} and referece {1}", new Object[] { sas.getId(), sas.getObjectRefString() });
            }
        }

        SipSessionsUtilImpl ssu = convergedContext.getSipSessionsUtil();

        if (ssu != null) {
            ssu.removeSessionsMapping(sas);
        }
    }

    /**
     * Adds the given SipApplicationSession to this session manager's
     * active cache.
     *
     * @param sas The SipApplicationSession to add
     *
     * @return the previous SipApplicationSession, or null
     */
    public SipApplicationSession addSipApplicationSession(SipApplicationSessionImpl sas) {
        SipApplicationSession ret = null;

        if (sas != null) {
            ret = applicationSessions.put(sas.getId(), sas);
        }

        return ret;
    }

    /**
     * Creates a new SipSession and adds it to the given SipApplicationSession
     * and this session manager's active cache.
     *
     * @param set
     * @param to
     * @param appSession
     * @param handler
     *
     * @return The new SipSession
     */
    public SipSessionDialogImpl createSipSession(DialogSet set, Address to, SipApplicationSessionImpl appSession, String handler) {
        return createSipSession(set, to, appSession, handler, null);
    }

    /**
     * Creates a new SipSession and adds it to the given SipApplicationSession
     * and this session manager's active cache.
     *
     * @param set
     * @param to
     * @param appSession
     * @param handler
     * @type type
     *
     * @return The new SipSession
     */
    public SipSessionDialogImpl createSipSession(DialogSet set, Address to, SipApplicationSessionImpl appSession, String handler, Type type) {
        SipSessionDialogImpl sess = null;

        if (type != null) {
            sess = createNewSipSession(set, to, appSession, handler, type);
        } else {
            sess = createNewSipSession(set, to, appSession, handler, Type.Undefined);
        }

        sipSessions.put(sess.getId(), sess);

        return sess;
    }

    /**
     * Gets the SipSession with the given id.
     *
     * @return The SipSession with the given id, or null if not found
     */
    public SipSessionDialogImpl findSipSession(String id) throws RemoteLockException {
        return sipSessions.get(id);
    }

    public SipSessionDialogImpl findSipSession(String id, boolean loadDependencies) throws RemoteLockException {
        return findSipSession(id);
    }

    /**
     * Removes the given SipSession from this session manager's active cache.
     *
     * The SipSession is also removed from its SipApplicationSession parent,
     * if it had been attached to any.
     *
     * @param sipSession The SipSession to remove
     */
    public void removeSipSession(SipSessionDialogImpl sipSession) {
        if (sipSession != null) {
            sipSessions.remove(sipSession.getId());
        }
    }

    /**
     * Removes the given SipSession from this session manager's active cache.
     *
     * The SipSession is also removed from its SipApplicationSession parent,
     * if it had been attached to any.
     *
     * @param sipSessionId The id of the SipSession to remove
     */
    public void removeSipSession(String sipSessionId) {
        if (sipSessionId != null) {
            sipSessions.remove(sipSessionId);
        }
    }

    /**
     * Adds the given SipSession to this session manager's active cache.
     *
     * @param sipSession The SipSession to add
     *
     * @return the previous SipSession, or null
     */
    public SipSession addSipSession(SipSessionDialogImpl sipSession) {
        SipSession ret = null;

        if (sipSession != null) {
            ret = sipSessions.put(sipSession.getId(), sipSession);
        }

        return ret;
    }

    /**
     * Creates a new ServletTimer.
     *
     * @return The new ServletTimer
     */
    public ServletTimerImpl createServletTimer(SipApplicationSessionImpl sas, Serializable info, long delay, TimerListener listener, boolean isPersistent) {
        ServletTimerImpl timer = createNewServletTimer(sas, info, delay, listener, isPersistent);
        servletTimers.put(timer.getId(), timer);

        return timer;
    }

    /**
     * Creates a new ServletTimer.
     *
     * @return The new ServletTimer
     */
    public ServletTimerImpl createServletTimer(SipApplicationSessionImpl sas, Serializable info, long delay, boolean fixedDelay, long period, TimerListener listener, boolean isPersistent) {
        ServletTimerImpl timer = createNewServletTimer(sas, info, delay, fixedDelay, period, listener, isPersistent);
        servletTimers.put(timer.getId(), timer);

        return timer;
    }

    /**
     * Gets the ServletTimer with the given id.
     *
     * @return The ServletTimer with the given id, or null if not found
     */
    public ServletTimerImpl findServletTimer(String id) throws RemoteLockException {
        return servletTimers.get(id);
    }

    public ServletTimerImpl findServletTimer(String id, boolean loadDependencies) throws RemoteLockException {
        return findServletTimer(id);
    }

    /**
     * Removes the given ServletTimer.
     *
     * @param timer The ServletTimer to be removed
     */
    public void removeServletTimer(ServletTimerImpl timer) {
        if (timer != null) {
            servletTimers.remove(timer.getId());
        }
    }

    /**
     * Adds the given ServletTimer to this session manager's
     * active cache.
     *
     * @param timer The ServletTimer to add
     *
     * @return the previous ServletTimer, or null
     */
    public ServletTimer addServletTimer(ServletTimerImpl timer) {
        ServletTimer ret = null;

        if (timer != null) {
            ret = servletTimers.put(timer.getId(), timer);
        }

        return ret;
    }

    /**
     * Sets the session timeout.
     *
     * @param timeout The session timeout
     */
    public void setSessionTimeout(int timeout) {
        sessionTimeout = timeout;
    }

    /**
     * Gets the session timeout.
     *
     * @return The session timeout
     */
    public int getSessionTimeout() {
        return sessionTimeout;
    }

    /**
     * Sets the repairDuringFailure property of this session manager.
     *
     * @param isRepairDuringFailure The value of the repairDuringFailure
     * property
     */
    public void setRepairDuringFailure(boolean isRepairDuringFailure) {
        this.isRepairDuringFailure = isRepairDuringFailure;
    }

    /**
     * @return True if this session manager should participate in a repair
     * during failure, and false otherwise
     */
    public boolean isRepairDuringFailure() {
        return isRepairDuringFailure;
    }

    /**
     * Starts this SipSessionManager.
     *
     * This method must not be called outside the lifecycle of the
     * associated converged context.
     */
    public void start() throws LifecycleException {
        if (!initialized) {
            init();
        }

        if (started) {
            return;
        }

        started = true;

        sipFactory = SipFactoryImpl.getInstance();

        SipSessionManagerRegistry reg = null;

        if (Globals.IS_SECURITY_ENABLED) {
            reg = (SipSessionManagerRegistry) AccessController.doPrivileged(new PrivilegedGetSipSessionManagerRegistry());
        } else {
            reg = SipSessionManagerRegistry.getInstance();
        }

        if (reg != null) {
            reg.register(this);
        }
    }

    /**
     * Stops this SipSessionManager.
     *
     * This method must not be called outside the lifecycle of the
     * associated converged context.
     */
    public void stop() throws LifecycleException {
        if (!started) {
            throw new LifecycleException("Not started");
        }

        started = false;

        SipSessionManagerRegistry reg = null;

        if (Globals.IS_SECURITY_ENABLED) {
            reg = (SipSessionManagerRegistry) AccessController.doPrivileged(new PrivilegedGetSipSessionManagerRegistry());
        } else {
            reg = SipSessionManagerRegistry.getInstance();
        }

        if (reg != null) {
            reg.unregister(this);
        }

        // TBD Clean up sessions, etc.
    }

    /**
     * Releases any resources held by this SipSessionManager during
     * undeployment.
     *
     * This method also invalidates all of the active SipSessions managed
     * by this SipSessionManager. The invalidation of a SipSession will
     * in turn trigger the invalidation of its associated DialogFragment,
     * which causes the DialogFragment to be removed from its manager.
     */
    public void release() {

        isBeingReleased = true;

        if (obsoleteSessionHandler != null) {
            DataCentricUtilHolder.removeEventListener(obsoleteSessionHandler);
        }

        synchronized (applicationSessions) {
            Iterator<SipApplicationSessionImpl> it = applicationSessions.values().iterator();
            while (it.hasNext()) {
                try {
                    it.next().invalidate();
                } catch (IllegalStateException ise) {
                    // Ignore
                }
            }
        }

        try {
            DialogFragmentManager.getInstance().removeDialogFragments(getApplicationId());
        } catch (IllegalStateException ise) {
            // Ignore
        }

        // Clear all active sessions and timers
        applicationSessions.clear();
        sipSessions.clear();
        servletTimers.clear();
    }

    /**
     * Adds a lifecycle event listener to this SipSessionManager.
     *
     * @param listener The lifecycle event listener to add
     */
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
    }

    /**
     * Gets the lifecycle event listeners of this SipSessionManager.
     *
     * @return Array (possibly of zero length) containing the lifecycle
     * event listeners of this SipSessionManager
     */
    public LifecycleListener[] findLifecycleListeners() {
        return lifecycle.findLifecycleListeners();
    }

    /**
     * Removes the give lifecycle event listener from this
     * SipSessionManager.
     *
     * @param listener The lifecycle event listener to remove
     */
    public void removeLifecycleListener(LifecycleListener listener) {
        lifecycle.removeLifecycleListener(listener);
    }

    /**
     * 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 new SipSessionDialogImpl(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 new SipApplicationSessionImpl(this, id);
    }

    /**
     * Creates a new ServletTimer.
     *
     * @return The new ServletTimer
     */
    protected ServletTimerImpl createNewServletTimer(SipApplicationSessionImpl sas, Serializable info, long delay, TimerListener listener, boolean isPersistent) {
        return new ServletTimerImpl(this, 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) {
        return new ServletTimerImpl(this, sas, info, delay, fixedDelay, period, listener, isPersistent);
    }

    /**
     * Gets the persistence type of this session manager.
     *
     * @return The persistence type of this session manager.
     */
    public String getPersistenceType() {
        return EEPersistenceTypeResolver.MEMORY_TYPE;
    }

    public String getApplicationId() {
        if (applicationId != null) {
            return applicationId;
        }

        Container container = getContext();
        StringBuilder sb = new StringBuilder(50);
        //prepend "SIP:" to distinguish from non-sip manager
        sb.append("SIP:");

        String clusterId = getClusterId();

        if (clusterId != null) {
            sb.append(getClusterId());
        }

        ArrayList<String> list = new ArrayList<String>(5);
                     
        while (container != null) {
            if (container.getName() != null) {
                list.add(":" + container.getName());
            }

            container = container.getParent();
        }

        for (int i = (list.size() - 1); i > -1; i--) {
            String nextString = (String) list.get(i);
            sb.append(nextString);
        }

        applicationId = sb.toString();

        return applicationId;
    }

    /**
     * @return The cluster id as defined in domain.xml
     */
    protected String getClusterId() {
        if (clusterId == null) {
            clusterId = getClusterIdFromConfig();
        }

        return clusterId;
    }

    /**
     * @return The cluster id as defined in domain.xml
     */
    private String getClusterIdFromConfig() {
        ServerConfigLookup lookup = new ServerConfigLookup();

        return lookup.getClusterIdFromConfig();
    }


    /**
     * @return true if this SipSessionManager is being destroyed as part
     * of its associated context being undeployed, and false otherwise
     */
    public boolean isBeingReleased() {
        return isBeingReleased;
    }


    /**
     * Initializes this SipSessionManager.
     */
    private void init() {
        if (initialized) {
            return;
        }

        attachEventListener();

        initialized = true;
    }

    private void initSipApplicationSession(SipApplicationSessionImpl sas, SipApplicationListeners sipApplicationListeners) {
        // If the SAS is already initialized don't enter synchronized block (issue 1953)
        if (sas.isInitialized()) {
            return;
        }
        synchronized (sas.getSasObjectLock()) {
            if (sas.isInitialized()) {
                return;
            }
            sas.setName(getContext().getAppName());
            SipApplicationListeners appListeners =
                    sas.getSipApplicationListeners();
            if (appListeners != null) {
                ArrayList<SipApplicationSessionListener> listeners =
                        appListeners.getSipApplicationSessionListeners();

                SipApplicationSessionEvent event =
                        new SipApplicationSessionEvent(sas);

                for (Iterator<SipApplicationSessionListener> iter =
                        listeners.iterator();
                        iter.hasNext();) {
                    SipApplicationSessionListener listener = iter.next();
                    listener.sessionCreated(event);
                }
            }

            sas.initAppSessionTimer(sessionTimeout);
            sas.setIsInitialized(true);
        }
    }

    public void logActiveObjects() {
        if (logger.isLoggable(Level.FINEST)) {
            StringBuffer sb = new StringBuffer();
            sb.append("\nActive Objects in Application: ").append(getApplicationId()).append('\n');

            for (Map.Entry<String, SipApplicationSessionImpl> sasEntry : applicationSessions.entrySet()) {
              SipApplicationSessionImpl sas = sasEntry.getValue();
                sb.append("  SAS: ").append(sasEntry.getKey()).append(" ref: ").append(sas.getObjectRefString()).append(" isValid:").append(sas.isValid()).append('\n');  
            }

            for (Map.Entry<String, SipSessionDialogImpl> ssEntry : sipSessions.entrySet()) {
                SipSessionDialogImpl ss = ssEntry.getValue();
                String creationDate = " at: "+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(ss.getCreationTime()));
                sb.append("  SS: ").append(ssEntry.getKey()).append(creationDate).append(" isValid:").append(ss.isValid()).append('\n');
            }

            for (Map.Entry<String, ServletTimerImpl> stEntry : servletTimers.entrySet()) {
                sb.append("  ST: ").append(stEntry.getKey()).append('\n');
            }

            logger.log(Level.FINEST, sb.toString());
        }
    }

    /**
     * Handling of obsolote sessions.
     * During failover the sessions are served by another server instance accordingly to the datacentric balancing.
     * When the failing node is returned back to service,
     * the sessions needs to be removed and established on the current recoved instance.
     *
     * The procedure removes all the sip application sessions that are not longer handled by this server instance.
     *
     * @author Adrian Szwej
     *
     */
    class ObsoleteSessionHandler implements EventListener {
        /** How long time to wait until starting the session iteration.
         */
        public static final long BACK_OFF_TIMER = 32000L;

        /** Timer handling the execution after backoff time has elapsed. */
        private GeneralTimer backOffTimer = null;

        /**
         * Constructor.
         * @param clusterName The name of the cluster to operate on.
         * @throws CLBRuntimeException
         */
        public ObsoleteSessionHandler(){
        }

        /**
         * Triggered when an instance has joined the cluster and is in service.
         * @param clusterName the source cluster
         * @param instanceName the name of the instance that has become ready for service
         *
         */
        public void onRecovery(String clusterName, String instanceName, boolean isClusterStartup) {
            startBackOffTimer();
        }

        public void onEnable(String clusterName, String instanceName) {
            startBackOffTimer();
        }
       
        public void onAdd(String clusterName, String instanceName,
                boolean lbEnabled) {
            startBackOffTimer();
        }
       
        public void onFailure(String clusterName, String instanceName, boolean isClusterShutdown) {
        }

        public void onDisable(String clusterName, String instanceName) {
        }

        public void onDelete(String clusterName, String instanceName) {
        }
       
        /**
         * Starts the backoff timer. If there is any timer already active, cancel that timer and issue a new one.
         */
        private void startBackOffTimer() {
            synchronized (getLock()) {
                if (backOffTimer != null) {
                    backOffTimer.cancel();
                }

                backOffTimer = TimerServiceImpl.getInstance().createTimer(new BackOffTimerListener(), BACK_OFF_TIMER, null);
            }
        }

        /**
         * Gets the instance for this obsolote sessionhandler.
         * @return reference of this handler.
         */
        private Object getLock() {
            return this;
        }

        /**
         * Removes all the sessions that are not longer belonging to this instance.
         */
        private Iterator<SipApplicationSession> removeObsoloteSessions() {
           
            //separate Set to exclude the invalidation time for the sessions
            Set<SipApplicationSession> invalidationSet = new HashSet<SipApplicationSession>();

            synchronized (applicationSessions) {
                Iterator<SipApplicationSessionImpl> it = applicationSessions.values().iterator();

                while (it.hasNext()) {
                    SipApplicationSessionImpl sas = it.next();

                    if (!DataCentricUtilHolder.getInstance().isLocal(sas.getBeKey())) {
                        invalidationSet.add(sas);
                    }
                }
            }

            return invalidationSet.iterator();
        }

        /**
         * Perform the actual invalidation outside the synchronization block.
         */
        private void performInvalidation(Iterator<SipApplicationSession> it) {
            while (it.hasNext()) {
                try {
                    it.next().invalidate();
                } catch (IllegalStateException ise) {
                    // Ignore
                }
            }
        }

        /**
        * This backoff timer will consider the switchover glitch where sas could be created and added just before the iteration.
        * The backoff timer makes sure no more obsolote sas references are in the session manager after the sas iteration.
        *
        * A second purpose of backoff timer is to postpone the session iteration in situations
        * where many instances are joining the cluster at the same time, e.g during HW upscale or cluster restart.
        */
        private class BackOffTimerListener implements GeneralTimerListener {
            public void timeout(GeneralTimer timer) {
                Iterator<SipApplicationSession> it = null;

                synchronized (getLock()) {
                    if (backOffTimer == timer) {
                        it = removeObsoloteSessions();

                        //unreference for garbage collection
                        backOffTimer = null;
                    } else {
                        //dont do anything, there is another timer started later on that will handle the invalidation process
                    }
                }

                if (it != null) {
                    performInvalidation(it);
                }
            }
        }
    }
}
TOP

Related Classes of com.ericsson.ssa.sip.SipSessionManagerBase$ObsoleteSessionHandler$BackOffTimerListener

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.