KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > cluster > session > DeltaSession


1 /*
2  * Copyright 1999,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.catalina.cluster.session;
18
19 import java.beans.PropertyChangeSupport JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.NotSerializableException JavaDoc;
22 import java.io.ObjectInputStream JavaDoc;
23 import java.io.ObjectOutputStream JavaDoc;
24 import java.io.Serializable JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.security.AccessController JavaDoc;
27 import java.security.Principal JavaDoc;
28 import java.security.PrivilegedAction JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Enumeration JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.Iterator JavaDoc;
33
34 import javax.servlet.ServletContext JavaDoc;
35 import javax.servlet.http.HttpSession JavaDoc;
36 import javax.servlet.http.HttpSessionAttributeListener JavaDoc;
37 import javax.servlet.http.HttpSessionBindingEvent JavaDoc;
38 import javax.servlet.http.HttpSessionBindingListener JavaDoc;
39 import javax.servlet.http.HttpSessionContext JavaDoc;
40 import javax.servlet.http.HttpSessionEvent JavaDoc;
41 import javax.servlet.http.HttpSessionListener JavaDoc;
42
43 import org.apache.catalina.Context;
44 import org.apache.catalina.Manager;
45 import org.apache.catalina.Session;
46 import org.apache.catalina.SessionEvent;
47 import org.apache.catalina.SessionListener;
48 import org.apache.catalina.cluster.ClusterSession;
49 import org.apache.catalina.realm.GenericPrincipal;
50 import org.apache.catalina.util.Enumerator;
51 import org.apache.catalina.util.StringManager;
52
53 /**
54  *
55  * Similar to the StandardSession, this code is identical, but for update and
56  * some small issues, simply copied in the first release. This session will keep
57  * track of deltas during a request.
58  * <p>
59  * <b>IMPLEMENTATION NOTE </b>: An instance of this class represents both the
60  * internal (Session) and application level (HttpSession) view of the session.
61  * However, because the class itself is not declared public, Java logic outside
62  * of the <code>org.apache.catalina.session</code> package cannot cast an
63  * HttpSession view of this instance back to a Session view.
64  * <p>
65  * <b>IMPLEMENTATION NOTE </b>: If you add fields to this class, you must make
66  * sure that you carry them over in the read/writeObject methods so that this
67  * class is properly serialized.
68  *
69  * @author Filip Hanik
70  * @author Craig R. McClanahan
71  * @author Sean Legassick
72  * @author <a HREF="mailto:jon@latchkey.com">Jon S. Stevens </a>
73  * @version $Revision: 1.30 $ $Date: 2005/03/03 14:06:36 $
74  */

