| SessionBasedClusteredSession.java |
/*
* JBoss, the OpenSource WebOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.web.tomcat.tc5.session;
import org.jboss.metadata.WebMetaData;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Implementation of a clustered session for the JBossCacheManager. The replication granularity
* level is session based; that is, we replicate per whole session object.
* We use JBossCache for our internal replicated data store.
* The internal structure is like in JBossCache:
* <pre>
* /JSESSION
* /web_app_path (path + session id is unique)
* /id Map(id, session)
* (VERSION_KEY, version) // Used for version tracking. version is an Integer.
* </pre>
* <p/>
* Note that the isolation level of the cache dictates the
* concurrency behavior.</p>
*
* @author Ben Wang
* @version $Revision: 1.3.2.5 $
*/
class SessionBasedClusteredSession
extends ClusteredSession implements Serializable
{
static final long serialVersionUID = 3200976125245487256L;
/**
* Descriptive information describing this Session implementation.
*/
protected static final String info = "SessionBasedClusteredSession/1.0";
private transient boolean isSessionModifiedSinceLastSave;
private transient JBossCacheService proxy_;
public SessionBasedClusteredSession(AbstractJBossManager manager)
{
super(manager);
initAfterLoad(manager);
}
/**
* Initialize fields marked as transient after loading this session
* from the distributed store
*
* @param manager the manager for this session
*/
public void initAfterLoad(AbstractJBossManager manager)
{
// Use proxy to determine if this is first time session retrieval.
if (this.proxy_ == null)
{
if (log.isDebugEnabled())
{
log.debug("initAfterLoad(): initialize the transient variables ...");
}
setManager(manager);
listeners = new ArrayList();
notes = new HashMap();
support = new PropertyChangeSupport(this);
expiring = false;
isSessionModifiedSinceLastSave = false;
// cache invalidate purpose
isOutdated = false;
proxy_ = ((JBossCacheManager) manager).getCacheService();
// still null???
if (proxy_ == null)
{
throw new RuntimeException("SessionBasedClusteredSession: Cache service is null.");
}
// Notify all attributes of type HttpSessionActivationListener (SRV 7.7.2)
this.activate();
}
}
// ----------------------------------------------------- Session Properties
/**
* Set the creation time for this session. This method is called by the
* Manager when an existing Session instance is reused.
*
* @param time The new creation time
*/
public void setCreationTime(long time)
{
super.setCreationTime(time);
sessionIsDirty();
}
/**
* Set the authenticated Principal that is associated with this Session.
* This provides an <code>Authenticator</code> with a means to cache a
* previously authenticated Principal, and avoid potentially expensive
* <code>Realm.authenticate()</code> calls on every request.
*
* @param principal The new Principal, or <code>null</code> if none
*/
public void setPrincipal(Principal principal)
{
Principal oldPrincipal = this.principal;
this.principal = principal;
support.firePropertyChange("principal", oldPrincipal, this.principal);
if ((oldPrincipal != null && !oldPrincipal.equals(principal)) ||
(oldPrincipal == null && principal != null))
sessionIsDirty();
}
// ------------------------------------------------- Session Public Methods
/**
* Return a string representation of this object.
*/
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append("SessionBasedClusteredSession[");
sb.append(id);
sb.append("]");
return (sb.toString());
}
/**
* Start to process my local attribute changes to the replication layer.
*/
public synchronized void processSessionRepl()
{
if (!isSessionDirty())
{
if (log.isDebugEnabled())
{
log.debug("processSessionRepl(): session is not dirty. No need to replicate.");
}
return;
}
// Replicate this first. Note this will be lightweight since many of the attributes are transient.
// And also without attributes
if (log.isDebugEnabled())
{
log.debug("processSessionRepl(): session is dirty. Will increment version from: " +
getVersion() + " and replicate.");
}
this.incrementVersion(); // cache invalidation versioning
proxy_.putSession(id, this);
isSessionModifiedSinceLastSave = false;
}
public void removeMyself()
{
proxy_.removeSession(id);
}
public void removeMyselfLocal()
{
proxy_.removeSessionLocal(id);
}
// ----------------------------------------------HttpSession Public Methods
/**
* Update the accessed time information for this session. This method
* should be called by the context when a request comes in for a particular
* session, even if the application does not reference it.
*/
public void access()
{
super.access();
// If we do not use the local cache the session is dirty
// after every access.
if (invalidationPolicy == WebMetaData.SESSION_INVALIDATE_ACCESS)
{
this.sessionIsDirty();
}
}
protected Object getJBossInternalAttribute(String name)
{
Object result = attributes.get(name);
if (result != null)
{
if (invalidationPolicy == WebMetaData.SESSION_INVALIDATE_SET_AND_GET)
{
sessionIsDirty();
}
else if (invalidationPolicy == WebMetaData.SESSION_INVALIDATE_SET_AND_NON_PRIMITIVE_GET)
{
if (!(result instanceof String ||
result instanceof Integer ||
result instanceof Long ||
result instanceof Byte ||
result instanceof Short ||
result instanceof Float ||
result instanceof Double ||
result instanceof Character ||
result instanceof Boolean)
)
{
sessionIsDirty();
}
}
}
return result;
}
protected Object removeJBossInternalAttribute(String name)
{
sessionIsDirty();
return attributes.remove(name);
}
protected Map getJBossInternalAttributes()
{
// TODO Add it to the doc
// No matter what, get all attributes is considered dirty.
sessionIsDirty();
return attributes;
}
protected Object setJBossInternalAttribute(String name, Object value)
{
sessionIsDirty();
return attributes.put(name, value);
}
protected void sessionIsDirty()
{
// Session is dirty
isSessionModifiedSinceLastSave = true;
}
public boolean isSessionDirty()
{
return isSessionModifiedSinceLastSave;
}
}
| SessionBasedClusteredSession.java |