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

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