ClusteredSessionCMP.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.apache.catalina.Manager; import org.jboss.ha.httpsession.interfaces.SerializableHttpSession; import java.beans.PropertyChangeSupport; import java.io.IOException; import java.security.Principal; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionContext; import org.apache.catalina.util.Enumerator; import org.apache.catalina.util.StringManager; import org.apache.catalina.session.StandardSession; import org.jboss.metadata.WebMetaData; import org.jboss.logging.Logger; /** Implementation of a clustered session for the ClusteredHttpSession-Service * @see org.jboss.ha.httpsession.server.ClusteredHTTPSessionService * * It is based on the standard catalina class org.apache.catalina.session.StandardSession * (Revision: 1.25.2.1 Release: 4.0.3) * * <p><b>Revisions:</b> * * <p><b>23.11.2003 Sacha Labourey:</b> * <ul> * <li> Avoid unnecessary session replication (3 policies)</li> * </ul> @see org.jboss.ha.httpsession.server.ClusteredHTTPSessionService @author Thomas Peuss <jboss@peuss.de> @author Sacha Labourey <sacha.labourey@jboss.org> @version $Revision: 1.1.2.2 $ */ class ClusteredSessionCMP extends StandardSession implements SerializableHttpSession { private static final long serialVersionUID = -758573655613558722L; private static Logger log = Logger.getLogger(ClusteredSessionCMP.class); // ----------------------------------------------------- Instance Variables /** * Descriptive information describing this Session implementation. */ protected static final String info = "ClusteredSessionCMP/1.0"; /** * The Manager with which this Session is associated. */ private transient Manager manager = null; /** * The string manager for this package. */ private static StringManager sm = StringManager.getManager("org.jboss.web.tomcat.session"); protected transient boolean isSessionModifiedSinceLastSave = true; protected transient int replicationType = WebMetaData.REPLICATION_TYPE_SYNC; protected transient boolean replicationTypeAlreadySet = false; public ClusteredSessionCMP(JBossManagerCMP manager) { super(manager); this.manager = manager; } /** * Initialize fields marked as transient after loading this session * from the distributed store * @param manager the manager for this session */ protected void initAfterLoad(JBossManagerCMP manager) { setManager(manager); expiring = false; listeners = new ArrayList(); notes = new HashMap(); support = new PropertyChangeSupport(this); this.replicationType = manager.getReplicationType (); this.replicationTypeAlreadySet = false; // Notify all attributes of type HttpSessionActivationListener (SRV 7.7.2) this.activate(); } // SerializableHttpSession-methods -------------------------------------------- /** * Are attributes modified? * @param previousVersion The version to diff with */ public boolean areAttributesModified(SerializableHttpSession previousVersion) { // return true; if (this == previousVersion) { if (log.isDebugEnabled()) log.debug ("Are current session " + this.id + " attributes modified? : " + isSessionModifiedSinceLastSave); return isSessionModifiedSinceLastSave; } else { return true; } } /** * Get the creation time of this session */ public long getContentCreationTime() { return this.getCreationTime(); } /** * Get the last access time for this session */ public long getContentLastAccessTime() { return this.getLastAccessedTime(); } public void sessionHasBeenStored () { isSessionModifiedSinceLastSave = false; replicationTypeAlreadySet = false; } public int getReplicationTypeForSession () { return this.replicationType; } public void setReplicationTypeForSession (int type) { this.replicationType = type; } public boolean isReplicationTypeAlreadySet() { return replicationTypeAlreadySet; } // ----------------------------------------------------- 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(); } /** * Set the Manager within which this Session is valid. * * @param manager The new Manager */ public void setManager(Manager manager) { super.setManager(manager); this.manager=manager; } // ------------------------------------------------- Session Public Methods /** * Return a string representation of this object. */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append("ClusteredSessionCMP["); sb.append(id); sb.append("]"); return (sb.toString()); } // ------------------------------------------------ Session Package Methods // ----------------------------------------------HttpSession Public Methods public void access() { super.access(); // If we do not use the local cache the session is dirty // after every access. if (!((JBossManagerCMP)manager).isUseLocalCache()) { this.sessionIsDirty(); } } /** * Return the object bound with the specified name in this session, or * <code>null</code> if no object is bound with that name. * * @param name Name of the attribute to be returned * * @exception IllegalStateException if this method is called on an * invalidated session */ public Object getAttribute(String name) { if (!isValid) throw new IllegalStateException (sm.getString("clusteredSession.getAttribute.ise")); synchronized (attributes) { Object result = attributes.get(name); if (result != null) { int invalidationPolicy = ((AbstractJBossManager)manager).getInvalidateSessionPolicy(); 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; } } /** * Remove the object bound with the specified name from this session. If * the session does not have an object bound with this name, this method * does nothing. * <p> * After this method executes, and if the object implements * <code>HttpSessionBindingListener</code>, the container calls * <code>valueUnbound()</code> on the object. * * @param name Name of the object to remove from this session. * * @exception IllegalStateException if this method is called on an * invalidated session */ public void removeAttribute(String name, boolean notify) { // Remove this attribute from our collection boolean found = false; synchronized (attributes) { found = attributes.containsKey(name); if (found) { // Session is now dirty sessionIsDirty (); } else { return; } } super.removeAttribute(name, notify); } /** Override to copy the attributes key set to avoid ConcurrentModification * exceptions. * * Return an <code>Enumeration</code> of <code>String</code> objects * containing the names of the objects bound to this session. * * @exception IllegalStateException if this method is called on an * invalidated session */ public Enumeration getAttributeNames() { if (!isValid()) { throw new IllegalStateException (sm.getString("standardSession.getAttributeNames.ise")); } synchronized (attributes) { HashSet keys = new HashSet(attributes.keySet()); Enumeration iter = new Enumerator(keys); return iter; } } /** * Bind an object to this session, using the specified name. If an object * of the same name is already bound to this session, the object is * replaced. * <p> * After this method executes, and if the object implements * <code>HttpSessionBindingListener</code>, the container calls * <code>valueBound()</code> on the object. * * @param name Name to which the object is bound, cannot be null * @param value Object to be bound, cannot be null * * @exception IllegalArgumentException if an attempt is made to add a * non-serializable object in an environment marked distributable. * @exception IllegalStateException if this method is called on an * invalidated session */ public void setAttribute(String name, Object value) { super.setAttribute(name, value); // Session is dirty sessionIsDirty (); } /** * Log a message on the Logger associated with our Manager (if any). * * @param message Message to be logged */ protected void log(String message) { log.debug(message); } /** * Log a message on the Logger associated with our Manager (if any). * * @param message Message to be logged * @param throwable Associated exception */ protected void log(String message, Throwable throwable) { log.error(message, throwable); } protected void writeObject(java.io.ObjectOutputStream out) throws IOException { synchronized (attributes) { out.defaultWriteObject(); } } protected void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); } protected void sessionIsDirty () { // Session is dirty isSessionModifiedSinceLastSave = true; } } // -------------------------------------------------------------- Private Class /** * This class is a dummy implementation of the <code>HttpSessionContext</code> * interface, to conform to the requirement that such an object be returned * when <code>HttpSession.getSessionContext()</code> is called. * * @author Craig R. McClanahan * * @deprecated As of Java Servlet API 2.1 with no replacement. The * interface will be removed in a future version of this API. */ final class ClusteredSessionContext implements HttpSessionContext { private HashMap dummy = new HashMap(); /** * Return the session identifiers of all sessions defined * within this context. * * @deprecated As of Java Servlet API 2.1 with no replacement. * This method must return an empty <code>Enumeration</code> * and will be removed in a future version of the API. */ public Enumeration getIds() { return (new Enumerator(dummy)); } /** * Return the <code>HttpSession</code> associated with the * specified session identifier. * * @param id Session identifier for which to look up a session * * @deprecated As of Java Servlet API 2.1 with no replacement. * This method must return null and will be removed in a * future version of the API. */ public HttpSession getSession(String id) { return (null); } }
ClusteredSessionCMP.java |