## org.mortbay.terracotta.servlet
Class TerracottaSessionManager

    java.lang.Object
      org.mortbay.component.AbstractLifeCycle
          org.mortbay.jetty.servlet.AbstractSessionManager
              org.mortbay.terracotta.servlet.TerracottaSessionManager

All Implemented Interfaces:
  java.lang.Runnable, LifeCycle, SessionManager

    public class TerracottaSessionManager

extends AbstractSessionManager
implements java.lang.Runnable

A specialized SessionManager to be used with Terracotta.

### IMPLEMENTATION NOTES

#### Requirements

This implementation of the session management requires J2SE 5 or superior.

#### Use of Hashtable

In Terracotta, collections classes are logically managed and we need two levels of locking: a local locking to handle concurrent requests on the same node and a distributed locking to handle concurrent requests on different nodes. Natively synchronized classes such as Hashtable fit better than synchronized wrappers obtained via, for example, `Collections.synchronizedMap(Map)`. This is because Terracotta may replay the method call on the inner unsynchronized collection without invoking the external wrapper, so the synchronization will be lost. Natively synchronized collections does not have this problem.

#### Use of Hashtable as a Set

There is no natively synchronized Set implementation, so we use Hashtable instead, see `TerracottaSessionIdManager`. However, we don't map the session id to itself, because Strings are treated specially by Terracotta, causing more traffic to the Terracotta server. Instead we use the same pattern used in the implementation of `java.util.HashSet`: use a single shared object to indicate the presence of a key. This is necessary since Hashtable does not allow null values.

#### Sessions expiration map

In order to scavenge expired sessions, we need a way to know if they are expired. This information is normally held in the session itself via the `lastAccessedTime` property. However, we would need to iterate over all sessions to check if each one is expired, and this migrates all sessions to the node, causing a lot of unneeded traffic between nodes and the Terracotta server. To avoid this, we keep a separate map from session id to expiration time, so we only need to migrate all the expirations times to see if a session is expired or not.

#### Update of lastAccessedTime

As a performance improvement, the lastAccessedTime is updated only periodically, and not every time a request enters a node. This optimization allows applications that have frequent requests but less frequent accesses to the session to perform better, because the traffic between the node and the Terracotta server is reduced. The update period is the scavenger period, see `Session#access(long)`.

#### Terracotta lock id

The Terracotta lock id is based on the session id, but this alone is not sufficient, as there may be two sessions with the same id for two different contexts. So we need session id and context path. However, this also is not enough, as we may have the rare case of the same webapp mapped to two different virtual hosts, and each virtual host must have a different session object. Therefore the lock id we need to use is a combination of session id, context path and virtual host, see `newLockId(String)`.

See Also:
  `TerracottaSessionIdManager`

Nested Class Summary
`protected static class` `TerracottaSessionManager.Lock`
`static class` `TerracottaSessionManager.SessionData` The session data that is distributed to cluster nodes via Terracotta.

Nested classes/interfaces inherited from class org.mortbay.jetty.servlet.AbstractSessionManager
`AbstractSessionManager.NullSessionContext, AbstractSessionManager.SessionIf`

Nested classes/interfaces inherited from interface org.mortbay.component.LifeCycle
`LifeCycle.Listener`

Field Summary

Fields inherited from class org.mortbay.jetty.servlet.AbstractSessionManager
`__distantFuture, _context, _dftMaxIdleSecs, _httpOnly, _loader, _maxCookieAge, _maxSessions, _minSessions, _nodeIdInSessionId, _refreshCookieAge, _secureCookies, _sessionAttributeListeners, _sessionCookie, _sessionDomain, _sessionHandler, _sessionIdManager, _sessionListeners, _sessionPath, _sessionURL, _sessionURLPrefix`

Fields inherited from class org.mortbay.component.AbstractLifeCycle
`_listeners`

Fields inherited from interface org.mortbay.jetty.SessionManager
`__DefaultSessionCookie, __DefaultSessionDomain, __DefaultSessionURL, __MaxAgeProperty, __SessionCookieProperty, __SessionDomainProperty, __SessionPathProperty, __SessionURLProperty`

Constructor Summary
`TerracottaSessionManager()`

Method Summary
`javax.servlet.http.Cookie` `access(javax.servlet.http.HttpSession session, boolean secure)` Called by the `SessionHandler` when a session is access by a request
`protected void` `addSession(AbstractSessionManager.Session session)`
`void` `complete(javax.servlet.http.HttpSession session)` Called by the `SessionHandler` when a reqeuest is not longer handling a session.
`void` `doStart()`
`void` `doStop()`
`void` `enter(Request request)`
`protected void` `enter(java.lang.String clusterId)`
`void` `exit(Request request)`
`protected void` `exit(java.lang.String clusterId)`
`long` `getScavengePeriodMs()`
`AbstractSessionManager.Session` `getSession(java.lang.String clusterId)` Get a known existingsession
`java.util.Map` `getSessionMap()`
`int` `getSessions()`
`protected void` `invalidateSessions()`
`protected java.lang.String` `newLockId(java.lang.String clusterId)`
`protected org.mortbay.terracotta.servlet.TerracottaSessionManager.Session` `newSession(javax.servlet.http.HttpServletRequest request)` Create a new session instance
`protected void` `removeSession(java.lang.String clusterId)`
`void` `run()`
`void` `setScavengePeriodMs(long ms)`
`protected boolean` `tryEnter(java.lang.String clusterId)`