75
76 public class DeltaSession implements HttpSession JavaDoc, Session JavaDoc, Serializable JavaDoc,
77         ClusterSession {
78
79     public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
80             .getLog(DeltaManager.class);
81
82     /**
83      * The string manager for this package.
84      */

85     protected static StringManager smp = StringManager
86             .getManager(Constants.Package);
87
88     // ----------------------------------------------------------- Constructors
89

90     /**
91      * Construct a new Session associated with the specified Manager.
92      *
93      * @param manager
94      * The manager with which this Session is associated
95      */

96     public DeltaSession(Manager manager) {
97
98         super();
99         this.manager = manager;
100         this.resetDeltaRequest();
101     }
102
103     // ----------------------------------------------------- Instance Variables
104

105     /**
106      * The dummy attribute value serialized when a NotSerializableException is
107      * encountered in <code>writeObject()</code>.
108      */

109     private static final String JavaDoc NOT_SERIALIZED = "___NOT_SERIALIZABLE_EXCEPTION___";
110
111     /**
112      * The collection of user data attributes associated with this Session.
113      */

114     private HashMap JavaDoc attributes = new HashMap JavaDoc();
115
116     /**
117      * The authentication type used to authenticate our cached Principal, if
118      * any. NOTE: This value is not included in the serialized version of this
119      * object.
120      */

121     private transient String JavaDoc authType = null;
122
123     /**
124      * The <code>java.lang.Method</code> for the
125      * <code>fireContainerEvent()</code> method of the
126      * <code>org.apache.catalina.core.StandardContext</code> method, if our
127      * Context implementation is of this class. This value is computed
128      * dynamically the first time it is needed, or after a session reload (since
129      * it is declared transient).
130      */

131     private transient Method JavaDoc containerEventMethod = null;
132
133     /**
134      * The method signature for the <code>fireContainerEvent</code> method.
135      */

136     private static final Class JavaDoc containerEventTypes[] = { String JavaDoc.class,
137             Object JavaDoc.class };
138
139     /**
140      * The time this session was created, in milliseconds since midnight,
141      * January 1, 1970 GMT.
142      */

143     private long creationTime = 0L;
144
145     /**
146      * The debugging detail level for this component. NOTE: This value is not
147      * included in the serialized version of this object.
148      */

149     private transient int debug = 0;
150
151     /**
152      * We are currently processing a session expiration, so bypass certain
153      * IllegalStateException tests. NOTE: This value is not included in the
154      * serialized version of this object.
155      */

156     private transient boolean expiring = false;
157
158     /**
159      * The facade associated with this session. NOTE: This value is not included
160      * in the serialized version of this object.
161      */

162     private transient DeltaSessionFacade facade = null;
163
164     /**
165      * The session identifier of this Session.
166      */

167     private String JavaDoc id = null;
168
169     /**
170      * Descriptive information describing this Session implementation.
171      */

172     private static final String JavaDoc info = "DeltaSession/1.0";
173
174     /**
175      * The last accessed time for this Session.
176      */

177     private long lastAccessedTime = creationTime;
178
179     /**
180      * The session event listeners for this Session.
181      */

182     private transient ArrayList JavaDoc listeners = new ArrayList JavaDoc();
183
184     /**
185      * The Manager with which this Session is associated.
186      */

187     private transient Manager manager = null;
188
189     /**
190      * The maximum time interval, in seconds, between client requests before the
191      * servlet container may invalidate this session. A negative time indicates
192      * that the session should never time out.
193      */

194     private int maxInactiveInterval = -1;
195
196     /**
197      * Flag indicating whether this session is new or not.
198      */

199     private boolean isNew = false;
200
201     /**
202      * Flag indicating whether this session is valid or not.
203      */

204     private boolean isValid = false;
205
206     /**
207      * Internal notes associated with this session by Catalina components and
208      * event listeners. <b>IMPLEMENTATION NOTE: </b> This object is <em>not</em>
209      * saved and restored across session serializations!
210      */

211     private transient HashMap JavaDoc notes = new HashMap JavaDoc();
212
213     /**
214      * The authenticated Principal associated with this session, if any.
215      * <b>IMPLEMENTATION NOTE: </b> This object is <i>not </i> saved and
216      * restored across session serializations!
217      */

218     private transient Principal JavaDoc principal = null;
219
220     /**
221      * The string manager for this package.
222      */

223     private static StringManager sm = StringManager
224             .getManager(Constants.Package);
225
226     /**
227      * The HTTP session context associated with this session.
228      */

229     private static HttpSessionContext JavaDoc sessionContext = null;
230
231     /**
232      * The property change support for this component. NOTE: This value is not
233      * included in the serialized version of this object.
234      */

235     private transient PropertyChangeSupport JavaDoc support = new PropertyChangeSupport JavaDoc(
236             this);
237
238     /**
239      * The current accessed time for this session.
240      */

241     private long thisAccessedTime = creationTime;
242
243     /**
244      * only the primary session will expire, or be able to expire due to
245      * inactivity. This is set to false as soon as I receive this session over
246      * the wire in a session message. That means that someone else has made a
247      * request on another server.
248      */

249     private transient boolean isPrimarySession = true;
250
251     /**
252      * The delta request contains all the action info
253      *
254      */

255     private transient DeltaRequest deltaRequest = null;
256
257     /**
258      * Last time the session was replicatd, used for distributed expiring of
259      * session
260      */

261     private transient long lastTimeReplicated = System.currentTimeMillis();
262
263     /**
264      * The access count for this session
265      */

266     protected transient int accessCount = 0;
267
268     // ----------------------------------------------------- Session Properties
269

270     /**
271      * returns true if this session is the primary session, if that is the case,
272      * the manager can expire it upon timeout.
273      */

274     public boolean isPrimarySession() {
275         return isPrimarySession;
276     }
277
278     /**
279      * Sets whether this is the primary session or not.
280      *
281      * @param primarySession
282      * Flag value
283      */

284     public void setPrimarySession(boolean primarySession) {
285         this.isPrimarySession = primarySession;
286     }
287
288     /**
289      * Return the authentication type used to authenticate our cached Principal,
290      * if any.
291      */

292     public String JavaDoc getAuthType() {
293
294         return (this.authType);
295
296     }
297
298     /**
299      * Set the authentication type used to authenticate our cached Principal, if
300      * any.
301      *
302      * @param authType
303      * The new cached authentication type
304      */

305     public void setAuthType(String JavaDoc authType) {
306
307         String JavaDoc oldAuthType = this.authType;
308         this.authType = authType;
309         support.firePropertyChange("authType", oldAuthType, this.authType);
310
311     }
312
313     /**
314      * Set the creation time for this session. This method is called by the
315      * Manager when an existing Session instance is reused.
316      *
317      * @param time
318      * The new creation time
319      */

320     public void setCreationTime(long time) {
321
322         this.creationTime = time;
323         this.lastAccessedTime = time;
324         this.thisAccessedTime = time;
325
326     }
327
328     /**
329      * Return the session identifier for this session.
330      */

331     public String JavaDoc getId() {
332
333         return (this.id);
334
335     }
336
337     /**
338      * Set the session identifier for this session.
339      *
340      * @param id
341      * The new session identifier
342      */

343     public void setId(String JavaDoc id) {
344
345         if ((this.id != null) && (manager != null))
346             manager.remove(this);
347
348         this.id = id;
349
350         if (manager != null)
351             manager.add(this);
352         tellNew();
353         if ( deltaRequest == null ) resetDeltaRequest();
354         else deltaRequest.setSessionId(id);
355     }
356
357     /**
358      * Inform the listeners about the new session.
359      *
360      */

361     public void tellNew() {
362
363         // Notify interested session event listeners
364
fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
365
366         // Notify interested application event listeners
367
Context JavaDoc context = (Context JavaDoc) manager.getContainer();
368         //fix for standalone manager without container
369
if (context != null) {
370             Object JavaDoc listeners[] = context.getApplicationLifecycleListeners();
371             if (listeners != null) {
372                 HttpSessionEvent JavaDoc event = new HttpSessionEvent JavaDoc(getSession());
373                 for (int i = 0; i < listeners.length; i++) {
374                     if (!(listeners[i] instanceof HttpSessionListener JavaDoc))
375                         continue;
376                     HttpSessionListener JavaDoc listener = (HttpSessionListener JavaDoc) listeners[i];
377                     try {
378                         fireContainerEvent(context, "beforeSessionCreated",
379                                 listener);
380                         listener.sessionCreated(event);
381                         fireContainerEvent(context, "afterSessionCreated",
382                                 listener);
383                     } catch (Throwable JavaDoc t) {
384                         try {
385                             fireContainerEvent(context, "afterSessionCreated",
386                                     listener);
387                         } catch (Exception JavaDoc e) {
388                             ;
389                         }
390                         // FIXME - should we do anything besides log these?
391
log.error(sm.getString("standardSession.sessionEvent"),
392                                 t);
393                     }
394                 }
395             }
396         }//end if
397
//end fix
398

399     }
400
401     /**
402      * Return descriptive information about this Session implementation and the
403      * corresponding version number, in the format
404      * <code>&lt;description&gt;/&lt;version&gt;</code>.
405      */

406     public String JavaDoc getInfo() {
407
408         return (info);
409
410     }
411
412     /**
413      * Return the last time the client sent a request associated with this
414      * session, as the number of milliseconds since midnight, January 1, 1970
415      * GMT. Actions that your application takes, such as getting or setting a
416      * value associated with the session, do not affect the access time.
417      */

418     public long getLastAccessedTime() {
419         if (!isValid) {
420             throw new IllegalStateException JavaDoc(sm
421                     .getString("standardSession.getLastAccessedTime"));
422
423         }
424         return (this.lastAccessedTime);
425
426     }
427
428     /**
429      * Return the Manager within which this Session is valid.
430      */

431     public Manager getManager() {
432
433         return (this.manager);
434
435     }
436
437     /**
438      * Set the Manager within which this Session is valid.
439      *
440      * @param manager
441      * The new Manager
442      */

443     public void setManager(Manager manager) {
444
445         this.manager = manager;
446
447     }
448
449     /**
450      * Return the maximum time interval, in seconds, between client requests
451      * before the servlet container will invalidate the session. A negative time
452      * indicates that the session should never time out.
453      */

454     public int getMaxInactiveInterval() {
455
456         return (this.maxInactiveInterval);
457
458     }
459
460     /**
461      * Set the maximum time interval, in seconds, between client requests before
462      * the servlet container will invalidate the session. A negative time
463      * indicates that the session should never time out.
464      *
465      * @param interval
466      * The new maximum interval
467      */

468     public void setMaxInactiveInterval(int interval) {
469         setMaxInactiveInterval(interval, true);
470     }
471
472     public void setMaxInactiveInterval(int interval, boolean addDeltaRequest) {
473
474         this.maxInactiveInterval = interval;
475         if (isValid && interval == 0) {
476             expire();
477         } else {
478             if (addDeltaRequest && (deltaRequest != null))
479                 deltaRequest.setMaxInactiveInterval(interval);
480         }
481
482     }
483
484     /**
485      * Set the <code>isNew</code> flag for this session.
486      *
487      * @param isNew
488      * The new value for the <code>isNew</code> flag
489      */

490     public void setNew(boolean isNew) {
491         setNew(isNew, true);
492     }
493
494     public void setNew(boolean isNew, boolean addDeltaRequest) {
495         this.isNew = isNew;
496         if (addDeltaRequest && (deltaRequest != null))
497             deltaRequest.setNew(isNew);
498     }
499
500     /**
501      * Return the authenticated Principal that is associated with this Session.
502      * This provides an <code>Authenticator</code> with a means to cache a
503      * previously authenticated Principal, and avoid potentially expensive
504      * <code>Realm.authenticate()</code> calls on every request. If there is
505      * no current associated Principal, return <code>null</code>.
506      */

507     public Principal JavaDoc getPrincipal() {
508
509         return (this.principal);
510
511     }
512
513     /**
514      * Set the authenticated Principal that is associated with this Session.
515      * This provides an <code>Authenticator</code> with a means to cache a
516      * previously authenticated Principal, and avoid potentially expensive
517      * <code>Realm.authenticate()</code> calls on every request.
518      *
519      * @param principal
520      * The new Principal, or <code>null</code> if none
521      */

522     public void setPrincipal(Principal JavaDoc principal) {
523         setPrincipal(principal, true);
524     }
525
526     public void setPrincipal(Principal JavaDoc principal, boolean addDeltaRequest) {
527         Principal JavaDoc oldPrincipal = this.principal;
528         this.principal = principal;
529         support.firePropertyChange("principal", oldPrincipal, this.principal);
530         if (addDeltaRequest && (deltaRequest != null))
531             deltaRequest.setPrincipal(principal);
532     }
533
534     /**
535      * Return the <code>HttpSession</code> for which this object is the
536      * facade.
537      */

538     public HttpSession JavaDoc getSession() {
539
540         if (facade == null) {
541             if (System.getSecurityManager() != null) {
542                 final DeltaSession fsession = this;
543                 facade = (DeltaSessionFacade) AccessController
544                         .doPrivileged(new PrivilegedAction JavaDoc() {
545                             public Object JavaDoc run() {
546                                 return new DeltaSessionFacade(fsession);
547                             }
548                         });
549             } else {
550                 facade = new DeltaSessionFacade(this);
551             }
552         }
553         return (facade);
554
555     }
556
557     /**
558      * Return the <code>isValid</code> flag for this session.
559      */

560     public boolean isValid() {
561
562         if (this.expiring) {
563             return true;
564         }
565
566         if (!this.isValid) {
567             return false;
568         }
569
570         if (accessCount > 0) {
571             return true;
572         }
573
574         if (maxInactiveInterval >= 0) {
575             long timeNow = System.currentTimeMillis();
576             int timeIdle = (int) ((timeNow - lastAccessedTime) / 1000L);
577             if ((timeIdle >= maxInactiveInterval) && (isPrimarySession())) {
578                 expire(true);
579             } else if (timeIdle >= (2 * maxInactiveInterval)) {
580                 //if the session has been idle twice as long as allowed,
581
//the primary session has probably crashed, and no other
582
//requests are coming in. that is why we do this. otherwise
583
//we would have a memory leak
584
expire(true, false);
585             }
586         }
587
588         return (this.isValid);
589     }
590
591     /**
592      * Set the <code>isValid</code> flag for this session.
593      *
594      * @param isValid
595      * The new value for the <code>isValid</code> flag
596      */

597     public void setValid(boolean isValid) {
598
599         this.isValid = isValid;
600     }
601
602     // ------------------------------------------------- Session Public Methods
603

604     /**
605      * Update the accessed time information for this session. This method should
606      * be called by the context when a request comes in for a particular
607      * session, even if the application does not reference it.
608      */

609     public void access() {
610
611         this.lastAccessedTime = this.thisAccessedTime;
612         this.thisAccessedTime = System.currentTimeMillis();
613
614         evaluateIfValid();
615
616         accessCount++;
617     }
618
619     public void endAccess() {
620         isNew = false;
621         accessCount--;
622     }
623
624     /**
625      * Add a session event listener to this component.
626      */

627     public void addSessionListener(SessionListener JavaDoc listener) {
628
629         synchronized (listeners) {
630             listeners.add(listener);
631         }
632
633     }
634
635     /**
636      * Perform the internal processing required to invalidate this session,
637      * without triggering an exception if the session has already expired.
638      */

639     public void expire() {
640
641         expire(true);
642
643     }
644
645     /**
646      * Perform the internal processing required to invalidate this session,
647      * without triggering an exception if the session has already expired.
648      *
649      * @param notify
650      * Should we notify listeners about the demise of this session?
651      */

652     public void expire(boolean notify) {
653         expire(notify, true);
654     }
655
656     public void expire(boolean notify, boolean notifyCluster) {
657
658         // Mark this session as "being expired" if needed
659
if (expiring)
660             return;
661         String JavaDoc expiredId = getId();
662
663         synchronized (this) {
664
665             if (manager == null)
666                 return;
667
668             expiring = true;
669
670             // Notify interested application event listeners
671
// FIXME - Assumes we call listeners in reverse order
672
Context JavaDoc context = (Context JavaDoc) manager.getContainer();
673             //fix for standalone manager without container
674
if (context != null) {
675                 Object JavaDoc listeners[] = context.getApplicationLifecycleListeners();
676                 if (notify && (listeners != null)) {
677                     HttpSessionEvent JavaDoc event = new HttpSessionEvent JavaDoc(getSession());
678                     for (int i = 0; i < listeners.length; i++) {
679                         int j = (listeners.length - 1) - i;
680                         if (!(listeners[j] instanceof HttpSessionListener JavaDoc))
681                             continue;
682                         HttpSessionListener JavaDoc listener = (HttpSessionListener JavaDoc) listeners[j];
683                         try {
684                             fireContainerEvent(context,
685                                     "beforeSessionDestroyed", listener);
686                             listener.sessionDestroyed(event);
687                             fireContainerEvent(context,
688                                     "afterSessionDestroyed", listener);
689                         } catch (Throwable JavaDoc t) {
690                             try {
691                                 fireContainerEvent(context,
692                                         "afterSessionDestroyed", listener);
693                             } catch (Exception JavaDoc e) {
694                                 ;
695                             }
696                             // FIXME - should we do anything besides log these?
697
log.error(sm
698                                     .getString("standardSession.sessionEvent"),
699                                     t);
700                         }
701                     }
702                 }
703             }//end if
704
//end fix
705
accessCount = 0;
706             setValid(false);
707
708             // Remove this session from our manager's active sessions
709
if (manager != null)
710                 manager.remove(this);
711
712             // Notify interested session event listeners
713
if (notify) {
714                 fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
715             }
716
717             // We have completed expire of this session
718
expiring = false;
719
720             // Unbind any objects associated with this session
721
String JavaDoc keys[] = keys();
722             for (int i = 0; i < keys.length; i++)
723                 removeAttributeInternal(keys[i], notify, false);
724
725             if (notifyCluster) {
726                 if (log.isDebugEnabled())
727                     log.debug(smp.getString("deltaSession.notifying",
728                             ((DeltaManager) manager).getName(), new Boolean JavaDoc(
729                                     isPrimarySession()), expiredId));
730                 ((DeltaManager) manager).sessionExpired(expiredId);
731             }
732
733         }
734
735     }
736
737     /**
738      * Return the object bound with the specified name to the internal notes for
739      * this session, or <code>null</code> if no such binding exists.
740      *
741      * @param name
742      * Name of the note to be returned
743      */

744     public Object JavaDoc getNote(String JavaDoc name) {
745
746         synchronized (notes) {
747             return (notes.get(name));
748         }
749
750     }
751
752     /**
753      * Return an Iterator containing the String names of all notes bindings that
754      * exist for this session.
755      */

756     public Iterator JavaDoc getNoteNames() {
757
758         synchronized (notes) {
759             return (notes.keySet().iterator());
760         }
761
762     }
763
764     /**
765      * Release all object references, and initialize instance variables, in
766      * preparation for reuse of this object.
767      */

768     public void recycle() {
769
770         // Reset the instance variables associated with this Session
771
attributes.clear();
772         setAuthType(null);
773         creationTime = 0L;
774         expiring = false;
775         id = null;
776         lastAccessedTime = 0L;
777         maxInactiveInterval = -1;
778         accessCount = 0;
779         notes.clear();
780         setPrincipal(null);
781         isNew = false;
782         isValid = false;
783         manager = null;
784         deltaRequest.clear();
785
786     }
787
788     /**
789      * Remove any object bound to the specified name in the internal notes for
790      * this session.
791      *
792      * @param name
793      * Name of the note to be removed
794      */

795     public void removeNote(String JavaDoc name) {
796
797         synchronized (notes) {
798             notes.remove(name);
799         }
800
801     }
802
803     /**
804      * Remove a session event listener from this component.
805      */

806     public void removeSessionListener(SessionListener JavaDoc listener) {
807
808         synchronized (listeners) {
809             listeners.remove(listener);
810         }
811
812     }
813
814     /**
815      * Bind an object to a specified name in the internal notes associated with
816      * this session, replacing any existing binding for this name.
817      *
818      * @param name
819      * Name to which the object should be bound
820      * @param value
821      * Object to be bound to the specified name
822      */

823     public void setNote(String JavaDoc name, Object JavaDoc value) {
824
825         synchronized (notes) {
826             notes.put(name, value);
827         }
828
829     }
830
831     /**
832      * Return a string representation of this object.
833      */

834     public String JavaDoc toString() {
835
836         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
837         sb.append("StandardSession[");
838         sb.append(id);
839         sb.append("]");
840         return (sb.toString());
841
842     }
843
844     // ------------------------------------------------ Session Package Methods
845

846     /**
847      * Read a serialized version of the contents of this session object from the
848      * specified object input stream, without requiring that the StandardSession
849      * itself have been serialized.
850      *
851      * @param stream
852      * The object input stream to read from
853      *
854      * @exception ClassNotFoundException
855      * if an unknown class is specified
856      * @exception IOException
857      * if an input/output error occurs
858      */

859     public void readObjectData(ObjectInputStream JavaDoc stream)
860             throws ClassNotFoundException JavaDoc, IOException JavaDoc {
861
862         readObject(stream);
863
864     }
865
866     /**
867      * Write a serialized version of the contents of this session object to the
868      * specified object output stream, without requiring that the
869      * StandardSession itself have been serialized.
870      *
871      * @param stream
872      * The object output stream to write to
873      *
874      * @exception IOException
875      * if an input/output error occurs
876      */

877     public void writeObjectData(ObjectOutputStream JavaDoc stream) throws IOException JavaDoc {
878
879         writeObject(stream);
880
881     }
882
883     public void resetDeltaRequest() {
884         if (deltaRequest == null) {
885             deltaRequest = new DeltaRequest(getId(), false);
886         } else {
887             deltaRequest.reset();
888             deltaRequest.setSessionId(getId());
889         }
890     }
891
892     public DeltaRequest getDeltaRequest() {
893         if (deltaRequest == null)
894             resetDeltaRequest();
895         return deltaRequest;
896     }
897
898     // ------------------------------------------------- HttpSession Properties
899

900     /**
901      * Return the time when this s