Package com.ericsson.ssa.sip

Source Code of com.ericsson.ssa.sip.SipApplicationSessionBase

/*
* 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.Constants;
import com.ericsson.ssa.config.SipFactoryFacade;
import com.ericsson.ssa.config.ConvergedContext;
import com.ericsson.ssa.container.sim.ApplicationDispatcher;
import com.ericsson.ssa.container.sim.ServletDispatcher;
import org.jvnet.glassfish.comms.deployment.backend.SipApplication;
import org.jvnet.glassfish.comms.deployment.backend.SipApplicationListeners;

import com.ericsson.ssa.sip.dialog.Cleanable;
import com.ericsson.ssa.sip.dialog.DialogCleaner;
import com.ericsson.ssa.sip.timer.GeneralTimer;
import com.ericsson.ssa.sip.timer.GeneralTimerImpl;
import com.ericsson.ssa.sip.timer.GeneralTimerListener;
import com.ericsson.ssa.sip.timer.ServletTimerImpl;
import com.ericsson.ssa.sip.timer.TimerServiceImpl;

import com.sun.enterprise.ee.web.sessmgmt.EEPersistenceTypeResolver;

import com.sun.enterprise.util.LocalStringManagerImpl;
import org.apache.catalina.session.SessionLock;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import java.net.MalformedURLException;
import java.net.URL;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import org.jvnet.glassfish.comms.util.LogUtil;
import java.util.logging.Logger;

import javax.servlet.http.HttpSession;
import javax.servlet.sip.ServletTimer;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipApplicationSessionActivationListener;
import javax.servlet.sip.SipApplicationSessionEvent;
import javax.servlet.sip.SipApplicationSessionListener;
import javax.servlet.sip.SipSession;
import javax.servlet.sip.TimerListener;
import javax.servlet.sip.URI;


/**
* Implementation of the SSA interface <code>SipApplicationSession</code>.<br>
* These methods can be called from the servlet code.
* <ol>
* <li>{@link #encodeURI(URI)}} Not Implmented !</li>
* <li>{@link #getAttribute(String)}</li>
* <li>{@link #getAttributeNames()}</li>
* <li>{@link #getCreationTime()}</li>
* <li>{@link #getId()}</li>
* <li>{@link #getLastAccessedTime()} Not Implemented !</li>
* <li>{@link #getSessions()}</li>
* <li>{@link #getSessions(String)}</li>
* <li>{@link #getTimers()}</li>
* <li>{@link #invalidate()}</li>
* <li>{@link #removeAttribute(String)}</li>
* <li>{@link #setAttribute(String, Object)}</li>
* <li>{@link #setExpires(int)}</li>
* </ol>
*
* @author ehsroha
* @Etag reviewed by ehsroha, removeSession method.
* @reviewed ejoelbi 2007-jan-17
*/
public abstract class SipApplicationSessionBase implements SipApplicationSession,
    GeneralTimerListener, Cleanable, Externalizable {
    public static final String APP_LOCK_ATTR_NAME = "com.ericsson.ssa.sip.SipApplicationSession.applicationLock";

    private static final long serialVersionUID = 1972145565288132288L;

    /** The serialized format versioning. 1 = first version. */
    private static final short serializedFormVersion = 1;

    private static final int DEFAULT_SAS_TIMEOUT = 3; // 3 minutes -- in accordance with the spec
    private static Logger logger = LogUtil.SIP_LOGGER.getLogger();
    private static ApplicationDispatcher applicationDispatcher = ApplicationDispatcher.getInstance();
    private static TimerServiceImpl timerService = TimerServiceImpl.getInstance();
    protected boolean isValid = true;
    /**
     * Flag indicating whether application will be notified when this session
     * transitions to ready-to-invalidate state.
     */
    private volatile boolean invalidateWhenReady = true;
    /**
     * Flag indicating whether the session is in ready-to-invalidate
     * state or not.
     */
    private volatile boolean readyToInvalidate = false;
    protected int deltaSessionTimeout = 0;
    private String currentServlet = null;
    protected transient GeneralTimerImpl sasTimer;
    private final SessionLock sessionLock = new SessionLock();

    // All SSA methods are synchronized using this lock.
    private final Object sasObjectLock = new Object();

    // The lock used by applications to lock the SAS and all its children.
    private final Object sasApplicationLock = new Object();
    private boolean invalidateInProgress;
    private volatile boolean explicitlyInvalidated;
    private boolean applicationLockUsed;
    protected static final LocalStringManagerImpl localStrings =
            new LocalStringManagerImpl(SipApplicationSessionBase.class);
    private volatile boolean isInitialized = false;
    /**
     * Constructor for serialization.
     */
    public SipApplicationSessionBase() {
    }

    public boolean isInitialized() {
        return isInitialized;
    }

    public void setIsInitialized(boolean initialized) {
        isInitialized = initialized;
    }
 
    // ---- SSA Methods ----

    /**
     * @see javax.servlet.sip.SipApplicationSession#encodeURI(URI)
     */
    public void encodeURI(URI uri) {
        synchronized (sasObjectLock) {
            validateSessionState();
        }

        if (getBeKey() != null) {
            UriUtil.setAndEncodeParameter(uri, URIImpl.BEKEY_PARAM, getBeKey());
        }

        UriUtil.setAndEncodeParameter(uri, URIImpl.SASID_PARAM, getId());
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#getAttribute(java.lang.String)
     */
    public Object getAttribute(String key) {
        synchronized (sasObjectLock) {
            validateSessionState();

            if (APP_LOCK_ATTR_NAME.equals(key)) {
                setApplicationLockUsed();

                return sasApplicationLock;
            }

            return getPFieldApplicationAttribute(key);
        }
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#getAttributeNames()
     */
    public Iterator<String> getAttributeNames() {
        synchronized (sasObjectLock) {
            validateSessionState();

            return getPFieldApplicationAttributeNames();
        }
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#getCreationTime()
     */
    public long getCreationTime() {
        synchronized (sasObjectLock) {
            validateSessionState();

            return getPFieldCreationDate();
        }
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#getId()
     */
    public abstract String getId();

    /**
     * Not implemented.
     *
     * @see javax.servlet.sip.SipApplicationSession#getLastAccessedTime()
     */
    @SuppressWarnings("unchecked")
    public long getLastAccessedTime() {
        synchronized (sasObjectLock) {
            long lastAccessedTime = -1;

            Iterator<SipSession> sipSessIter = (Iterator<SipSession>)
            getSessions(SipFactoryImpl.SIP_URI_PROTOCOL, true);
            while (sipSessIter.hasNext()) {
                long sessAccessTime = sipSessIter.next().getLastAccessedTime();
                if (sessAccessTime > lastAccessedTime) {
                    lastAccessedTime = sessAccessTime;
                }
            }

            Iterator<HttpSession> httpSessIter = (Iterator<HttpSession>)
            getSessions(SipFactoryImpl.HTTP_URI_PROTOCOL, true);
            while (httpSessIter.hasNext()) {
                long sessAccessTime = httpSessIter.next().getLastAccessedTime();
                if (sessAccessTime > lastAccessedTime) {
                    lastAccessedTime = sessAccessTime;
                }
            }
            return lastAccessedTime;
        }
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#getSessions()
     */
    public Iterator<?> getSessions() {
        synchronized (sasObjectLock) {
            validateSessionState();

            ArrayList<Object> list = new ArrayList<Object>(5);

            for (SipSessionBase sess : getPFieldSipSessions()) {
                if (sess != null) {
                    list.add(sess);
                }
            }

            for (HttpSession sess : getPFieldHttpSessions()) {
                if (sess != null) {
                    list.add(sess);
                }
            }

            return list.iterator();
        }
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#getSessions(java.lang.String)
     */
    public Iterator<?> getSessions(String protocol) {
        return getSessions(protocol, false);
    }

    /**
     * Gets all sessions of the given protocol (HTTP or SIP).
     *
     * @param protocol The requested protocol
     * @param activeOnly true if only the currently active sessions should
     * be returned, false otherwise
     */
    public Iterator<?> getSessions(String protocol, boolean activeOnly) {
        if (protocol == null)
            throw new NullPointerException("Argument protocol is null");

        synchronized (sasObjectLock) {

            validateSessionState();

            if (SipFactoryImpl.SIP_URI_PROTOCOL.equalsIgnoreCase(protocol)) {

                ArrayList<SipSession> ss = new ArrayList<SipSession>(5);

                if (activeOnly) {
                    for (SipSessionBase sess : getPFieldSipSessionsActiveOnly()) {
                        if (sess != null) {
                            ss.add(sess);
                        }
                    }
                } else {
                    for (SipSessionBase sess : getPFieldSipSessions()) {
                        if (sess != null) {
                            ss.add(sess);
                        }
                    }
                }

                return ss.iterator();

            } else if (SipFactoryImpl.HTTP_URI_PROTOCOL.equalsIgnoreCase(
                        protocol)) {

                ArrayList<HttpSession> sw = new ArrayList<HttpSession>(5);

                if (activeOnly) {
                    for (HttpSession sess : getPFieldHttpSessionsActiveOnly()) {
                        if (sess != null) {
                            sw.add(sess);
                        }
                    }
                } else {
                    for (HttpSession sess : getPFieldHttpSessions()) {
                        if (sess != null) {
                            sw.add(sess);
                        }
                    }
                }

                return sw.iterator();

            } else {
                throw new IllegalArgumentException("Protocol is not understood by container");
                // return Collections.EMPTY_LIST.iterator();
            }
        }
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#getTimers()
     */
    public Collection<ServletTimer> getTimers() {
        synchronized (sasObjectLock) {
            validateSessionState();

            return getPFieldApplicationTimers();
        }
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#invalidate()
     */
    public void invalidate() {
        synchronized (sasObjectLock) {
            if (this.invalidateInProgress) {
                this.explicitlyInvalidated = true;
                return;
            }
        }
        // if called from SipServlet code
        invalidate(false);
    }

    public String getApplicationName() {
        return getPFieldApplicationName();
    }
  

   public ServletTimer getTimer(String id) {
       validateSessionState();
       synchronized (sasObjectLock) {
           return getPFieldApplicationTimer(id);
       }
   }

    /**
     * @see javax.servlet.sip.SipApplicationSession#removeAttribute(java.lang.String)
     */
    public void removeAttribute(String key) {
        synchronized (sasObjectLock) {
            validateSessionState();
            removePFieldApplicationAttribute(key);
        }
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#setAttribute(java.lang.String,
     *      java.lang.Object)
     */
    public void setAttribute(String key, Object value) {
        if (key == null)
            throw new NullPointerException("Argument key is null");
        if (value == null)
            throw new NullPointerException("Argument valu is null");
        synchronized (sasObjectLock) {
            if (APP_LOCK_ATTR_NAME.equals(key)) {
                return; // Ignore, it is not allowed to change the lock.
            }

            validateSessionState();
            setPFieldApplicationAttribute(key, value);
        }
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#setExpires(int)
     */
    public int setExpires(int deltaMinutes) {
       
        synchronized (sasObjectLock) {
            validateSessionState();
        }
       
        if (deltaMinutes < 1) {
            // Container does not allow infinite expiration time
            // In JSR289 returning 0 means rejection
            return 0; // reject extention
        }
       
        /**
         * During SAS timeout handling, if the extension is requested on the
         * explicitly invalidated SAS then such a request should be rejected.
         */
        if(explicitlyInvalidated) {
            return 0;
        }
       
        synchronized (sasObjectLock) {
           
            if (sasTimer != null) {
                sasTimer.cancel();
            }

            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE,
                    "Started timer, session-timeout:" + deltaMinutes);
            }

            deltaSessionTimeout = deltaMinutes;

            long expirationTime = System.currentTimeMillis() +
                (deltaSessionTimeout * 60 * 1000L);
            sasTimer = (GeneralTimerImpl) timerService.createTimer((GeneralTimerListener) this,
                    deltaSessionTimeout * 60 * 1000L, null);
            setPFieldExpirationTime(expirationTime);

            return deltaSessionTimeout;
        }
    }

    // ---- Methods used internally by the container ----

    /**
     * Called when the object is created <br>
     * see {@link SipFactoryFacade#createApplicationSession()}. <br>
     * This method is <b>not</b> thread safe
     */
    public void initAppSessionTimer(int sessionTimeout) {
        // start applicationSessionTimer
        int configuredSessionTimeout = -1;

        if (sessionTimeout == SipApplication.UNKNOWN_TIMEOUT_VALUE) {
            configuredSessionTimeout = DEFAULT_SAS_TIMEOUT;

            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE,
                    "session-timeout not configured, using default:" +
                    configuredSessionTimeout);
            }
        } else {
            configuredSessionTimeout = sessionTimeout;
        }

        if (configuredSessionTimeout >= 1) {
            setPFieldExpirationTime(System.currentTimeMillis() +
                (configuredSessionTimeout * 60 * 1000L));
            // TODO currently assume this "internal" timer should not be
            // included
            // in m_applicatinonTimers
            sasTimer = (GeneralTimerImpl) timerService.createTimer((GeneralTimerListener) this,
                    (configuredSessionTimeout * 60 * 1000L), null);

            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE,
                    "Started timer defined in sip.xml : session-timeout:" +
                    configuredSessionTimeout);
            }
        } else {
            setPFieldExpirationTime(-1L);

            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE,
                    "No default timer, sip.xml : session-timeout:" +
                    configuredSessionTimeout);
            }
        }

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE, "app:" + getName() + " " + this);
        }
    }

    protected void restartAppSessionTimer() {
        long expTime = getPFieldExpirationTime();

        if (expTime > 0) {
            if (sasTimer != null) {
                sasTimer.cancel();
            }
           
            if(expTime < System.currentTimeMillis()) {
                //call timeout which either extends or invalidates
                timeout(null);
            } else {
                sasTimer = (GeneralTimerImpl) timerService.createTimer((GeneralTimerListener) this,
                        expTime - System.currentTimeMillis(), null);
            }
        } else {
            // nothing to do
            //FIXME - doing nothing means that the infinite
            //case truly never expires - do we want this?
        }
    }

    /**
     * Called when the timer associated with the <code>session-timeout</code>
     * in sip.xml expires. see {@link #initAppSessionTimer()}. {@inheritDoc}
     */
    public void timeout(GeneralTimer timer) {
        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE, "app session timeout:" + getName());
        }

        // What happens if there are several listeners and they "disagree"
        // about
        // the extension of the session
        // (1),(3),(2) --> last setExpire() wins The first two gets canceled
        synchronized (sasObjectLock) {
            if (!isValid){
                // no need to do anything if we are already invalidated
                return;
            }
            deltaSessionTimeout = 0; // reset delta, now let the listeners
            // extend
            // when the invalidateInProgress=true a call to invalidate() will
            // have
            // no effect.
            this.invalidateInProgress = true;
        }

        // "lifetime"
        boolean shouldExtend = false;

        Iterator<SipApplicationSessionListener> iter = getSipApplicationListeners()
        .getSipApplicationSessionListeners()
        .iterator();

        SipApplicationSessionEvent sasEvent = new SipApplicationSessionEvent(this);
        while (iter.hasNext() && !explicitlyInvalidated) {
            SipApplicationSessionListener listener = iter.next();

            try {
                listener.sessionExpired(sasEvent);
            } catch (Throwable t) {
                logger.log(Level.WARNING, "sas_listener_session_expired_invocation_error", this);
                logger.log(Level.WARNING, t.getMessage(), t);
            }

            // Synced to capture accidental setExpires invocations during
            // the timeout handling.
            synchronized(sasObjectLock) {
                if (deltaSessionTimeout >= 1) {
                    shouldExtend = true;

                    break;
                }
            }
        }
       
        synchronized (sasObjectLock) {
            this.invalidateInProgress = false;
        }

        if ((!shouldExtend || explicitlyInvalidated) && isValid()) {
            try {
                invalidate(true);
            } catch (IllegalStateException ignore) {
                // short term solution for race (Issue 1371)
                // sas might have been invalidated after isValid() returned....
                // we can ignore this exception since invalidation already
                // happened
            }
        }
    }


    /**
     * Notifies any interested session attributes that this
     * SipApplicationSession has been activated.
     */
    protected void notifySessionDidActivate() {     
      SipApplicationSessionEvent sasEvent = new SipApplicationSessionEvent(this);
     
      // Notify all SipApplicationSessionActivationListeners in xml
      ArrayList<SipApplicationSessionActivationListener> listeners = getSipApplicationListeners().getSipApplicationSessionActivationListener();
      for(SipApplicationSessionActivationListener l : listeners) {
            l.sessionDidActivate(sasEvent);
      }
     
      // Notify all attributes implementing SipApplicationSessionActivationListener
        Iterator<String> attrNames = getAttributeNames();

        if (attrNames == null) {
            return;
        }
       
        while (attrNames.hasNext()) {
            String attrName = attrNames.next();
            Object attrValue = getAttribute(attrName);

            if (attrValue instanceof SipApplicationSessionActivationListener) {
                ((SipApplicationSessionActivationListener) attrValue).sessionDidActivate(sasEvent);
            }
        }
    }

    /**
     * Notifies any interested session attributes that this
     * SipApplicationSession is about to be passivated.
     */
    protected void notifySessionWillPassivate() {
      SipApplicationSessionEvent sasEvent = new SipApplicationSessionEvent(this);
     
      // Notify all SipApplicationSessionActivationListeners in xml
      ArrayList<SipApplicationSessionActivationListener> listeners = getSipApplicationListeners().getSipApplicationSessionActivationListener();
      for(SipApplicationSessionActivationListener l : listeners) {
            l.sessionWillPassivate(sasEvent);
      }
     
      // Notify all attributes implementing SipApplicationSessionActivationListener
        Iterator<String> attrNames = getAttributeNames();

        if (attrNames == null) {
            return;
        }

        while (attrNames.hasNext()) {
            String attrName = attrNames.next();
            Object attrValue = getAttribute(attrName);

            if (attrValue instanceof SipApplicationSessionActivationListener) {
                ((SipApplicationSessionActivationListener) attrValue).sessionWillPassivate(sasEvent);
            }
        }
    }

    /**
     * See if the session is valid or not.
     *
     * @return true if the session has not been invalidated yet. no call to
     *         {@link #invalidate()} has been made or the session-timeout in
     *         sip.xml has not yet expired.
     */
    public boolean isValid() {
        synchronized (sasObjectLock) {
            return isValid;
        }
    }

    // -------- SIP Session Attributes -------------
    /**
     * @return Returns the name.
     */
    public String getName() {
        synchronized (sasObjectLock) {
            return getPFieldApplicationName();
        }
    }

    public void setName(String applicationName) {
        synchronized (sasObjectLock) {
            setPFieldApplicationName(applicationName);
        }
    }

    public void addSession(SipSessionBase session) {
        synchronized (sasObjectLock) {
            validateSessionState();
            addSipProtocolSession(session);
        }
    }

    public void removeSession(SipSessionBase session) {
        synchronized (sasObjectLock) {
          // a SAS does not have to be valid in order to allow removal of a SS
          // it can happen that the SAS is already invalid in some raceconditions
//            validateSessionState();
            removePFieldSipProtocolSession(session);
        }
    }

    /**
     * @param session
     */
    public void addSession(HttpSession session) {
        synchronized (sasObjectLock) {
            addPFieldHttpProtocolSession(session);
        }
    }

    public void removeSession(HttpSession session) {
        removeSession(session, true);
    }

    public void removeSession(HttpSession session, boolean removeFromManager) {
        synchronized (sasObjectLock) {
            removePFieldHttpProtocolSession(session, removeFromManager);
        }
    }

    /**
     * @param st
     */
    public void addServletTimer(ServletTimerImpl st) {
        synchronized (sasObjectLock) {
            addPFieldApplicationTimer(st);
        }
    }

    /**
     * @param st
     */
    public void cancelServletTimer(ServletTimer st) {
        synchronized (sasObjectLock) {
            removePFieldApplicationTimer((ServletTimerImpl) st);
        }
    }

    /**
     * @return Returns the m_SipApplicationListeners.
     */
    public abstract SipApplicationListeners getSipApplicationListeners();

    /**
     * @return
     */
    public TimerListener getTimerListener() {
        synchronized (sasObjectLock) {
            validateSessionState();

            return getSipApplicationListeners().getTimerListener();
        }
    }

    public void setCurrentServlet(String servlet) {
        synchronized (sasObjectLock) {
            this.currentServlet = servlet;
        }
    }

    public String getCurrentServlet() {
        synchronized (sasObjectLock) {
            return currentServlet;
        }
    }

    public ServletDispatcher getServletDispatcher() {
        synchronized (sasObjectLock) {
            return applicationDispatcher.getServletDispatcher(getName());
        }
    }

    /**
     * Can be called from servlet Thread and the
     * <code>m_applicationSessionTimer</code> thread. Note! All calls to this
     * methods should synchronize on SIP_APP_LOCK
     *
     * @param hasTimedOut
     */
    protected void invalidate(boolean hasTimedOut) {
        synchronized (sasObjectLock) {
            if(!isValid()) {
                throw new IllegalStateException(localStrings.getLocalString(
                "sas_already_invalid",
                "Should not call invalidate() when the application session " +
                "is not valid."));
            }
            // first cancel the application timer cancel if any
            if (sasTimer != null) {
                // do not call with mayInterruptIfRunning=true, because we may
                // interrupt the current thread.
                if (hasTimedOut) {
                    sasTimer.cancel();
                } else {
                    // Try to force the timer to stop if invalid() is called from
                    // servlet code.
                    sasTimer.cancel(true);
                }
            }

            cancelAllServletTimers();
            notifyAttributesUnbound();
            // Invalidate session, important that the m_IsValid before invalidating
            // the SipSessions.
            isValid = false;
        }

        // Call ApplicationSession listener session destroyed
        ArrayList<SipApplicationSessionListener> listeners = getSipApplicationListeners()
        .getSipApplicationSessionListeners();

        SipApplicationSessionEvent sasEvent = new SipApplicationSessionEvent(this);
        for (Iterator<SipApplicationSessionListener> lIter = listeners.iterator();
                lIter.hasNext();) {
            SipApplicationSessionListener list = lIter.next();

            try {
                list.sessionDestroyed(sasEvent);
            } catch (Throwable t) {
                logger.log(Level.WARNING, "sas_listener_session_destroyed_invocation_error", this);
        logger.log(Level.WARNING, t.getMessage(), t);
            }
        }

        Iterable<SipSessionBase> sipSessions = null;
        Iterable<HttpSession> httpSessions = null;
        synchronized (sasObjectLock) {
            sipSessions = getPFieldSipSessions();
            httpSessions = getPFieldHttpSessions();
        }
        boolean atLeastOneSSExisted = false;
        for (SipSessionBase sess : sipSessions) {
            // Session may have been explicitly invalidated....
            atLeastOneSSExisted = true;
            if ((sess != null) && sess.isValid()) {
                try {
                    sess.invalidate(hasTimedOut);
                } catch (Throwable t) {
                    if (logger.isLoggable(Level.FINE)) {
                        logger.log(Level.FINE,
                                "sip_session_unable_to_invalidate", sess);
                        logger.log(Level.FINE, t.getMessage(), t);
                    }
                }
            }
        }
       
        if (!atLeastOneSSExisted) {
            DialogCleaner.getInstance().registerForSupervision(
                    this, DialogCleaner.NO_DIALOG_TIMEOUT);
        }

        // Clean the HttpSession
        for (HttpSession sess : httpSessions) {
            // Session may have been explicitly invalidated....
            if (sess != null) {
                try {
                    // Session may have been explicitly invalidated....
                    sess.invalidate();
                } catch (Throwable t) {
                    if (logger.isLoggable(Level.FINE)) {
                        logger.log(Level.FINE,
                                "http_session_unable_to_invalidate", sess);
                        logger.log(Level.FINE, t.getMessage(), t);
                    }
                }
            }
        }

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE, "Done invalidating " + this);
        }
    }

    public boolean isReadyToInvalidate() {
        return isReadyToInvalidate(true);
    }

    public boolean getInvalidateWhenReady() {
        validateSessionState();
        return invalidateWhenReady;
    }
   
    public void setInvalidateWhenReady(boolean iwr) {

        validateSessionState();

        boolean wasInvalidateWhenReady;
        synchronized (sasObjectLock) {
            if(iwr == invalidateWhenReady) {
                return;
            }
            wasInvalidateWhenReady = invalidateWhenReady;
            invalidateWhenReady = iwr;
        }
        /*
         * If IWR was already true, then we should do nothing.
         * Otherwise we will cause an infinite loop if setInvalidateWhenReady(true)
         * is called from listener's sessionReadyToInvalidate callback.
         */
        if (!wasInvalidateWhenReady) {
            if (checkSessionReadyToInvalidate()) { // we should notify the listeners in this case.
                sessionReadyToInvalidate(); // don't hold ssLock while notifying.
            }
        }

        if (logger.isLoggable(Level.FINE)) {
            if (invalidateWhenReady) {
                logger.log(Level.FINE,
                        "Invalidate-When-Ready machanism is enabled for " + this);
            } else {
                logger.log(Level.FINE,
                        "Invalidate-When-Ready machanism is disabled for " + this);
            }
        }
    }

    protected void initInvalidateWhenReady() {
        SipSessionManager manager = getSipSessionManager();
        if (manager != null) {
            ConvergedContext ctx = manager.getContext();
            if (ctx != null) {
                SipApplication descriptor = ctx.getSipApplication();
                if (descriptor != null &&
                        SipApplication.ApplicationVersion.VERSION_1_0.equals(
                                descriptor.getApplicationVersion())) {
                    invalidateWhenReady = false;
                    return;
                }
            }
        }
        invalidateWhenReady = true;
    }


    private boolean isReadyToInvalidate(boolean validateSession) {
        if(validateSession) {
            validateSessionState();
        }
        if (!readyToInvalidate) {
            synchronized(sasObjectLock) {
                readyToInvalidate = isEmpty();
            }
        }
        return readyToInvalidate;
    }

    protected void setReadyToInvalidate(boolean val) {
        readyToInvalidate = val;
    }

    /**
     * This method does not check for the validity of the session.
     */
    protected  boolean checkSessionReadyToInvalidate() {
        if(invalidateWhenReady && isReadyToInvalidate(false)) {
            return true;
        }
        return false;
    }

    /**
     * This method is called when this SAS becomes ready-to-invalidate.
     * It can happen in the following cases:
     *
     * (a) The last protocol session belonging to this SAS is invalidated
     * (b) The last ServletTimer associated with this SAS expires.
     * (c) The application calls setInvalidateWhenReady(true) when IWR was false
     *     earlier but the SAS is already in ready-to-invalidate state.
     *
     */
    protected void sessionReadyToInvalidate() {
        if (isValid()) {
            notifySessionReadyToInvalidate(); // notify the application listeners.
            if (invalidateWhenReady && isValid()) {
                // application is OK to do invalidaion & has not invalidated explicitly.
                if(logger.isLoggable(Level.FINE)) {
                    logger.log(Level.FINE, "Invalidating " + this + " which is in" +
                            " ready-to-invalidate state");
                }
                invalidate();
            }
        }
    }

    protected void notifySessionReadyToInvalidate() {
        SipApplicationListeners listeners = getSipApplicationListeners();
        if (listeners == null) {
            return;
        }
        List<SipApplicationSessionListener> sasListeners =
                listeners.getSipApplicationSessionListeners();
        Iterator<SipApplicationSessionListener> iter = sasListeners.iterator();
        SipApplicationSessionEvent event = new SipApplicationSessionEvent(this);
        /**
         * Stop notifying the listeners if any of the following occur:
         *
         * (a) one of the listener invoked setInvalidateWhenReady(false)
         * (b) this session is no longer valid, may be because the listener
         *     has invoked invalidate() explicitly.
         */
        while (iter.hasNext() && invalidateWhenReady && isValid()) {
            SipApplicationSessionListener listener = iter.next();
            try {
                listener.sessionReadyToInvalidate(event);
            } catch (Throwable t) {
                logger.log(Level.WARNING, t.getMessage(), t);
            }
        }
    }

    protected abstract void notifyAttributesUnbound();

  /**
     * Note! All calls to this MUST synchronize on SIP_APP_LOCK.
     */
    private void cancelAllServletTimers() {
        for (ServletTimer timer : getTimers()) {
            if (logger.isLoggable(Level.FINER)) {
                logger.log(Level.FINER, "cancel timer:" + timer.toString());
            }

            // terminate timer with force i.e. thread may be interrupted
            // to avoid "zombie" timers
            // application should cancel its own timers if thread
            // interruption
            // during appsession invalidate is not acceptable
            ((ServletTimerImpl) timer).cancel(true);
        }
    }

    private void validateSessionState() {
        if(!isValid()) {
            throw new IllegalStateException(localStrings.getLocalString(
                    "sas_invalid", "SipApplicationSession is not valid."));
        }
    }

    public SipSession getSipSession(String id) {
        if (id == null) {
            throw new NullPointerException();
        }

        for (Iterator<?> i = getSessions(SipFactoryImpl.SIP_URI_PROTOCOL);
                i.hasNext();) {
            SipSession s = (SipSession) i.next();
            if (s.getId().equals(id)) {
                // match...
                return s;
            }
        }

        // no match...
        return null;
    }

    public Object getSession(String id, Protocol protocol) {
        if(id == null) {
            throw new NullPointerException(localStrings.getLocalString(
                    "get_session_null_id",
                    "Can not retrieve a session using null id."));
        }
        if(protocol == null) {
            throw new NullPointerException(localStrings.getLocalString(
                    "get_session_null_protocol",
                    "Can not retrieve a session using null protocol."));
        }
        if(!isValid()) {
            throw new IllegalStateException(localStrings.getLocalString(
                    "get_session_sas_invalid",
                    "Can not call getSession after the SipApplicationSession has been invalidated."));
        }
        if(protocol.equals(Protocol.SIP)) {
            return getPFieldSipSession(id);
        }
        if(protocol.equals(Protocol.HTTP)) {
            return getPFieldHttpSession(id);
        }
        return null;
    }
   
    public URL encodeURL(URL url) {
        validateSessionState();

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

        String path = url.getPath();
        String query = url.getQuery();

        String anchor = "";
        int pound = path.indexOf('#');

        if (pound >= 0) {
            anchor = path.substring(pound);
            path = path.substring(0, pound);
        }

        StringBuilder encoded = new StringBuilder(url.getProtocol());
        encoded.append("://");
        encoded.append(url.getHost());
        encoded.append(":");
        encoded.append(url.getPort());
        encoded.append(path);
        encoded.append(Constants.SAS_ID_URI_PARAMETER);
        encoded.append(getId());
        String bekey = getBeKey();
        if (bekey != null) {
            encoded.append(Constants.BEKEY_URI_PARAMETER);
            encoded.append(bekey);
        }

        if (anchor != null) {
            encoded.append(anchor);
        }

        if (query != null) {
            encoded.append("?");
            encoded.append(query);
        }

        URL encodedUrl = null;

        try {
            encodedUrl = new URL(encoded.toString());
        } catch (MalformedURLException e) {
            // XXX FIXME log warning
        }

        return encodedUrl;
    }

    public long getExpirationTime() {
        validateSessionState();
           
        return getPFieldExpirationTime();
    }

    /**
     * Gets the SipSessionManager of this SipApplicationSession.
     *
     * @return The SipSessionManager of this SipApplicationSession
     */
    public abstract SipSessionManager getSipSessionManager();

    /**
     * get this session locked for foreground if the session is found to be
     * presently background locked; retry logic in a time-decay polling loop
     * waits for background lock to clear after 6 attempts (12.6 seconds) it
     * unlocks the session and acquires the foreground lock
     */
    public boolean lockForegroundWithRetry() {
        boolean result = false;

        long pollTime = 200L;
        int tryNumber = 0;
        int maxNumberOfRetries = 7;
        boolean keepTrying = true;

        // try to lock up to numTries (i.e. 7) times
        // poll and wait starting with 200 ms
        while (keepTrying) {
            boolean lockResult = lockForeground();
            if (lockResult) {
                keepTrying = false;
                result = true;
                break;
            }

            tryNumber++;

            if (tryNumber < maxNumberOfRetries) {
                pollTime = pollTime * 2L;
                try {
                    Thread.sleep(pollTime);
                } catch (InterruptedException e) {
                    ;
                }
            } else {
                // unlock the background so we can take over
                // FIXME: need to log warning for this situation
                unlockBackground();
            }
        }

        return result;
    }

    /**
     * return whether this session is currently foreground locked
     */
    public synchronized boolean isForegroundLocked() {
        return sessionLock.isForegroundLocked();
    }

    /**
     * lock the session for foreground returns true if successful; false if
     * unsuccessful
     */
    public synchronized boolean lockBackground() {
        return sessionLock.lockBackground();
    }

    /**
     * lock the session for background returns true if successful; false if
     * unsuccessful
     */
    public synchronized boolean lockForeground() {
        return sessionLock.lockForeground();
    }

    /**
     * unlock the session completely irregardless of whether it was foreground
     * or background locked
     */
    public synchronized void unlockForegroundCompletely() {
        sessionLock.unlockForegroundCompletely();
    }

    /**
     * unlock the session from foreground
     */
    public synchronized void unlockForeground() {
        sessionLock.unlockForeground();
    }

    /**
     * unlock the session from background
     */
    public synchronized void unlockBackground() {
        sessionLock.unlockBackground();
    }

    /**
     * return the Session lock
     */
    public SessionLock getSessionLock() {
        return sessionLock;
    }

    /**
     * Returns true if this SipApplicationSession is replicable, false
     * otherwise.
     *
     * @return true if this SipApplicationSession is replicable, false otherwise
     */
    public boolean isReplicable() {
        return EEPersistenceTypeResolver.REPLICATED_TYPE.equals(getSipSessionManager()
                                                                    .getPersistenceType());
    }

    /**
     * Gets the lock that locks this SAS.
     *
     * @return the lock that locks this SAS
     */
    public Object getSasObjectLock() {
        return sasObjectLock;
    }

    /**
     * Gets the lock used by applications to lock the SAS and all its children.
     *
     * @return the lock used by applications to lock the SAS and all its
     *         children
     */
    public Object getSasApplicationLock() {
        return sasApplicationLock;
    }


    /**
     * Checks if the application has used the SAS application lock and atomically reset the state of this flag.
     * @return true if the SAS application lock has been used
     */
    public boolean getAndResetApplicationLockUsed() {
        synchronized (sasObjectLock) {
            boolean retVal = applicationLockUsed;
            applicationLockUsed = false;

            return retVal;
        }
    }

    private void setApplicationLockUsed() {
        synchronized (sasObjectLock) {
            applicationLockUsed = true;
        }
    }

    /**
     * Sets the hash key which was used to route the initial request that caused this
     * SipApplicationSession to be created.
     * @param beKey the hash key
     * @deprecated This method has no effect anymore. When calling {@link #getBeKey()}, the bekey
     *             is always extracted from the ID {@link #getId()}.
     */
    @Deprecated
    public void setBeKey(String beKey) {
        // Has no effect anymore, after fix of Issue#1365. The bekey is always extracted
        // from SAS-ID
    }

    /**
     * Gets the hash key which was used to route the initial request that caused this
     * SipApplicationSession to be created.
     * @return the hash key which was used to route the initial request that caused this
     * SipApplicationSession to be created
     */
    public String getBeKey() {
        return SipApplicationSessionUtil.getSipApplicationKey(getId());
    }

    // ---- Persisted Fields (PField) ----

    /**
     * Gets the actual value of the creation date.
     *
     * @return the actual value of the creation date
     */
    protected abstract long getPFieldCreationDate();

    /**
     * Gets the actual value of the application name.
     *
     * @return the actual value of the application name.
     */
    protected abstract String getPFieldApplicationName();

    /**
     * Sets the actual value of the application name.
     *
     * @param applicationName the actual value of the application name.
     */
    protected abstract void setPFieldApplicationName(String applicationName);

    /**
     * Gets the value of the application attribute identified by the given key.
     *
     * @param key the key
     * @return the value of the application attribute identified by the given
     *         key
     */
    protected abstract Object getPFieldApplicationAttribute(String key);

    /**
     * Sets the value of the application attribute identified by the given key.
     *
     * @param key the key
     * @param value the value
     */
    protected abstract void setPFieldApplicationAttribute(String key,
        Object value);

    /**
     * Removes the application attribute identified by the given key.
     *
     * @param key the key
     */
    protected abstract void removePFieldApplicationAttribute(String key);

    /**
     * Gets the names of all application attributes.
     *
     * @return the names of all application attributes
     */
    protected abstract Iterator<String> getPFieldApplicationAttributeNames();

    /**
     * Adds a SIP protocol session.
     *
     * @param session the session
     */
    protected abstract void addSipProtocolSession(SipSessionBase session);

    /**
     * Removes a SIP protocol session.
     *
     * @param session the session to remove
     */
    protected abstract void removePFieldSipProtocolSession(
        SipSessionBase session);

    /**
     * Gets the SIP protocol sessions.
     *
     * @return the SIP protocol sessions
     */
    protected abstract Iterable<SipSessionBase> getPFieldSipSessions();

    /**
     * Gets all SIP protocol sessions that are currently active.
     *
     * @return the currently active SIP protocol sessions
     */
    protected abstract Iterable<SipSessionBase> getPFieldSipSessionsActiveOnly();

    /**
     * Gets the SIP protocol session for a given ID.
     *
     * @param id SipSession ID
     * @return null if the SipSession with given ID does not exist or any
     * internal error happens while retrieving; otherwise a SIP protocol session.
     */
    protected abstract SipSessionBase getPFieldSipSession(String id);

    /**
     * Removes a HTTP protocol session.
     *
     * @param session the session to remove
     */
    protected abstract void removePFieldHttpProtocolSession(HttpSession session);

    /**
     * Removes a HTTP protocol session.
     *
     * @param session the session to remove
     * @param removeFromManager true if the session also needs to be removed from
     * its manager, false otherwise
     */
    protected abstract void removePFieldHttpProtocolSession(
            HttpSession session, boolean removeFromManager);

    /**
     * Adds a HTTP protocol session.
     *
     * @param session the session
     */
    protected abstract void addPFieldHttpProtocolSession(HttpSession session);

    /**
     * Gets the HTTP protocol sessions.
     *
     * @return the HTTP protocol sessions
     */
    protected abstract Iterable<HttpSession> getPFieldHttpSessions();

    /**
     * Gets all HTTP protocol sessions that are currently active.
     *
     * @return the currently active HTTP protocol sessions
     */
    protected abstract Iterable<HttpSession> getPFieldHttpSessionsActiveOnly();
   
    /**
     * Gets the HTTP protocol session for a given ID.
     *
     * @param id HttpSession ID
     * @return null if the HttpSession with given ID does not exist or any
     * internal error happens while retrieving; otherwise a HTTP protocol session.
     */
    protected abstract HttpSession getPFieldHttpSession(String id);

    /**
     * Gets the application timers
     *
     * @return the application timers
     */
    protected abstract Collection<ServletTimer> getPFieldApplicationTimers();

    /**
     * Gets the application timer with the given id.
     */
    protected abstract ServletTimer getPFieldApplicationTimer(String id);
    /**
     * Adds an application timer.
     *
     * @param timer the timer
     */
    protected abstract void addPFieldApplicationTimer(ServletTimerImpl timer);

    /**
     * Removes an application timer
     *
     * @param timer the timer
     */
    protected abstract void removePFieldApplicationTimer(ServletTimerImpl timer);

    /**
     * Gets the SAS lifetime timer timeout value.
     *
     * @return the SAS lifetime timer expiration time
     */
    protected abstract long getPFieldExpirationTime();

    /**
     * Sets the SAS lifetime timer timeout value.
     *
     * @param expirationTime the SAS lifetime timer expiration time
     */
    protected abstract void setPFieldExpirationTime(long expirationTime);

    protected abstract boolean isEmpty();


    /**
     * @serialData See serialized form version 1 in
     * #readExternal(ObjectInput in)
     * 
     * @param out the stream to write the object members
     *
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeShort(serializedFormVersion);
        out.writeBoolean(invalidateWhenReady);
        out.writeBoolean(readyToInvalidate);
    }


    /**
     * @serialData first field is an short and represents the
     * serializedFormVersion.<br><br>
     * <h3>Data layout for serializedFormVersion = 1 follows</h3>
     *
     * <li>field is a <b>boolean</b> and represents invalidateWhenReady
     * field</li>
     * <li>field is a <b>boolean</b> and represents readyToInvalidate
     * field</li>
     *
     * @param in the stream to read the object members
     *
     * @throws IOException is thrown when unsupported version is detected
     * @throws ClassNotFoundException
     */
    public void readExternal(ObjectInput in)
        throws IOException, ClassNotFoundException {
        // Only the fully created SAS will only be serialized always,
        // So it is safe to make isInitialized=true upon deserialization.
        isInitialized = true;
        short readSerializedFormVersion = in.readShort();
        switch(readSerializedFormVersion) {
        case 1:
            invalidateWhenReady = in.readBoolean();
            readyToInvalidate = in.readBoolean();
            break;
        default:
            throw new IOException("Unable to deserialize into "
                    + this.getClass().getName()
                    + " with serialVersionUID = " + serialVersionUID
                    + " due to unknown serializedFormVersion of "
                    + readSerializedFormVersion);
        }       
    }

}
TOP

Related Classes of com.ericsson.ssa.sip.SipApplicationSessionBase

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.