Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » catalina » cluster » session » [javadoc | source]
    1   /*
    2    * Copyright 1999,2004 The Apache Software Foundation.
    3    * 
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    * 
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    * 
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package org.apache.catalina.cluster.session;
   18   
   19   import java.beans.PropertyChangeSupport;
   20   import java.io.IOException;
   21   import java.io.NotSerializableException;
   22   import java.io.ObjectInputStream;
   23   import java.io.ObjectOutputStream;
   24   import java.io.Serializable;
   25   import java.lang.reflect.Method;
   26   import java.security.AccessController;
   27   import java.security.Principal;
   28   import java.security.PrivilegedAction;
   29   import java.util.ArrayList;
   30   import java.util.Enumeration;
   31   import java.util.HashMap;
   32   import java.util.Hashtable;
   33   import java.util.Iterator;
   34   import java.util.Map;
   35   
   36   import javax.servlet.ServletContext;
   37   import javax.servlet.http.HttpSession;
   38   import javax.servlet.http.HttpSessionAttributeListener;
   39   import javax.servlet.http.HttpSessionBindingEvent;
   40   import javax.servlet.http.HttpSessionBindingListener;
   41   import javax.servlet.http.HttpSessionContext;
   42   import javax.servlet.http.HttpSessionEvent;
   43   import javax.servlet.http.HttpSessionListener;
   44   
   45   import org.apache.catalina.Context;
   46   import org.apache.catalina.Manager;
   47   import org.apache.catalina.Session;
   48   import org.apache.catalina.SessionEvent;
   49   import org.apache.catalina.SessionListener;
   50   import org.apache.catalina.cluster.ClusterSession;
   51   import org.apache.catalina.realm.GenericPrincipal;
   52   import org.apache.catalina.util.Enumerator;
   53   import org.apache.catalina.util.StringManager;
   54   
   55   /**
   56    * 
   57    * Similar to the StandardSession, this code is identical, but for update and
   58    * some small issues, simply copied in the first release. This session will keep
   59    * track of deltas during a request.
   60    * <p>
   61    * <b>IMPLEMENTATION NOTE </b>: An instance of this class represents both the
   62    * internal (Session) and application level (HttpSession) view of the session.
   63    * However, because the class itself is not declared public, Java logic outside
   64    * of the <code>org.apache.catalina.session</code> package cannot cast an
   65    * HttpSession view of this instance back to a Session view.
   66    * <p>
   67    * <b>IMPLEMENTATION NOTE </b>: If you add fields to this class, you must make
   68    * sure that you carry them over in the read/writeObject methods so that this
   69    * class is properly serialized.
   70    * 
   71    * @author Filip Hanik
   72    * @author Craig R. McClanahan
   73    * @author Sean Legassick
   74    * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens </a>
   75    * @version $Revision: 326850 $ $Date: 2005-10-20 03:34:58 -0400 (Thu, 20 Oct 2005) $
   76    */
   77   
   78   public class DeltaSession implements HttpSession, Session, Serializable,
   79           ClusterSession {
   80   
   81       public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
   82               .getLog(DeltaManager.class);
   83   
   84       /**
   85        * The string manager for this package.
   86        */
   87       protected static StringManager smp = StringManager
   88               .getManager(Constants.Package);
   89   
   90   
   91       // ----------------------------------------------------- Instance Variables
   92   
   93       /**
   94        * Type array.
   95        */
   96       protected static final String EMPTY_ARRAY[] = new String[0];
   97   
   98       /**
   99        * The dummy attribute value serialized when a NotSerializableException is
  100        * encountered in <code>writeObject()</code>.
  101        */
  102       private static final String NOT_SERIALIZED = "___NOT_SERIALIZABLE_EXCEPTION___";
  103   
  104       /**
  105        * The collection of user data attributes associated with this Session.
  106        */
  107       private Map attributes = new Hashtable();
  108   
  109       /**
  110        * The authentication type used to authenticate our cached Principal, if
  111        * any. NOTE: This value is not included in the serialized version of this
  112        * object.
  113        */
  114       private transient String authType = null;
  115   
  116       /**
  117        * The <code>java.lang.Method</code> for the
  118        * <code>fireContainerEvent()</code> method of the
  119        * <code>org.apache.catalina.core.StandardContext</code> method, if our
  120        * Context implementation is of this class. This value is computed
  121        * dynamically the first time it is needed, or after a session reload (since
  122        * it is declared transient).
  123        */
  124       private transient Method containerEventMethod = null;
  125   
  126       /**
  127        * The method signature for the <code>fireContainerEvent</code> method.
  128        */
  129       private static final Class containerEventTypes[] = { String.class,
  130               Object.class };
  131   
  132       /**
  133        * The time this session was created, in milliseconds since midnight,
  134        * January 1, 1970 GMT.
  135        */
  136       private long creationTime = 0L;
  137   
  138       /**
  139        * The debugging detail level for this component. NOTE: This value is not
  140        * included in the serialized version of this object.
  141        */
  142       private transient int debug = 0;
  143   
  144       /**
  145        * We are currently processing a session expiration, so bypass certain
  146        * IllegalStateException tests. NOTE: This value is not included in the
  147        * serialized version of this object.
  148        */
  149       private transient boolean expiring = false;
  150   
  151       /**
  152        * The facade associated with this session. NOTE: This value is not included
  153        * in the serialized version of this object.
  154        */
  155       private transient DeltaSessionFacade facade = null;
  156   
  157       /**
  158        * The session identifier of this Session.
  159        */
  160       private String id = null;
  161   
  162       /**
  163        * Descriptive information describing this Session implementation.
  164        */
  165       private static final String info = "DeltaSession/1.0";
  166   
  167       /**
  168        * The last accessed time for this Session.
  169        */
  170       private long lastAccessedTime = creationTime;
  171   
  172       /**
  173        * The session event listeners for this Session.
  174        */
  175       private transient ArrayList listeners = new ArrayList();
  176   
  177       /**
  178        * The Manager with which this Session is associated.
  179        */
  180       private transient Manager manager = null;
  181   
  182       /**
  183        * The maximum time interval, in seconds, between client requests before the
  184        * servlet container may invalidate this session. A negative time indicates
  185        * that the session should never time out.
  186        */
  187       private int maxInactiveInterval = -1;
  188   
  189       /**
  190        * Flag indicating whether this session is new or not.
  191        */
  192       private boolean isNew = false;
  193   
  194       /**
  195        * Flag indicating whether this session is valid or not.
  196        */
  197       protected boolean isValid = false;
  198   
  199       /**
  200        * Internal notes associated with this session by Catalina components and
  201        * event listeners. <b>IMPLEMENTATION NOTE: </b> This object is <em>not</em>
  202        * saved and restored across session serializations!
  203        */
  204       private transient Map notes = new Hashtable();
  205   
  206       /**
  207        * The authenticated Principal associated with this session, if any.
  208        * <b>IMPLEMENTATION NOTE: </b> This object is <i>not </i> saved and
  209        * restored across session serializations!
  210        */
  211       private transient Principal principal = null;
  212   
  213       /**
  214        * The string manager for this package.
  215        */
  216       private static StringManager sm = StringManager
  217               .getManager(Constants.Package);
  218   
  219       /**
  220        * The HTTP session context associated with this session.
  221        */
  222       private static HttpSessionContext sessionContext = null;
  223   
  224       /**
  225        * The property change support for this component. NOTE: This value is not
  226        * included in the serialized version of this object.
  227        */
  228       private transient PropertyChangeSupport support = new PropertyChangeSupport(
  229               this);
  230   
  231       /**
  232        * The current accessed time for this session.
  233        */
  234       private long thisAccessedTime = creationTime;
  235   
  236       /**
  237        * only the primary session will expire, or be able to expire due to
  238        * inactivity. This is set to false as soon as I receive this session over
  239        * the wire in a session message. That means that someone else has made a
  240        * request on another server.
  241        */
  242       private transient boolean isPrimarySession = true;
  243   
  244       /**
  245        * The delta request contains all the action info
  246        *  
  247        */
  248       private transient DeltaRequest deltaRequest = null;
  249   
  250       /**
  251        * Last time the session was replicatd, used for distributed expiring of
  252        * session
  253        */
  254       private transient long lastTimeReplicated = System.currentTimeMillis();
  255   
  256       /**
  257        * The access count for this session
  258        */
  259       protected transient int accessCount = 0;
  260   
  261       // ----------------------------------------------------------- Constructors
  262       
  263       /**
  264        * Construct a new Session associated with the specified Manager.
  265        * 
  266        * @param manager
  267        *            The manager with which this Session is associated
  268        */
  269       public DeltaSession(Manager manager) {
  270   
  271           super();
  272           this.manager = manager;
  273           this.resetDeltaRequest();
  274       }
  275   
  276       // ----------------------------------------------------- Session Properties
  277   
  278       /**
  279        * returns true if this session is the primary session, if that is the case,
  280        * the manager can expire it upon timeout.
  281        */
  282       public boolean isPrimarySession() {
  283           return isPrimarySession;
  284       }
  285   
  286       /**
  287        * Sets whether this is the primary session or not.
  288        * 
  289        * @param primarySession
  290        *            Flag value
  291        */
  292       public void setPrimarySession(boolean primarySession) {
  293           this.isPrimarySession = primarySession;
  294       }
  295   
  296       /**
  297        * Return the authentication type used to authenticate our cached Principal,
  298        * if any.
  299        */
  300       public String getAuthType() {
  301   
  302           return (this.authType);
  303   
  304       }
  305   
  306       /**
  307        * Set the authentication type used to authenticate our cached Principal, if
  308        * any.
  309        * 
  310        * @param authType
  311        *            The new cached authentication type
  312        */
  313       public void setAuthType(String authType) {
  314   
  315           String oldAuthType = this.authType;
  316           this.authType = authType;
  317           support.firePropertyChange("authType", oldAuthType, this.authType);
  318   
  319       }
  320   
  321       /**
  322        * Set the creation time for this session. This method is called by the
  323        * Manager when an existing Session instance is reused.
  324        * 
  325        * @param time
  326        *            The new creation time
  327        */
  328       public void setCreationTime(long time) {
  329   
  330           this.creationTime = time;
  331           this.lastAccessedTime = time;
  332           this.thisAccessedTime = time;
  333   
  334       }
  335   
  336       /**
  337        * Return the session identifier for this session.
  338        */
  339       public String getId() {
  340   
  341           if ( !isValid() ) {
  342               throw new IllegalStateException
  343               (sm.getString("standardSession.getId.ise"));
  344           }
  345   
  346           return (this.id);
  347   
  348       }
  349   
  350   
  351       /**
  352        * Return the session identifier for this session.
  353        */
  354       public String getIdInternal() {
  355   
  356           return (this.id);
  357   
  358       }
  359   
  360   
  361       /**
  362        * Set the session identifier for this session without notify listeners.
  363        * 
  364        * @param id
  365        *            The new session identifier
  366        */
  367       public void setIdInternal(String id) {
  368           if ((this.id != null) && (manager != null))
  369               manager.remove(this);
  370   
  371           this.id = id;
  372   
  373           if (manager != null)
  374               manager.add(this);
  375           if ( deltaRequest == null ) resetDeltaRequest();
  376           else deltaRequest.setSessionId(id);
  377       }
  378   
  379       /**
  380        * Set the session identifier for this session.
  381        * 
  382        * @param id
  383        *            The new session identifier
  384        */
  385       public void setId(String id) {
  386           setIdInternal(id);
  387           tellNew();
  388        }
  389   
  390       /**
  391        * Inform the listeners about the new session.
  392        *  
  393        */
  394       public void tellNew() {
  395   
  396           // Notify interested session event listeners
  397           fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
  398   
  399           // Notify interested application event listeners
  400           Context context = (Context) manager.getContainer();
  401           //fix for standalone manager without container
  402           if (context != null) {
  403               Object listeners[] = context.getApplicationLifecycleListeners();
  404               if (listeners != null) {
  405                   HttpSessionEvent event = new HttpSessionEvent(getSession());
  406                   for (int i = 0; i < listeners.length; i++) {
  407                       if (!(listeners[i] instanceof HttpSessionListener))
  408                           continue;
  409                       HttpSessionListener listener = (HttpSessionListener) listeners[i];
  410                       try {
  411                           fireContainerEvent(context, "beforeSessionCreated",
  412                                   listener);
  413                           listener.sessionCreated(event);
  414                           fireContainerEvent(context, "afterSessionCreated",
  415                                   listener);
  416                       } catch (Throwable t) {
  417                           try {
  418                               fireContainerEvent(context, "afterSessionCreated",
  419                                       listener);
  420                           } catch (Exception e) {
  421                               ;
  422                           }
  423                           // FIXME - should we do anything besides log these?
  424                           log.error(sm.getString("standardSession.sessionEvent"),
  425                                   t);
  426                       }
  427                   }
  428               }
  429           }//end if
  430           //end fix
  431   
  432       }
  433   
  434       /**
  435        * Return descriptive information about this Session implementation and the
  436        * corresponding version number, in the format
  437        * <code>&lt;description&gt;/&lt;version&gt;</code>.
  438        */
  439       public String getInfo() {
  440   
  441           return (info);
  442   
  443       }
  444   
  445       /**
  446        * Return the last time the client sent a request associated with this
  447        * session, as the number of milliseconds since midnight, January 1, 1970
  448        * GMT. Actions that your application takes, such as getting or setting a
  449        * value associated with the session, do not affect the access time.
  450        */
  451       public long getLastAccessedTime() {
  452           if (!isValid) {
  453               throw new IllegalStateException(sm
  454                       .getString("standardSession.getLastAccessedTime"));
  455   
  456           }
  457           return (this.lastAccessedTime);
  458   
  459       }
  460   
  461       /**
  462        * Return the Manager within which this Session is valid.
  463        */
  464       public Manager getManager() {
  465   
  466           return (this.manager);
  467   
  468       }
  469   
  470       /**
  471        * Set the Manager within which this Session is valid.
  472        * 
  473        * @param manager
  474        *            The new Manager
  475        */
  476       public void setManager(Manager manager) {
  477   
  478           this.manager = manager;
  479   
  480       }
  481   
  482       /**
  483        * Return the maximum time interval, in seconds, between client requests
  484        * before the servlet container will invalidate the session. A negative time
  485        * indicates that the session should never time out.
  486        */
  487       public int getMaxInactiveInterval() {
  488   
  489           return (this.maxInactiveInterval);
  490   
  491       }
  492   
  493       /**
  494        * Set the maximum time interval, in seconds, between client requests before
  495        * the servlet container will invalidate the session. A negative time
  496        * indicates that the session should never time out.
  497        * 
  498        * @param interval
  499        *            The new maximum interval
  500        */
  501       public void setMaxInactiveInterval(int interval) {
  502           setMaxInactiveInterval(interval, true);
  503       }
  504   
  505       public void setMaxInactiveInterval(int interval, boolean addDeltaRequest) {
  506   
  507           this.maxInactiveInterval = interval;
  508           if (isValid && interval == 0) {
  509               expire();
  510           } else {
  511               if (addDeltaRequest && (deltaRequest != null))
  512                   deltaRequest.setMaxInactiveInterval(interval);
  513           }
  514   
  515       }
  516   
  517       /**
  518        * Set the <code>isNew</code> flag for this session.
  519        * 
  520        * @param isNew
  521        *            The new value for the <code>isNew</code> flag
  522        */
  523       public void setNew(boolean isNew) {
  524           setNew(isNew, true);
  525       }
  526   
  527       public void setNew(boolean isNew, boolean addDeltaRequest) {
  528           this.isNew = isNew;
  529           if (addDeltaRequest && (deltaRequest != null))
  530               deltaRequest.setNew(isNew);
  531       }
  532   
  533       /**
  534        * Return the authenticated Principal that is associated with this Session.
  535        * This provides an <code>Authenticator</code> with a means to cache a
  536        * previously authenticated Principal, and avoid potentially expensive
  537        * <code>Realm.authenticate()</code> calls on every request. If there is
  538        * no current associated Principal, return <code>null</code>.
  539        */
  540       public Principal getPrincipal() {
  541   
  542           return (this.principal);
  543   
  544       }
  545   
  546       /**
  547        * Set the authenticated Principal that is associated with this Session.
  548        * This provides an <code>Authenticator</code> with a means to cache a
  549        * previously authenticated Principal, and avoid potentially expensive
  550        * <code>Realm.authenticate()</code> calls on every request.
  551        * 
  552        * @param principal
  553        *            The new Principal, or <code>null</code> if none
  554        */
  555       public void setPrincipal(Principal principal) {
  556           setPrincipal(principal, true);
  557       }
  558   
  559       public void setPrincipal(Principal principal, boolean addDeltaRequest) {
  560           Principal oldPrincipal = this.principal;
  561           this.principal = principal;
  562           support.firePropertyChange("principal", oldPrincipal, this.principal);
  563           if (addDeltaRequest && (deltaRequest != null))
  564               deltaRequest.setPrincipal(principal);
  565       }
  566   
  567       /**
  568        * Return the <code>HttpSession</code> for which this object is the
  569        * facade.
  570        */
  571       public HttpSession getSession() {
  572   
  573           if (facade == null) {
  574               if (System.getSecurityManager() != null) {
  575                   final DeltaSession fsession = this;
  576                   facade = (DeltaSessionFacade) AccessController
  577                           .doPrivileged(new PrivilegedAction() {
  578                               public Object run() {
  579                                   return new DeltaSessionFacade(fsession);
  580                               }
  581                           });
  582               } else {
  583                   facade = new DeltaSessionFacade(this);
  584               }
  585           }
  586           return (facade);
  587   
  588       }
  589   
  590       /**
  591        * Return the <code>isValid</code> flag for this session.
  592        */
  593       public boolean isValid() {
  594   
  595           if (this.expiring) {
  596               return true;
  597           }
  598   
  599           if (!this.isValid) {
  600               return false;
  601           }
  602   
  603           if (accessCount > 0) {
  604               return true;
  605           }
  606   
  607           if (maxInactiveInterval >= 0) {
  608               long timeNow = System.currentTimeMillis();
  609               int timeIdle = (int) ((timeNow - lastAccessedTime) / 1000L);
  610               if (isPrimarySession()) {
  611                   if(timeIdle >= maxInactiveInterval) {
  612                       expire(true);
  613                   }
  614               } else {
  615                   if (timeIdle >= (2 * maxInactiveInterval)) {
  616                   //if the session has been idle twice as long as allowed,
  617                   //the primary session has probably crashed, and no other
  618                   //requests are coming in. that is why we do this. otherwise
  619                   //we would have a memory leak
  620                       expire(true, false);
  621                   }
  622               }
  623           }
  624   
  625           return (this.isValid);
  626       }
  627   
  628       /**
  629        * Set the <code>isValid</code> flag for this session.
  630        * 
  631        * @param isValid
  632        *            The new value for the <code>isValid</code> flag
  633        */
  634       public void setValid(boolean isValid) {
  635   
  636           this.isValid = isValid;
  637       }
  638   
  639       // ------------------------------------------------- Session Public Methods
  640   
  641       /**
  642        * Update the accessed time information for this session. This method should
  643        * be called by the context when a request comes in for a particular
  644        * session, even if the application does not reference it.
  645        */
  646       public void access() {
  647   
  648           this.lastAccessedTime = this.thisAccessedTime;
  649           this.thisAccessedTime = System.currentTimeMillis();
  650   
  651           evaluateIfValid();
  652   
  653           accessCount++;
  654       }
  655   
  656       public void endAccess() {
  657           isNew = false;
  658           accessCount--;
  659       }
  660   
  661       /**
  662        * Add a session event listener to this component.
  663        */
  664       public void addSessionListener(SessionListener listener) {
  665   
  666           synchronized (listeners) {
  667               listeners.add(listener);
  668           }
  669   
  670       }
  671   
  672       /**
  673        * Perform the internal processing required to invalidate this session,
  674        * without triggering an exception if the session has already expired.
  675        */
  676       public void expire() {
  677   
  678           expire(true);
  679   
  680       }
  681   
  682       /**
  683        * Perform the internal processing required to invalidate this session,
  684        * without triggering an exception if the session has already expired.
  685        * 
  686        * @param notify
  687        *            Should we notify listeners about the demise of this session?
  688        */
  689       public void expire(boolean notify) {
  690           expire(notify, true);
  691       }
  692   
  693       public void expire(boolean notify, boolean notifyCluster) {
  694   
  695           // Mark this session as "being expired" if needed
  696           if (expiring)
  697               return;
  698           String expiredId = getIdInternal();
  699   
  700           synchronized (this) {
  701   
  702               if (manager == null)
  703                   return;
  704   
  705               expiring = true;
  706   
  707               // Notify interested application event listeners
  708               // FIXME - Assumes we call listeners in reverse order
  709               Context context = (Context) manager.getContainer();
  710               //fix for standalone manager without container
  711               if (context != null) {
  712                   Object listeners[] = context.getApplicationLifecycleListeners();
  713                   if (notify && (listeners != null)) {
  714                       HttpSessionEvent event = new HttpSessionEvent(getSession());
  715                       for (int i = 0; i < listeners.length; i++) {
  716                           int j = (listeners.length - 1) - i;
  717                           if (!(listeners[j] instanceof HttpSessionListener))
  718                               continue;
  719                           HttpSessionListener listener = (HttpSessionListener) listeners[j];
  720                           try {
  721                               fireContainerEvent(context,
  722                                       "beforeSessionDestroyed", listener);
  723                               listener.sessionDestroyed(event);
  724                               fireContainerEvent(context,
  725                                       "afterSessionDestroyed", listener);
  726                           } catch (Throwable t) {
  727                               try {
  728                                   fireContainerEvent(context,
  729                                           "afterSessionDestroyed", listener);
  730                               } catch (Exception e) {
  731                                   ;
  732                               }
  733                               // FIXME - should we do anything besides log these?
  734                               log.error(sm
  735                                       .getString("standardSession.sessionEvent"),
  736                                       t);
  737                           }
  738                       }
  739                   }
  740               }//end if
  741               //end fix
  742               accessCount = 0;
  743               setValid(false);
  744   
  745               // Remove this session from our manager's active sessions
  746               if (manager != null)
  747                   manager.remove(this);
  748   
  749               // Notify interested session event listeners
  750               if (notify) {
  751                   fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
  752               }
  753   
  754               // We have completed expire of this session
  755               expiring = false;
  756   
  757               // Unbind any objects associated with this session
  758               String keys[] = keys();
  759               for (int i = 0; i < keys.length; i++)
  760                   removeAttributeInternal(keys[i], notify, false);
  761   
  762               if (notifyCluster) {
  763                   if (log.isDebugEnabled())
  764                       log.debug(smp.getString("deltaSession.notifying",
  765                               ((DeltaManager) manager).getName(), new Boolean(
  766                                       isPrimarySession()), expiredId));
  767                   ((DeltaManager) manager).sessionExpired(expiredId);
  768               }
  769   
  770           }
  771   
  772       }
  773   
  774       /**
  775        * Return the object bound with the specified name to the internal notes for
  776        * this session, or <code>null</code> if no such binding exists.
  777        * 
  778        * @param name
  779        *            Name of the note to be returned
  780        */
  781       public Object getNote(String name) {
  782               return (notes.get(name));
  783       }
  784   
  785       /**
  786        * Return an Iterator containing the String names of all notes bindings that
  787        * exist for this session.
  788        */
  789       public Iterator getNoteNames() {
  790               return (notes.keySet().iterator());
  791       }
  792   
  793       /**
  794        * Release all object references, and initialize instance variables, in
  795        * preparation for reuse of this object.
  796        */
  797       public void recycle() {
  798   
  799           // Reset the instance variables associated with this Session
  800           attributes.clear();
  801           setAuthType(null);
  802           creationTime = 0L;
  803           expiring = false;
  804           id = null;
  805           lastAccessedTime = 0L;
  806           maxInactiveInterval = -1;
  807           accessCount = 0;
  808           notes.clear();
  809           setPrincipal(null);
  810           isNew = false;
  811           isValid = false;
  812           manager = null;
  813           deltaRequest.clear();
  814   
  815       }
  816   
  817       /**
  818        * Remove any object bound to the specified name in the internal notes for
  819        * this session.
  820        * 
  821        * @param name
  822        *            Name of the note to be removed
  823        */
  824       public void removeNote(String name) {
  825           notes.remove(name);
  826       }
  827   
  828       /**
  829        * Remove a session event listener from this component.
  830        */
  831       public void removeSessionListener(SessionListener listener) {
  832   
  833           synchronized (listeners) {
  834               listeners.remove(listener);
  835           }
  836   
  837       }
  838   
  839       /**
  840        * Bind an object to a specified name in the internal notes associated with
  841        * this session, replacing any existing binding for this name.
  842        * 
  843        * @param name
  844        *            Name to which the object should be bound
  845        * @param value
  846        *            Object to be bound to the specified name
  847        */
  848       public void setNote(String name, Object value) {
  849           notes.put(name, value);
  850       }
  851   
  852       /**
  853        * Return a string representation of this object.
  854        */
  855       public String toString() {
  856   
  857           StringBuffer sb = new StringBuffer();
  858           sb.append("DeltaSession[");
  859           sb.append(id);
  860           sb.append("]");
  861           return (sb.toString());
  862   
  863       }
  864   
  865       // ------------------------------------------------ Session Package Methods
  866   
  867       /**
  868        * Read a serialized version of the contents of this session object from the
  869        * specified object input stream, without requiring that the StandardSession
  870        * itself have been serialized.
  871        * 
  872        * @param stream
  873        *            The object input stream to read from
  874        * 
  875        * @exception ClassNotFoundException
  876        *                if an unknown class is specified
  877        * @exception IOException
  878        *                if an input/output error occurs
  879        */
  880       public void readObjectData(ObjectInputStream stream)
  881               throws ClassNotFoundException, IOException {
  882   
  883           readObject(stream);
  884   
  885       }
  886   
  887       /**
  888        * Write a serialized version of the contents of this session object to the
  889        * specified object output stream, without requiring that the
  890        * StandardSession itself have been serialized.
  891        * 
  892        * @param stream
  893        *            The object output stream to write to
  894        * 
  895        * @exception IOException
  896        *                if an input/output error occurs
  897        */
  898       public void writeObjectData(ObjectOutputStream stream) throws IOException {
  899   
  900           writeObject(stream);
  901   
  902       }
  903   
  904       public void resetDeltaRequest() {
  905           if (deltaRequest == null) {
  906               deltaRequest = new DeltaRequest(getIdInternal(), false);
  907           } else {
  908               deltaRequest.reset();
  909               deltaRequest.setSessionId(getIdInternal());
  910           }
  911       }
  912   
  913       public DeltaRequest getDeltaRequest() {
  914           if (deltaRequest == null)
  915               resetDeltaRequest();
  916           return deltaRequest;
  917       }
  918   
  919       // ------------------------------------------------- HttpSession Properties
  920   
  921       /**
  922        * Return the time when this session was created, in milliseconds since
  923        * midnight, January 1, 1970 GMT.
  924        * 
  925        * @exception IllegalStateException
  926        *                if this method is called on an invalidated session
  927        */
  928       public long getCreationTime() {
  929   
  930           if (!expiring && !isValid)
  931               throw new IllegalStateException(sm
  932                       .getString("standardSession.getCreationTime.ise"));
  933   
  934           return (this.creationTime);
  935   
  936       }
  937   
  938       /**
  939        * Return the ServletContext to which this session belongs.
  940        */
  941       public ServletContext getServletContext() {
  942   
  943           if (manager == null)
  944               return (null);
  945           Context context = (Context) manager.getContainer();
  946           if (context == null)
  947               return (null);
  948           else
  949               return (context.getServletContext());
  950   
  951       }
  952   
  953       /**
  954        * Return the session context with which this session is associated.
  955        * 
  956        * @deprecated As of Version 2.1, this method is deprecated and has no
  957        *             replacement. It will be removed in a future version of the
  958        *             Java Servlet API.
  959        */
  960       public HttpSessionContext getSessionContext() {
  961   
  962           if (sessionContext == null)
  963               sessionContext = new StandardSessionContext();
  964           return (sessionContext);
  965   
  966       }
  967   
  968       // ----------------------------------------------HttpSession Public Methods
  969   
  970       /**
  971        * Return the object bound with the specified name in this session, or
  972        * <code>null</code> if no object is bound with that name.
  973        * 
  974        * @param name
  975        *            Name of the attribute to be returned
  976        * 
  977        * @exception IllegalStateException
  978        *                if this method is called on an invalidated session
  979        */
  980       public Object getAttribute(String name) {
  981   
  982           if (!isValid())
  983               throw new IllegalStateException(sm
  984                       .getString("standardSession.getAttribute.ise"));
  985           return (attributes.get(name));
  986       }
  987   
  988       /**
  989        * Return an <code>Enumeration</code> of <code>String</code> objects
  990        * containing the names of the objects bound to this session.
  991        * 
  992        * @exception IllegalStateException
  993        *                if this method is called on an invalidated session
  994        */
  995       public Enumeration getAttributeNames() {
  996   
  997           if (!isValid())
  998               throw new IllegalStateException(sm
  999                       .getString("standardSession.getAttributeNames.ise"));
 1000           return (new Enumerator(attributes.keySet(), true));
 1001       }
 1002   
 1003       /**
 1004        * Return the object bound with the specified name in this session, or
 1005        * <code>null</code> if no object is bound with that name.
 1006        * 
 1007        * @param name
 1008        *            Name of the value to be returned
 1009        * 
 1010        * @exception IllegalStateException
 1011        *                if this method is called on an invalidated session
 1012        * 
 1013        * @deprecated As of Version 2.2, this method is replaced by
 1014        *             <code>getAttribute()</code>
 1015        */
 1016       public Object getValue(String name) {
 1017   
 1018           return (getAttribute(name));
 1019   
 1020       }
 1021   
 1022       /**
 1023        * Return the set of names of objects bound to this session. If there are no
 1024        * such objects, a zero-length array is returned.
 1025        * 
 1026        * @exception IllegalStateException
 1027        *                if this method is called on an invalidated session
 1028        * 
 1029        * @deprecated As of Version 2.2, this method is replaced by
 1030        *             <code>getAttributeNames()</code>
 1031        */
 1032       public String[] getValueNames() {
 1033   
 1034           if (!isValid())
 1035               throw new IllegalStateException(sm
 1036                       .getString("standardSession.getValueNames.ise"));
 1037   
 1038           return (keys());
 1039   
 1040       }
 1041   
 1042       /**
 1043        * Invalidates this session and unbinds any objects bound to it.
 1044        * 
 1045        * @exception IllegalStateException
 1046        *                if this method is called on an invalidated session
 1047        */
 1048       public void invalidate() {
 1049   
 1050           if (!isValid())
 1051               throw new IllegalStateException(sm
 1052                       .getString("standardSession.invalidate.ise"));
 1053   
 1054           // Cause this session to expire
 1055           expire();
 1056   
 1057       }
 1058   
 1059       /**
 1060        * Return <code>true</code> if the client does not yet know about the
 1061        * session, or if the client chooses not to join the session. For example,
 1062        * if the server used only cookie-based sessions, and the client has
 1063        * disabled the use of cookies, then a session would be new on each request.
 1064        * 
 1065        * @exception IllegalStateException
 1066        *                if this method is called on an invalidated session
 1067        */
 1068       public boolean isNew() {
 1069   
 1070           if (!isValid())
 1071               throw new IllegalStateException(sm
 1072                       .getString("standardSession.isNew.ise"));
 1073   
 1074           return (this.isNew);
 1075   
 1076       }
 1077   
 1078       /**
 1079        * Bind an object to this session, using the specified name. If an object of
 1080        * the same name is already bound to this session, the object is replaced.
 1081        * <p>
 1082        * After this method executes, and if the object implements
 1083        * <code>HttpSessionBindingListener</code>, the container calls
 1084        * <code>valueBound()</code> on the object.
 1085        * 
 1086        * @param name
 1087        *            Name to which the object is bound, cannot be null
 1088        * @param value
 1089        *            Object to be bound, cannot be null
 1090        * 
 1091        * @exception IllegalStateException
 1092        *                if this method is called on an invalidated session
 1093        * 
 1094        * @deprecated As of Version 2.2, this method is replaced by
 1095        *             <code>setAttribute()</code>
 1096        */
 1097       public void putValue(String name, Object value) {
 1098   
 1099           setAttribute(name, value);
 1100   
 1101       }
 1102   
 1103       /**
 1104        * Remove the object bound with the specified name from this session. If the
 1105        * session does not have an object bound with this name, this method does
 1106        * nothing.
 1107        * <p>
 1108        * After this method executes, and if the object implements
 1109        * <code>HttpSessionBindingListener</code>, the container calls
 1110        * <code>valueUnbound()</code> on the object.
 1111        * 
 1112        * @param name
 1113        *            Name of the object to remove from this session.
 1114        * 
 1115        * @exception IllegalStateException
 1116        *                if this method is called on an invalidated session
 1117        */
 1118       public void removeAttribute(String name) {
 1119   
 1120           removeAttribute(name, true);
 1121   
 1122       }
 1123   
 1124       /**
 1125        * Remove the object bound with the specified name from this session. If the
 1126        * session does not have an object bound with this name, this method does
 1127        * nothing.
 1128        * <p>
 1129        * After this method executes, and if the object implements
 1130        * <code>HttpSessionBindingListener</code>, the container calls
 1131        * <code>valueUnbound()</code> on the object.
 1132        * 
 1133        * @param name
 1134        *            Name of the object to remove from this session.
 1135        * @param notify
 1136        *            Should we notify interested listeners that this attribute is
 1137        *            being removed?
 1138        * 
 1139        * @exception IllegalStateException
 1140        *                if this method is called on an invalidated session
 1141        */
 1142       public void removeAttribute(String name, boolean notify) {
 1143           removeAttribute(name, notify, true);
 1144       }
 1145   
 1146       public void removeAttribute(String name, boolean notify,
 1147               boolean addDeltaRequest) {
 1148   
 1149           // Validate our current state
 1150           if (!isValid())
 1151               throw new IllegalStateException(sm
 1152                       .getString("standardSession.removeAttribute.ise"));
 1153           removeAttributeInternal(name, notify, addDeltaRequest);
 1154       }
 1155   
 1156       /**
 1157        * Remove the object bound with the specified name from this session. If the
 1158        * session does not have an object bound with this name, this method does
 1159        * nothing.
 1160        * <p>
 1161        * After this method executes, and if the object implements
 1162        * <code>HttpSessionBindingListener</code>, the container calls
 1163        * <code>valueUnbound()</code> on the object.
 1164        * 
 1165        * @param name
 1166        *            Name of the object to remove from this session.
 1167        * 
 1168        * @exception IllegalStateException
 1169        *                if this method is called on an invalidated session
 1170        * 
 1171        * @deprecated As of Version 2.2, this method is replaced by
 1172        *             <code>removeAttribute()</code>
 1173        */
 1174       public void removeValue(String name) {
 1175   
 1176           removeAttribute(name);
 1177   
 1178       }
 1179   
 1180       /**
 1181        * Bind an object to this session, using the specified name. If an object of
 1182        * the same name is already bound to this session, the object is replaced.
 1183        * <p>
 1184        * After this method executes, and if the object implements
 1185        * <code>HttpSessionBindingListener</code>, the container calls
 1186        * <code>valueBound()</code> on the object.
 1187        * 
 1188        * @param name
 1189        *            Name to which the object is bound, cannot be null
 1190        * @param value
 1191        *            Object to be bound, cannot be null
 1192        * 
 1193        * @exception IllegalArgumentException
 1194        *                if an attempt is made to add a non-serializable object in
 1195        *                an environment marked distributable.
 1196        * @exception IllegalStateException
 1197        *                if this method is called on an invalidated session
 1198        */
 1199       public void setAttribute(String name, Object value) {
 1200           setAttribute(name, value, true, true);
 1201       }
 1202   
 1203       public void setAttribute(String name, Object value, boolean notify,
 1204               boolean addDeltaRequest) {
 1205   
 1206           // Name cannot be null
 1207           if (name == null)
 1208               throw new IllegalArgumentException(sm
 1209                       .getString("standardSession.setAttribute.namenull"));
 1210   
 1211           // Null value is the same as removeAttribute()
 1212           if (value == null) {
 1213               removeAttribute(name);
 1214               return;
 1215           }
 1216   
 1217           // Validate our current state
 1218           if (!isValid())
 1219               throw new IllegalStateException(sm
 1220                       .getString("standardSession.setAttribute.ise"));
 1221           if (!(value instanceof java.io.Serializable)) {
 1222               throw new IllegalArgumentException("Attribute [" + name
 1223                       + "] is not serializable");
 1224           }
 1225   
 1226           if (addDeltaRequest && (deltaRequest != null))
 1227               deltaRequest.setAttribute(name, value);
 1228   
 1229   
 1230           // Construct an event with the new value
 1231           HttpSessionBindingEvent event = null;
 1232   
 1233           // Call the valueBound() method if necessary
 1234           if (value instanceof HttpSessionBindingListener && notify) {
 1235               // Don't call any notification if replacing with the same value
 1236               Object oldValue = attributes.get(name);
 1237               if (value != oldValue) {
 1238                   event = new HttpSessionBindingEvent(getSession(), name, value);
 1239                   try {
 1240                       ((HttpSessionBindingListener) value).valueBound(event);
 1241                   } catch (Exception x) {
 1242                       log.error(smp.getString("deltaSession.valueBound.ex"), x);
 1243                   }
 1244               }
 1245           }
 1246   
 1247           // Replace or add this attribute
 1248           Object unbound = attributes.put(name, value);
 1249           // Call the valueUnbound() method if necessary
 1250           if ((unbound != null) && (unbound != value) && notify
 1251                   && (unbound instanceof HttpSessionBindingListener)) {
 1252               try {
 1253                   ((HttpSessionBindingListener) unbound)
 1254                           .valueUnbound(new HttpSessionBindingEvent(
 1255                                   (HttpSession) getSession(), name));
 1256               } catch (Exception x) {
 1257                   log.error(smp.getString("deltaSession.valueBinding.ex"), x);
 1258               }
 1259   
 1260           }
 1261   
 1262           //dont notify any listeners
 1263           if (!notify)
 1264               return;
 1265   
 1266           // Notify interested application event listeners
 1267           Context context = (Context) manager.getContainer();
 1268           //fix for standalone manager without container
 1269           if (context != null) {
 1270               Object listeners[] = context.getApplicationEventListeners();
 1271               if (listeners == null)
 1272                   return;
 1273               for (int i = 0; i < listeners.length; i++) {
 1274                   if (!(listeners[i] instanceof HttpSessionAttributeListener))
 1275                       continue;
 1276                   HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i];
 1277                   try {
 1278                       if (unbound != null) {
 1279                           fireContainerEvent(context,
 1280                                   "beforeSessionAttributeReplaced", listener);
 1281                           if (event == null) {
 1282                               event = new HttpSessionBindingEvent(getSession(),
 1283                                       name, unbound);
 1284                           }
 1285                           listener.attributeReplaced(event);
 1286                           fireContainerEvent(context,
 1287                                   "afterSessionAttributeReplaced", listener);
 1288                       } else {
 1289                           fireContainerEvent(context,
 1290                                   "beforeSessionAttributeAdded", listener);
 1291                           if (event == null) {
 1292                               event = new HttpSessionBindingEvent(getSession(),
 1293                                       name, value);
 1294                           }
 1295                           listener.attributeAdded(event);
 1296                           fireContainerEvent(context,
 1297                                   "afterSessionAttributeAdded", listener);
 1298                       }
 1299                   } catch (Throwable t) {
 1300                       try {
 1301                           if (unbound != null) {
 1302                               fireContainerEvent(context,
 1303                                       "afterSessionAttributeReplaced", listener);
 1304                           } else {
 1305                               fireContainerEvent(context,
 1306                                       "afterSessionAttributeAdded", listener);
 1307                           }
 1308                       } catch (Exception e) {
 1309                           ;
 1310                       }
 1311                       // FIXME - should we do anything besides log these?
 1312                       log
 1313                               .error(
 1314                                       sm
 1315                                               .getString("standardSession.attributeEvent"),
 1316                                       t);
 1317                   }
 1318               } //for
 1319           }//end if
 1320           //end fix
 1321   
 1322       }
 1323   
 1324       // -------------------------------------------- HttpSession Private Methods
 1325   
 1326       /**
 1327        * Read a serialized version of this session object from the specified
 1328        * object input stream.
 1329        * <p>
 1330        * <b>IMPLEMENTATION NOTE </b>: The reference to the owning Manager is not
 1331        * restored by this method, and must be set explicitly.
 1332        * 
 1333        * @param stream
 1334        *            The input stream to read from
 1335        * 
 1336        * @exception ClassNotFoundException
 1337        *                if an unknown class is specified
 1338        * @exception IOException
 1339        *                if an input/output error occurs
 1340        */
 1341       private void readObject(ObjectInputStream stream)
 1342               throws ClassNotFoundException, IOException {
 1343   
 1344           // Deserialize the scalar instance variables (except Manager)
 1345           authType = null; // Transient only
 1346           creationTime = ((Long) stream.readObject()).longValue();
 1347           lastAccessedTime = ((Long) stream.readObject()).longValue();
 1348           maxInactiveInterval = ((Integer) stream.readObject()).intValue();
 1349           isNew = ((Boolean) stream.readObject()).booleanValue();
 1350           isValid = ((Boolean) stream.readObject()).booleanValue();
 1351           thisAccessedTime = ((Long) stream.readObject()).longValue();
 1352           boolean hasPrincipal = stream.readBoolean();
 1353           principal = null;
 1354           if (hasPrincipal) {
 1355               principal = SerializablePrincipal.readPrincipal(stream,
 1356                       getManager().getContainer().getRealm());
 1357           }
 1358   
 1359           //        setId((String) stream.readObject());
 1360           id = (String) stream.readObject();
 1361           if (log.isDebugEnabled())
 1362               log.debug(smp.getString("deltaSession.readSession",  id));
 1363   
 1364           // Deserialize the attribute count and attribute values
 1365           if (attributes == null)
 1366               attributes = new Hashtable();
 1367           int n = ((Integer) stream.readObject()).intValue();
 1368           boolean isValidSave = isValid;
 1369           isValid = true;
 1370           for (int i = 0; i < n; i++) {
 1371               String name = (String) stream.readObject();
 1372               Object value = (Object) stream.readObject();
 1373               if ((value instanceof String) && (value.equals(NOT_SERIALIZED)))
 1374                   continue;
 1375               attributes.put(name, value);
 1376           }
 1377           isValid = isValidSave;
 1378           
 1379           if (listeners == null) {
 1380               listeners = new ArrayList();
 1381           }
 1382           
 1383           if (notes == null) {
 1384               notes = new Hashtable();
 1385           }
 1386       }
 1387   
 1388       /**
 1389        * Write a serialized version of this session object to the specified object
 1390        * output stream.
 1391        * <p>
 1392        * <b>IMPLEMENTATION NOTE </b>: The owning Manager will not be stored in the
 1393        * serialized representation of this Session. After calling
 1394        * <code>readObject()</code>, you must set the associated Manager
 1395        * explicitly.
 1396        * <p>
 1397        * <b>IMPLEMENTATION NOTE </b>: Any attribute that is not Serializable will
 1398        * be unbound from the session, with appropriate actions if it implements
 1399        * HttpSessionBindingListener. If you do not want any such attributes, be
 1400        * sure the <code>distributable</code> property of the associated Manager
 1401        * is set to <code>true</code>.
 1402        * 
 1403        * @param stream
 1404        *            The output stream to write to
 1405        * 
 1406        * @exception IOException
 1407        *                if an input/output error occurs
 1408        */
 1409       private void writeObject(ObjectOutputStream stream) throws IOException {
 1410   
 1411           // Write the scalar instance variables (except Manager)
 1412           stream.writeObject(new Long(creationTime));
 1413           stream.writeObject(new Long(lastAccessedTime));
 1414           stream.writeObject(new Integer(maxInactiveInterval));
 1415           stream.writeObject(new Boolean(isNew));
 1416           stream.writeObject(new Boolean(isValid));
 1417           stream.writeObject(new Long(thisAccessedTime));
 1418           stream.writeBoolean(getPrincipal() != null);
 1419           if (getPrincipal() != null) {
 1420               SerializablePrincipal.writePrincipal((GenericPrincipal) principal,
 1421                       stream);
 1422           }
 1423   
 1424           stream.writeObject(id);
 1425           if (log.isDebugEnabled())
 1426               log.debug(smp.getString("deltaSession.writeSession",id));
 1427   
 1428           // Accumulate the names of serializable and non-serializable attributes
 1429           String keys[] = keys();
 1430           ArrayList saveNames = new ArrayList();
 1431           ArrayList saveValues = new ArrayList();
 1432           for (int i = 0; i < keys.length; i++) {
 1433               Object value = null;
 1434               value = attributes.get(keys[i]);
 1435               if (value == null)
 1436                   continue;
 1437               else if (value instanceof Serializable) {
 1438                   saveNames.add(keys[i]);
 1439                   saveValues.add(value);
 1440               }
 1441           }
 1442   
 1443           // Serialize the attribute count and the Serializable attributes
 1444           int n = saveNames.size();
 1445           stream.writeObject(new Integer(n));
 1446           for (int i = 0; i < n; i++) {
 1447               stream.writeObject((String) saveNames.get(i));
 1448               try {
 1449                   stream.writeObject(saveValues.get(i));
 1450                   //                if (log.isDebugEnabled())
 1451                   //                    log.debug(" storing attribute '" + saveNames.get(i) +
 1452                   //                        "' with value '" + saveValues.get(i) + "'");
 1453               } catch (NotSerializableException e) {
 1454                   log.error(sm.getString("standardSession.notSerializable",
 1455                           saveNames.get(i), id), e);
 1456                   stream.writeObject(NOT_SERIALIZED);
 1457                   log.error("  storing attribute '" + saveNames.get(i)
 1458                           + "' with value NOT_SERIALIZED");
 1459               }
 1460           }
 1461   
 1462       }
 1463   
 1464       private void evaluateIfValid() {
 1465           /*
 1466            * If this session has expired or is in the process of expiring or will
 1467            * never expire, return
 1468            */
 1469           if (!this.isValid || expiring || maxInactiveInterval < 0)
 1470               return;
 1471   
 1472           isValid();
 1473   
 1474       }
 1475   
 1476       // -------------------------------------------------------- Private Methods
 1477   
 1478       /**
 1479        * Fire container events if the Context implementation is the
 1480        * <code>org.apache.catalina.core.StandardContext</code>.
 1481        * 
 1482        * @param context
 1483        *            Context for which to fire events
 1484        * @param type
 1485        *            Event type
 1486        * @param data
 1487        *            Event data
 1488        * 
 1489        * @exception Exception
 1490        *                occurred during event firing
 1491        */
 1492       private void fireContainerEvent(Context context, String type, Object data)
 1493               throws Exception {
 1494   
 1495           if (!"org.apache.catalina.core.StandardContext".equals(context
 1496                   .getClass().getName())) {
 1497               return; // Container events are not supported
 1498           }
 1499           // NOTE: Race condition is harmless, so do not synchronize
 1500           if (containerEventMethod == null) {
 1501               containerEventMethod = context.getClass().getMethod(
 1502                       "fireContainerEvent", containerEventTypes);
 1503           }
 1504           Object containerEventParams[] = new Object[2];
 1505           containerEventParams[0] = type;
 1506           containerEventParams[1] = data;
 1507           containerEventMethod.invoke(context, containerEventParams);
 1508   
 1509       }
 1510   
 1511       /**
 1512        * Notify all session event listeners that a particular event has occurred
 1513        * for this Session. The default implementation performs this notification
 1514        * synchronously using the calling thread.
 1515        * 
 1516        * @param type
 1517        *            Event type
 1518        * @param data
 1519        *            Event data
 1520        */
 1521       public void fireSessionEvent(String type, Object data) {
 1522           if (listeners.size() < 1)
 1523               return;
 1524           SessionEvent event = new SessionEvent(this, type, data);
 1525           SessionListener list[] = new SessionListener[0];
 1526           synchronized (listeners) {
 1527               list = (SessionListener[]) listeners.toArray(list);
 1528           }
 1529   
 1530           for (int i = 0; i < list.length; i++) {
 1531               ((SessionListener) list[i]).sessionEvent(event);
 1532           }
 1533   
 1534       }
 1535   
 1536       /**
 1537        * Return the names of all currently defined session attributes as an array
 1538        * of Strings. If there are no defined attributes, a zero-length array is
 1539        * returned.
 1540        */
 1541       protected String[] keys() {
 1542           return ((String[]) attributes.keySet().toArray(EMPTY_ARRAY));
 1543       }
 1544   
 1545       /**
 1546        * Return the value of an attribute without a check for validity.
 1547        */
 1548       protected Object getAttributeInternal(String name) {
 1549           return (attributes.get(name));  
 1550       }
 1551   
 1552       protected void removeAttributeInternal(String name, boolean notify,
 1553               boolean addDeltaRequest) {
 1554   
 1555           // Remove this attribute from our collection
 1556           Object value = attributes.remove(name);
 1557           if (value == null)
 1558               return;
 1559   
 1560           if (addDeltaRequest && (deltaRequest != null))
 1561               deltaRequest.removeAttribute(name);
 1562   
 1563           // Do we need to do valueUnbound() and attributeRemoved() notification?
 1564           if (!notify) {
 1565               return;
 1566           }
 1567   
 1568           // Call the valueUnbound() method if necessary
 1569            HttpSessionBindingEvent event = null;
 1570            if (value instanceof HttpSessionBindingListener) {
 1571               event = new HttpSessionBindingEvent(
 1572                   (HttpSession) getSession(), name, value);
 1573               try {
 1574                   ((HttpSessionBindingListener) value).valueUnbound(event);
 1575               } catch (Exception x) {
 1576                   log.error(smp.getString("deltaSession.valueUnbound.ex"), x);
 1577               }
 1578           }
 1579           // Notify interested application event listeners
 1580           Context context = (Context) manager.getContainer();
 1581           //fix for standalone manager without container
 1582           if (context != null) {
 1583               Object listeners[] = context.getApplicationEventListeners();
 1584               if (listeners == null)
 1585                   return;
 1586               for (int i = 0; i < listeners.length; i++) {
 1587                   if (!(listeners[i] instanceof HttpSessionAttributeListener))
 1588                       continue;
 1589                   HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i];
 1590                   try {
 1591                       fireContainerEvent(context,
 1592                               "beforeSessionAttributeRemoved", listener);
 1593                       if (event == null) {
 1594                           event = new HttpSessionBindingEvent
 1595                               (getSession(), name, value);
 1596                       }
 1597                       listener.attributeRemoved(event);
 1598                       fireContainerEvent(context, "afterSessionAttributeRemoved",
 1599                               listener);
 1600                   } catch (Throwable t) {
 1601                       try {
 1602                           fireContainerEvent(context,
 1603                                   "afterSessionAttributeRemoved", listener);
 1604                       } catch (Exception e) {
 1605                           ;
 1606                       }
 1607                       // FIXME - should we do anything besides log these?
 1608                       log
 1609                               .error(
 1610                                       sm
 1611                                               .getString("standardSession.attributeEvent"),
 1612                                       t);
 1613                   }
 1614               } //for
 1615           }//end if
 1616           //end fix
 1617   
 1618       }
 1619   
 1620       protected long getLastTimeReplicated() {
 1621           return lastTimeReplicated;
 1622       }
 1623   
 1624       protected void setLastTimeReplicated(long lastTimeReplicated) {
 1625           this.lastTimeReplicated = lastTimeReplicated;
 1626       }
 1627   
 1628       protected void setAccessCount(int accessCount) {
 1629           this.accessCount = accessCount;
 1630       }
 1631   
 1632       protected int getAccessCount() {
 1633           return accessCount;
 1634       }
 1635   
 1636   }
 1637   
 1638   // -------------------------------------------------------------- Private Class
 1639   
 1640   /**
 1641    * This class is a dummy implementation of the <code>HttpSessionContext</code>
 1642    * interface, to conform to the requirement that such an object be returned when
 1643    * <code>HttpSession.getSessionContext()</code> is called.
 1644    * 
 1645    * @author Craig R. McClanahan
 1646    * 
 1647    * @deprecated As of Java Servlet API 2.1 with no replacement. The interface
 1648    *             will be removed in a future version of this API.
 1649    */
 1650   
 1651   final class StandardSessionContext implements HttpSessionContext {
 1652   
 1653       private HashMap dummy = new HashMap();
 1654   
 1655       /**
 1656        * Return the session identifiers of all sessions defined within this
 1657        * context.
 1658        * 
 1659        * @deprecated As of Java Servlet API 2.1 with no replacement. This method
 1660        *             must return an empty <code>Enumeration</code> and will be
 1661        *             removed in a future version of the API.
 1662        */
 1663       public Enumeration getIds() {
 1664   
 1665           return (new Enumerator(dummy));
 1666   
 1667       }
 1668   
 1669       /**
 1670        * Return the <code>HttpSession</code> associated with the specified
 1671        * session identifier.
 1672        * 
 1673        * @param id
 1674        *            Session identifier for which to look up a session
 1675        * 
 1676        * @deprecated As of Java Servlet API 2.1 with no replacement. This method
 1677        *             must return null and will be removed in a future version of
 1678        *             the API.
 1679        */
 1680       public HttpSession getSession(String id) {
 1681   
 1682           return (null);
 1683   
 1684       }
 1685   
 1686   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » catalina » cluster » session » [javadoc | source]