Methods inherited from class org.mortbay.jetty.servlet.AbstractSessionManager

`addEventListener, addSession, clearEventListeners, getClusterId, getHttpOnly, getHttpSession, getIdManager, getMaxCookieAge, getMaxInactiveInterval, getMaxSessions, getMetaManager, getMinSessions, getNodeId, getRefreshCookieAge, getSecureCookies, getSessionCookie, getSessionCookie, getSessionDomain, getSessionHandler, getSessionPath, getSessionURL, getSessionURLPrefix, isNodeIdInSessionId, isUsingCookies, isValid, newHttpSession, removeEventListener, removeSession, removeSession, resetStats, setHttpOnly, setIdManager, setMaxCookieAge, setMaxInactiveInterval, setMetaManager, setNodeIdInSessionId, setRefreshCookieAge, setSecureCookies, setSessionCookie, setSessionDomain, setSessionHandler, setSessionPath, setSessionURL, setUsingCookies`

Methods inherited from class org.mortbay.component.AbstractLifeCycle
`addLifeCycleListener, isFailed, isRunning, isStarted, isStarting, isStopped, isStopping, removeLifeCycleListener, start, stop`

Methods inherited from class java.lang.Object
`clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

Methods inherited from interface org.mortbay.component.LifeCycle
`addLifeCycleListener, isFailed, isRunning, isStarted, isStarting, isStopped, isStopping, removeLifeCycleListener, start, stop`

Constructor Detail

### TerracottaSessionManager

    public TerracottaSessionManager()

Method Detail

### doStart

    public void doStart()
                 throws java.lang.Exception

  Overrides:
    `doStart` in class `AbstractSessionManager`
  Throws:
    `java.lang.Exception`

### doStop

    public void doStop()
                throws java.lang.Exception

  Overrides:
    `doStop` in class `AbstractSessionManager`
  Throws:
    `java.lang.Exception`

### run

    public void run()

  Specified by:
    `run` in interface `java.lang.Runnable`

### enter

    public void enter(Request request)

### enter

    protected void enter(java.lang.String clusterId)

### tryEnter

    protected boolean tryEnter(java.lang.String clusterId)

### exit

    public void exit(Request request)

### exit

    protected void exit(java.lang.String clusterId)

### addSession

    protected void addSession(AbstractSessionManager.Session session)

  Specified by:
    `addSession` in class `AbstractSessionManager`

### access

    public javax.servlet.http.Cookie access(javax.servlet.http.HttpSession session,
                                            boolean secure)

  Description copied from interface: `SessionManager`
  Called by the `SessionHandler` when a session is access by a request

  Specified by:
    `access` in interface `SessionManager`
  Overrides:
    `access` in class `AbstractSessionManager`
  Returns:
    Cookie If non null, this cookie should be set on the response to either migrate the session or to refresh a cookie that may expire.

### complete

    public void complete(javax.servlet.http.HttpSession session)

  Description copied from interface: `SessionManager`
  Called by the `SessionHandler` when a reqeuest is not longer handling a session. Not this includes new sessions, so there may not be a matching call to `#access(HttpSession)`.

  Specified by:
    `complete` in interface `SessionManager`
  Overrides:
    `complete` in class `AbstractSessionManager`

### removeSession

    protected void removeSession(java.lang.String clusterId)

  Specified by:
    `removeSession` in class `AbstractSessionManager`

### setScavengePeriodMs

    public void setScavengePeriodMs(long ms)

### getScavengePeriodMs

    public long getScavengePeriodMs()

### getSession

    public AbstractSessionManager.Session getSession(java.lang.String clusterId)

  Description copied from class: `AbstractSessionManager`
  Get a known existingsession

  Specified by:
    `getSession` in class `AbstractSessionManager`
  Parameters:
    `clusterId` - The session ID in the cluster, stripped of any worker name.
  Returns:
    A Session or null if none exists.

### newLockId

    protected java.lang.String newLockId(java.lang.String clusterId)

### getSessionMap

    public java.util.Map getSessionMap()

  Specified by:
    `getSessionMap` in class `AbstractSessionManager`

### getSessions

    public int getSessions()

  Specified by:
    `getSessions` in class `AbstractSessionManager`

### newSession

    protected org.mortbay.terracotta.servlet.TerracottaSessionManager.Session newSession(javax.servlet.http.HttpServletRequest request)

  Description copied from class: `AbstractSessionManager`
  Create a new session instance

  Specified by:
    `newSession` in class `AbstractSessionManager`
  Returns:

### invalidateSessions

    protected void invalidateSessions()

  Specified by:
    `invalidateSessions` in class `AbstractSessionManager`

Copyright © 1995-2010 Mort Bay Consulting. All Rights Reserved.