Home » apache-tomcat-6.0.26-src » org.apache » catalina » session » [javadoc | source]

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

Home » apache-tomcat-6.0.26-src » org.apache » catalina » session » [javadoc | source]