KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > session > StandardSession


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 JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.NotSerializableException JavaDoc;
25 import java.io.ObjectInputStream JavaDoc;
26 import java.io.ObjectOutputStream JavaDoc;
27 import java.io.Serializable JavaDoc;
28 import java.lang.reflect.Method JavaDoc;
29 import java.security.AccessController JavaDoc;
30 import java.security.Principal JavaDoc;
31 import java.security.PrivilegedAction JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Enumeration JavaDoc;
34 import java.util.HashMap JavaDoc;
35 import java.util.Hashtable JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.concurrent.ConcurrentHashMap JavaDoc;
39 import java.util.concurrent.atomic.AtomicInteger JavaDoc;
40
41 import javax.servlet.ServletContext JavaDoc;
42 import javax.servlet.http.HttpSession JavaDoc;
43 import javax.servlet.http.HttpSessionActivationListener JavaDoc;
44 import javax.servlet.http.HttpSessionAttributeListener JavaDoc;
45 import javax.servlet.http.HttpSessionBindingEvent JavaDoc;
46 import javax.servlet.http.HttpSessionBindingListener JavaDoc;
47 import javax.servlet.http.HttpSessionContext JavaDoc;
48 import javax.servlet.http.HttpSessionEvent JavaDoc;
49 import javax.servlet.http.HttpSessionListener JavaDoc;
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: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
81  */

82
83 public class StandardSession
84     implements HttpSession JavaDoc, Session JavaDoc, Serializable JavaDoc {
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 JavaDoc();
108         }
109
110     }
111
112
113     // ----------------------------------------------------- Instance Variables
114

115
116     /**
117      * Type array.
118      */

119     protected static final String JavaDoc EMPTY_ARRAY[] = new String JavaDoc[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 JavaDoc NOT_SERIALIZED =
127         "___NOT_SERIALIZABLE_EXCEPTION___";
128
129
130     /**
131      * The collection of user data attributes associated with this Session.
132      */

133     protected Map JavaDoc attributes = new ConcurrentHashMap JavaDoc();
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 JavaDoc 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 JavaDoc containerEventMethod = null;
153
154
155     /**
156      * The method signature for the <code>fireContainerEvent</code> method.
157      */

158     protected static final Class JavaDoc containerEventTypes[] =
159     { String JavaDoc.class, Object JavaDoc.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 JavaDoc[] 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 JavaDoc id = null;
196
197
198     /**
199      * Descriptive information describing this Session implementation.
200      */

201     protected static final String JavaDoc 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 JavaDoc listeners = new ArrayList JavaDoc();
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 JavaDoc notes = new Hashtable JavaDoc();
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 JavaDoc 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 JavaDoc 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 JavaDoc support =
276         new PropertyChangeSupport JavaDoc(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 JavaDoc 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 JavaDoc 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 JavaDoc authType) {
312
313         String JavaDoc 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 JavaDoc getId() {
339
340         return (this.id);
341
342     }
343
344
345     /**
346      * Return the session identifier for this session.
347      */

348     public String JavaDoc 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 JavaDoc 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 JavaDoc context = (Context JavaDoc) manager.getContainer();
384         Object JavaDoc listeners[] = context.getApplicationLifecycleListeners();
385         if (listeners != null) {
386             HttpSessionEvent JavaDoc event =
387                 new HttpSessionEvent JavaDoc(getSession());
388             for (int i = 0; i < listeners.length; i++) {
389                 if (!(listeners[i] instanceof HttpSessionListener JavaDoc))
390                     continue;
391                 HttpSessionListener JavaDoc listener =
392                     (HttpSessionListener JavaDoc) 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 JavaDoc t) {
402                     try {
403                         fireContainerEvent(context,
404                                            "afterSessionCreated",
405                                            listener);
406                     } catch (Exception JavaDoc 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 JavaDoc 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 JavaDoc
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 JavaDoc 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 JavaDoc principal) {
540
541         Principal JavaDoc 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 JavaDoc getSession() {
553
554         if (facade == null){
555             if (SecurityUtil.isPackageProtectionEnabled()){
556                 final StandardSession fsession = this;
557                 facade = (StandardSessionFacade)AccessController.doPrivileged(new PrivilegedAction JavaDoc(){
558                     public Object JavaDoc 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 JavaDoc 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 JavaDoc context = (Context JavaDoc) manager.getContainer();
688             Object JavaDoc listeners[] = context.getApplicationLifecycleListeners();
689             if (notify && (listeners != null)) {
690                 HttpSessionEvent JavaDoc event =
691                     new HttpSessionEvent JavaDoc(getSession());
692                 for (int i = 0; i < listeners.length; i++) {
693                     int j = (listeners.length - 1) - i;
694                     if (!(listeners[j] instanceof HttpSessionListener JavaDoc))
695                         continue;
696                     HttpSessionListener JavaDoc listener =
697                         (HttpSessionListener JavaDoc) 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 JavaDoc t) {
707                         try {
708                             fireContainerEvent(context,
709                                                "afterSessionDestroyed",
710                                                listener);
711                         } catch (Exception JavaDoc 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 JavaDoc 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 JavaDoc event = null;
774         String JavaDoc keys[] = keys();
775         for (int i = 0; i < keys.length; i++) {
776             Object JavaDoc attribute = attributes.get(keys[i]);
777             if (attribute instanceof HttpSessionActivationListener JavaDoc) {
778                 if (event == null)
779                     event = new HttpSessionEvent JavaDoc(getSession());
780                 try {
781                     ((HttpSessionActivationListener JavaDoc)attribute)
782                         .sessionWillPassivate(event);
783                 } catch (Throwable JavaDoc 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 JavaDoc();
802         }
803         
804         // Notify interested session event listeners
805
fireSessionEvent(Session.SESSION_ACTIVATED_EVENT, null);
806
807         // Notify ActivationListeners
808
HttpSessionEvent JavaDoc event = null;
809         String JavaDoc keys[] = keys();
810         for (int i = 0; i < keys.length; i++) {
811             Object JavaDoc attribute = attributes.get(keys[i]);
812             if (attribute instanceof HttpSessionActivationListener JavaDoc) {
813                 if (event == null)
814                     event = new HttpSessionEvent JavaDoc(getSession());
815                 try {
816                     ((HttpSessionActivationListener JavaDoc)attribute)
817                         .sessionDidActivate(event);
818                 } catch (Throwable JavaDoc 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 JavaDoc getNote(String JavaDoc 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 JavaDoc 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         accessCount = null;
867         notes.clear();
868         setPrincipal(null);
869         isNew = false;
870         isValid = false;
871         manager = null;
872
873     }
874
875
876     /**
877      * Remove any object bound to the specified name in the internal notes
878      * for this session.
879      *
880      * @param name Name of the note to be removed
881      */

882     public void removeNote(String JavaDoc name) {
883
884         notes.remove(name);
885
886     }
887
888
889     /**
890      * Remove a session event listener from this component.
891      */

892     public void removeSessionListener(SessionListener JavaDoc listener) {
893
894         listeners.remove(listener);
895
896     }
897
898
899     /**
900      * Bind an object to a specified name in the internal notes associated
901      * with this session, replacing any existing binding for this name.
902      *
903      * @param name Name to which the object should be bound
904      * @param value Object to be bound to the specified name
905      */

906     public void setNote(String JavaDoc name, Object JavaDoc value) {
907
908         notes.put(name, value);
909
910     }
911
912
913     /**
914      * Return a string representation of this object.
915      */

916     public String JavaDoc toString() {
917
918         StringBuffer JavaDoc sb = new StringBuffer