/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (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/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Copyright (c) Ericsson AB, 2004-2007. All rights reserved.
 */
package com.ericsson.ssa.sip;

import com.ericsson.ssa.config.SipFactoryFacade;
import com.ericsson.ssa.container.sim.ApplicationDispatcher;
import com.ericsson.ssa.container.sim.ServletDispatcher;
import com.ericsson.ssa.dd.SipApplication;
import com.ericsson.ssa.dd.SipApplicationListeners;
import com.ericsson.ssa.sip.timer.ServletTimerImpl;
import com.ericsson.ssa.sip.timer.TimerServiceImpl;

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

import org.apache.catalina.Manager;
import org.apache.catalina.session.SessionLock;

import java.net.URL;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpSession;
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;
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,
    TimerListener {
    // --- Transient fields ---
    private static Logger logger = Logger.getLogger("SipContainer");
    private static ApplicationDispatcher m_ApplicationDispatcher = ApplicationDispatcher.getInstance();
    private static TimerServiceImpl m_timerService = TimerServiceImpl.getInstance();
    private boolean m_IsValid = true;
    private int m_defaultSessionTimeout; // Does not need to be Thread safe
    private SipApplicationListeners m_SipApplicationListeners = null;
    private int m_deltaSessionTimeout = 0;
    private String m_currentServlet = null;
    private SessionLock m_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 sasStructureLock = new Object();
    private volatile boolean invalidateInProgress;
    private volatile boolean shouldBePersisted;

    /**
     * Construct the object.
     * @param manager
     */
    public SipApplicationSessionBase(SipApplicationListeners listeners) {
        setApplicationListeners(listeners);

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

    /**
     * Constructor for serialization.
     */
    public SipApplicationSessionBase() {
    }

    protected void setApplicationListeners(SipApplicationListeners listeners) {
        m_SipApplicationListeners = listeners;
    }

    // ---- SSA Methods ----

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

        // FIXME not implemented
    }

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

            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()
     */
    public long getLastAccessedTime() {
        // FIXME not implemented
        return -1;
    }

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

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

            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) {
        synchronized (sasObjectLock) {
            validateSessionState();

            if (SipFactoryImpl.SIP_URI_PROTOCOL.equalsIgnoreCase(protocol)) {
                ArrayList<SipSession> ss = new ArrayList<SipSession>();

                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>();

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

                return sw.iterator();
            } else {
                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() {
        if (this.invalidateInProgress) {
            return;
        }

        synchronized (sasObjectLock) {
            // if called from SipServlet code
            invalidate(false);
        }
    }

    /**
     * @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) {
        synchronized (sasObjectLock) {
            validateSessionState();
            setPFieldApplicationAttribute(key, value);
        }
    }

    /**
     * @see javax.servlet.sip.SipApplicationSession#setExpires(int)
     */
    public int setExpires(int deltaMinutes) {
        if (deltaMinutes < 1) {
            throw new IllegalArgumentException();
        }

        synchronized (sasObjectLock) {
            validateSessionState();

            ServletTimerImpl sasTimer = getPFieldSasLifetimeTimer();

            if (sasTimer != null) {
                sasTimer.cancel();
            }

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

            m_deltaSessionTimeout = deltaMinutes;
            setPFieldSasLifetimeTimer(m_timerService.createTimer(
                    (TimerListener) this, (m_deltaSessionTimeout * 60 * 1000L),
                    false, null));

            return m_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() {
        // start applicationSessionTimer
        int configuredSessionTimeout = getDefaultSessionTimeout();

        if (configuredSessionTimeout >= 1) {
            // TODO currently assume this "internal" timer should not be
            // included
            // in m_applicatinonTimers
            setPFieldSasLifetimeTimer(m_timerService.createTimer(
                    (TimerListener) this,
                    (configuredSessionTimeout * 60 * 1000L), false, null));

            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE,
                    "Started timer defined in sip.xml : session-timeout:" +
                    configuredSessionTimeout);
            }
        } else {
            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);
        }
    }

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

        synchronized (sasObjectLock) {
            // "lifetime"
            boolean shouldContinue = false;

            // when the invalidateInProgress=true a call to invalidate() will
            // have
            // no effect.
            this.invalidateInProgress = true;
            // 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
            m_deltaSessionTimeout = 0; // reset delta, now let the listeners
                                       // extend

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

            while (iter.hasNext()) {
                SipApplicationSessionListener listener = iter.next();

                try {
                    listener.sessionExpired(new SipApplicationSessionEvent(this));
                } catch (RuntimeException e) {
                    logger.log(Level.WARNING,
                        "SipApplicationSessionListener.sessionExpired() generated an exception",
                        e);
                }

                if (m_deltaSessionTimeout >= 1) {
                    shouldContinue = true;

                    break;
                }
            }

            this.invalidateInProgress = false;

            if ((shouldContinue == false) && isValid()) {
                invalidate(true);
            }
        }
    }

    /**
     * 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 m_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) {
            validateSessionState();
            removePFieldSipProtocolSession(session);
        }
    }

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

    /**
     * @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 SipApplicationListeners getSipApplicationListeners() {
        synchronized (sasObjectLock) {
            validateSessionState();

            return m_SipApplicationListeners;
        }
    }

    /**
     * @param sipApplicationListeners The m_SipApplicationListeners to set.
     */
    public void setSipApplicationListeners(
        SipApplicationListeners sipApplicationListeners) {
        synchronized (sasObjectLock) {
            validateSessionState();
            m_SipApplicationListeners = sipApplicationListeners;
        }
    }

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

            return m_SipApplicationListeners.getTimerListener();
        }
    }

    /**
     * @return Returns the m_defaultSessionTimeout.
     */
    public int getDefaultSessionTimeout() {
        return m_defaultSessionTimeout;
    }

    /**
     * @param sessionTimeout The m_defaultSessionTimeout to set. Note! this
     *                method is not thread safe.
     */
    public void setDefaultSessionTimeout(int sessionTimeout) {
        if (sessionTimeout == SipApplication.UNKNOWN_TIMEOUT_VALUE) {
            m_defaultSessionTimeout = 60;

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

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

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

    public ServletDispatcher getServletDispatcher() {
        synchronized (sasObjectLock) {
            return m_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
     */
    private void invalidate(boolean hasTimedOut) {
        validateSessionState(
            "Should not call invalidate() when appsession is not valid");

        // first cancel the application timer cancel if any
        ServletTimerImpl sasTimer = getPFieldSasLifetimeTimer();

        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();

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

        // Invalidate session, important that the m_IsValid before invalidating
        // the SipSessions.
        m_IsValid = false;

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

            try {
                list.sessionDestroyed(new SipApplicationSessionEvent(this));
            } catch (RuntimeException e) {
                logger.log(Level.WARNING,
                    "SipApplicationSessionListener.sessionDestroyed() generated an exception",
                    e);
            }
        }

        for (SipSessionBase sess : getPFieldSipSessions()) {
            // Session may have been explicitly invalidated....
            if ((sess != null) && sess.isValid()) {
                sess.invalidate(hasTimedOut);
            }
        }

        // Clean the HttpSession
        for (HttpSession sess : getPFieldHttpSessions()) {
            // Session may have been explicitly invalidated....
            if (sess != null) {
                // Session may have been explicitly invalidated....
                sess.invalidate();
            }
        }

        // Remove this SipApplicationSession from its manager
        removeMeFromManager();

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

    protected abstract void removeMeFromManager();

    /**
     * Note! All calls to this MUST synchronize on SIP_APP_LOCK.
     */
    private void cancelAllServletTimers() {
        for (ServletTimer timer : getTimers()) {
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE, "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);
        }
    }

    /*
     * Note! All calls to this should synchronize on SIP_APP_LOCK. @param
     * message
     */
    private void validateSessionState(final String message) {
        if (!this.m_IsValid) {
            throw new IllegalStateException(message);
        }
    }

    private void validateSessionState() {
        validateSessionState("");
    }

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

        for (Iterator<?> i = getSessions(); i.hasNext();) {
            SipSession s = (SipSession) i.next();

            if (s.getId().equals(id)) {
                // match...
                return s;
            }
        }

        // no match...
        return null;
    }

    /* TO DO */
    public URL encodeURL(URL url) {
        throw new RuntimeException(" Not implemented yet ");
    }

    /* TO DO */
    public long getExpirationTime() {
        // throw new RuntimeException(" Not implemented yet ");
        return 1L; // XXX FIXME
    }

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

    /**
     * Sets the session manager for the HTTP protocol sessions of this
     * SipApplicationSession.
     *
     * @param manager The session manager for the HTTP protocol sessions of this
     *                SipApplicationSession
     */
    public abstract void setHttpSessionManager(Manager manager);

    /**
     * Gets the name of the instance.that currently owns this
     * SipApplicationSession.
     *
     * @return The name of the instance that currently owns this
     *         SipApplicationSession
     */
    public String getCurrentOwnerInstanceName() {
        return getSipSessionManager().getInstanceName();
    }

    /**
     * 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
     */
    protected boolean getSessionLockForForeground() {
        boolean result = false;

        // now lock the session
        long pollTime = 200L;
        int tryNumber = 0;
        int numTries = 7;
        boolean keepTrying = true;
        boolean lockResult = false;

        // try to lock up to numTries (i.e. 7) times
        // poll and wait starting with 200 ms
        while (keepTrying) {
            lockResult = lockForeground();

            if (lockResult) {
                keepTrying = false;
                result = true;

                break;
            }

            tryNumber++;

            if (tryNumber < (numTries - 1)) {
                pollTime = pollTime * 2L;
            } 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 m_SessionLock.isForegroundLocked();
    }

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

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

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

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

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

    /**
     * return the Session lock
     */
    public SessionLock getSessionLock() {
        return m_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 getSasStructureLock() {
        return sasStructureLock;
    }

    /**
     * Marks a session as confirmed.
     *
     * @param session the session
     */
    public abstract void setSessionConfirmed(SipSessionBase session);

    public boolean shouldBePersisted() {
        return shouldBePersisted;
    }

    public void setShouldBePersisted() {
        shouldBePersisted = true;
    }

    // ---- 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();

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

    /**
     * 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 the application timers
     *
     * @return the application timers
     */
    protected abstract Collection<ServletTimer> getPFieldApplicationTimers();

    /**
     * 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.
     *
     * @return the SAS lifetime timer
     */
    protected abstract ServletTimerImpl getPFieldSasLifetimeTimer();

    /**
     * Sets the SAS lifetime timer.
     *
     * @param timer the SAS lifetime timer
     */
    protected abstract void setPFieldSasLifetimeTimer(ServletTimerImpl timer);

    /**
     * Sets the ID.
     *
     * @param id
     */
    protected abstract void setPFieldId(String id);
}
