001: package de.webman.template.jsp;
002:
003: import java.io.IOException;
004: import java.io.ObjectInputStream;
005: import java.io.ObjectOutputStream;
006: import java.io.Serializable;
007: import java.util.Enumeration;
008: import java.util.Hashtable;
009: import java.util.Vector;
010: import javax.servlet.ServletException;
011: import javax.servlet.ServletContext;
012: import javax.servlet.http.HttpSession;
013: import javax.servlet.http.HttpSessionBindingEvent;
014: import javax.servlet.http.HttpSessionBindingListener;
015: import javax.servlet.http.HttpSessionContext;
016:
017: /**
018: * Standard implementation of the <b>Session</b> interface. This object is
019: * serializable, so that it can be stored in persistent storage or transferred
020: * to a different JVM for distributable session support.
021: * @author $Author: alex $
022: * @version $Revision: 1.3 $
023: */
024: final class WebManSession implements HttpSession, Serializable {
025:
026: private ServletContext context;
027:
028: /**
029: * Construct a new Session associated with the specified Manager.
030: *
031: * @param manager The manager with which this Session is associated
032: */
033: WebManSession(ServletContext _context) {
034: context = _context;
035: }
036:
037: /**
038: 2.3
039: */
040: public ServletContext getServletContext() {
041: return context;
042: }
043:
044: /**
045: * The collection of user data attributes associated with this Session.
046: */
047: private Hashtable attributes = new Hashtable();
048:
049: /**
050: * The time this session was created, in milliseconds since midnight,
051: * January 1, 1970 GMT.
052: */
053: private long creationTime;
054:
055: /**
056: * The session identifier of this Session.
057: */
058: private String id = null;
059:
060: /**
061: * Descriptive information describing this Session implementation.
062: */
063: private static final String INFO = "StandardSession/1.0";
064:
065: /**
066: * The last accessed time for this Session.
067: */
068: private long lastAccessedTime = creationTime;
069:
070: /**
071: * The maximum time interval, in seconds, between client requests before
072: * the servlet container may invalidate this session. A negative time
073: * indicates that the session should never time out.
074: */
075: private int maxInactiveInterval = -1;
076:
077: /**
078: * Flag indicating whether this session is new or not.
079: */
080: private boolean isNew = true;
081:
082: /**
083: * Flag indicating whether this session is valid or not.
084: */
085: private boolean isValid = false;
086:
087: /**
088: * The HTTP session context associated with this session.
089: */
090: private static HttpSessionContext sessionContext = null;
091:
092: /**
093: * The current accessed time for this session.
094: */
095: private long this AccessedTime = creationTime;
096:
097: // ----------------------------------------------------- Session Properties
098:
099: /**
100: * Set the creation time for this session. This method is called by the
101: * Manager when an existing Session instance is reused.
102: *
103: * @param time The new creation time
104: */
105: public void setCreationTime(long time) {
106:
107: this .creationTime = time;
108: this .lastAccessedTime = time;
109: this .this AccessedTime = time;
110:
111: }
112:
113: /**
114: * Return the session identifier for this session.
115: */
116: public String getId() {
117:
118: return (this .id);
119:
120: }
121:
122: /**
123: * Set the session identifier for this session.
124: *
125: * @param id The new session identifier
126: */
127: public void setId(String id) {
128:
129: this .id = id;
130:
131: }
132:
133: /**
134: * Return descriptive information about this Session implementation and
135: * the corresponding version number, in the format
136: * <code><description>/<version></code>.
137: */
138: public String getInfo() {
139: return INFO;
140: }
141:
142: /**
143: * Return the last time the client sent a request associated with this
144: * session, as the number of milliseconds since midnight, January 1, 1970
145: * GMT. Actions that your application takes, such as getting or setting
146: * a value associated with the session, do not affect the access time.
147: */
148: public long getLastAccessedTime() {
149:
150: return (this .lastAccessedTime);
151:
152: }
153:
154: /**
155: * Return the maximum time interval, in seconds, between client requests
156: * before the servlet container will invalidate the session. A negative
157: * time indicates that the session should never time out.
158: *
159: * @exception IllegalStateException if this method is called on
160: * an invalidated session
161: */
162: public int getMaxInactiveInterval() {
163:
164: return (this .maxInactiveInterval);
165:
166: }
167:
168: /**
169: * Set the maximum time interval, in seconds, between client requests
170: * before the servlet container will invalidate the session. A negative
171: * time indicates that the session should never time out.
172: *
173: * @param interval The new maximum interval
174: */
175: public void setMaxInactiveInterval(int interval) {
176:
177: this .maxInactiveInterval = interval;
178:
179: }
180:
181: /**
182: * Return the <code>HttpSession</code> for which this object
183: * is the facade.
184: */
185: public HttpSession getSession() {
186:
187: return ((HttpSession) this );
188:
189: }
190:
191: // ------------------------------------------------- Session Public Methods
192:
193: /**
194: * Update the accessed time information for this session. This method
195: * should be called by the context when a request comes in for a particular
196: * session, even if the application does not reference it.
197: */
198: public void access() {
199:
200: this .lastAccessedTime = this .this AccessedTime;
201: this .this AccessedTime = System.currentTimeMillis();
202: this .isNew = false;
203: }
204:
205: /**
206: * Perform the internal processing required to invalidate this session,
207: * without triggering an exception if the session has already expired.
208: */
209: public void expire() {
210:
211: // Unbind any objects associated with this session
212: Vector results = new Vector();
213: Enumeration attrs = getAttributeNames();
214: while (attrs.hasMoreElements()) {
215: String attr = (String) attrs.nextElement();
216: results.addElement(attr);
217: }
218: Enumeration names = results.elements();
219: while (names.hasMoreElements()) {
220: String name = (String) names.nextElement();
221: removeAttribute(name);
222: }
223:
224: // Mark this session as invalid
225: setValid(false);
226:
227: }
228:
229: /**
230: * Release all object references, and initialize instance variables, in
231: * preparation for reuse of this object.
232: */
233: public void recycle() {
234:
235: // Reset the instance variables associated with this Session
236: attributes.clear();
237: creationTime = 0;
238: id = null;
239: lastAccessedTime = 0;
240: maxInactiveInterval = -1;
241: isNew = true;
242: isValid = false;
243:
244: }
245:
246: // ------------------------------------------------ Session Package Methods
247:
248: /**
249: * Return the <code>isValid</code> flag for this session.
250: */
251: boolean isValid() {
252:
253: return (this .isValid);
254:
255: }
256:
257: /**
258: * Set the <code>isNew</code> flag for this session.
259: *
260: * @param isNew The new value for the <code>isNew</code> flag
261: */
262: void setNew(boolean isNew) {
263:
264: this .isNew = isNew;
265:
266: }
267:
268: /**
269: * Set the <code>isValid</code> flag for this session.
270: *
271: * @param isValid The new value for the <code>isValid</code> flag
272: */
273: void setValid(boolean isValid) {
274:
275: this .isValid = isValid;
276: }
277:
278: // ------------------------------------------------- HttpSession Properties
279:
280: /**
281: * Return the time when this session was created, in milliseconds since
282: * midnight, January 1, 1970 GMT.
283: *
284: * @exception IllegalStateException if this method is called on an
285: * invalidated session
286: */
287: public long getCreationTime() {
288:
289: return (this .creationTime);
290:
291: }
292:
293: /**
294: * Return the session context with which this session is associated.
295: *
296: * @deprecated As of Version 2.1, this method is deprecated and has no
297: * replacement. It will be removed in a future version of the
298: * Java Servlet API.
299: */
300: public HttpSessionContext getSessionContext() {
301:
302: if (sessionContext == null)
303: sessionContext = new SessionContextImpl();
304: return (sessionContext);
305:
306: }
307:
308: // ----------------------------------------------HttpSession Public Methods
309:
310: /**
311: * Return the object bound with the specified name in this session, or
312: * <code>null</code> if no object is bound with that name.
313: *
314: * @param name Name of the attribute to be returned
315: *
316: * @exception IllegalStateException if this method is called on an
317: * invalidated session
318: */
319: public Object getAttribute(String name) {
320:
321: return (attributes.get(name));
322:
323: }
324:
325: /**
326: * Return an <code>Enumeration</code> of <code>String</code> objects
327: * containing the names of the objects bound to this session.
328: *
329: * @exception IllegalStateException if this method is called on an
330: * invalidated session
331: */
332: public Enumeration getAttributeNames() {
333: return (attributes.keys());
334: }
335:
336: /**
337: * Return the object bound with the specified name in this session, or
338: * <code>null</code> if no object is bound with that name.
339: *
340: * @param name Name of the value to be returned
341: *
342: * @exception IllegalStateException if this method is called on an
343: * invalidated session
344: *
345: * @deprecated As of Version 2.2, this method is replaced by
346: * <code>getAttribute()</code>
347: */
348: public Object getValue(String name) {
349:
350: return (getAttribute(name));
351:
352: }
353:
354: /**
355: * Return the set of names of objects bound to this session. If there
356: * are no such objects, a zero-length array is returned.
357: *
358: * @exception IllegalStateException if this method is called on an
359: * invalidated session
360: *
361: * @deprecated As of Version 2.2, this method is replaced by
362: * <code>getAttributeNames()</code>
363: */
364: public String[] getValueNames() {
365:
366: Vector results = new Vector();
367: Enumeration attrs = getAttributeNames();
368: while (attrs.hasMoreElements()) {
369: String attr = (String) attrs.nextElement();
370: results.addElement(attr);
371: }
372: String names[] = new String[results.size()];
373: for (int i = 0; i < names.length; i++)
374: names[i] = (String) results.elementAt(i);
375: return (names);
376:
377: }
378:
379: /**
380: * Invalidates this session and unbinds any objects bound to it.
381: *
382: * @exception IllegalStateException if this method is called on
383: * an invalidated session
384: */
385: public void invalidate() {
386:
387: // Cause this session to expire
388: expire();
389:
390: }
391:
392: /**
393: * Return <code>true</code> if the client does not yet know about the
394: * session, or if the client chooses not to join the session. For
395: * example, if the server used only cookie-based sessions, and the client
396: * has disabled the use of cookies, then a session would be new on each
397: * request.
398: *
399: * @exception IllegalStateException if this method is called on an
400: * invalidated session
401: */
402: public boolean isNew() {
403: return (this .isNew);
404:
405: }
406:
407: /**
408: * Bind an object to this session, using the specified name. If an object
409: * of the same name is already bound to this session, the object is
410: * replaced.
411: * <p>
412: * After this method executes, and if the object implements
413: * <code>HttpSessionBindingListener</code>, the container calls
414: * <code>valueBound()</code> on the object.
415: *
416: * @param name Name to which the object is bound, cannot be null
417: * @param value Object to be bound, cannot be null
418: *
419: * @exception IllegalStateException if this method is called on an
420: * invalidated session
421: *
422: * @deprecated As of Version 2.2, this method is replaced by
423: * <code>setAttribute()</code>
424: */
425: public void putValue(String name, Object value) {
426:
427: setAttribute(name, value);
428:
429: }
430:
431: /**
432: * Remove the object bound with the specified name from this session. If
433: * the session does not have an object bound with this name, this method
434: * does nothing.
435: * <p>
436: * After this method executes, and if the object implements
437: * <code>HttpSessionBindingListener</code>, the container calls
438: * <code>valueUnbound()</code> on the object.
439: *
440: * @param name Name of the object to remove from this session.
441: *
442: * @exception IllegalStateException if this method is called on an
443: * invalidated session
444: */
445: public void removeAttribute(String name) {
446:
447: synchronized (attributes) {
448: Object object = attributes.get(name);
449: if (object == null)
450: return;
451: attributes.remove(name);
452: if (object instanceof HttpSessionBindingListener) {
453: ((HttpSessionBindingListener) object)
454: .valueUnbound(new HttpSessionBindingEvent(
455: (HttpSession) this , name));
456: }
457: }
458:
459: }
460:
461: /**
462: * Remove the object bound with the specified name from this session. If
463: * the session does not have an object bound with this name, this method
464: * does nothing.
465: * <p>
466: * After this method executes, and if the object implements
467: * <code>HttpSessionBindingListener</code>, the container calls
468: * <code>valueUnbound()</code> on the object.
469: *
470: * @param name Name of the object to remove from this session.
471: *
472: * @exception IllegalStateException if this method is called on an
473: * invalidated session
474: *
475: * @deprecated As of Version 2.2, this method is replaced by
476: * <code>removeAttribute()</code>
477: */
478: public void removeValue(String name) {
479:
480: removeAttribute(name);
481:
482: }
483:
484: /**
485: * Bind an object to this session, using the specified name. If an object
486: * of the same name is already bound to this session, the object is
487: * replaced.
488: * <p>
489: * After this method executes, and if the object implements
490: * <code>HttpSessionBindingListener</code>, the container calls
491: * <code>valueBound()</code> on the object.
492: *
493: * @param name Name to which the object is bound, cannot be null
494: * @param value Object to be bound, cannot be null
495: *
496: * @exception IllegalArgumentException if an attempt is made to add a
497: * non-serializable object in an environment marked distributable.
498: * @exception IllegalStateException if this method is called on an
499: * invalidated session
500: */
501: public void setAttribute(String name, Object value) {
502: // System.out.println("Set attribute: " + name + " , " + value + " " + this);
503: synchronized (attributes) {
504: removeAttribute(name);
505: attributes.put(name, value);
506: if (value instanceof HttpSessionBindingListener)
507: ((HttpSessionBindingListener) value)
508: .valueBound(new HttpSessionBindingEvent(
509: (HttpSession) this , name));
510: }
511:
512: }
513:
514: // -------------------------------------------- HttpSession Private Methods
515:
516: /**
517: * Read a serialized version of this session object from the specified
518: * object input stream.
519: * <p>
520: * <b>IMPLEMENTATION NOTE</b>: The reference to the owning Manager
521: * is not restored by this method, and must be set explicitly.
522: *
523: * @param stream The input stream to read from
524: *
525: * @exception ClassNotFoundException if an unknown class is specified
526: * @exception IOException if an input/output error occurs
527: */
528: private void readObject(ObjectInputStream stream)
529: throws ClassNotFoundException, IOException {
530:
531: // Deserialize the scalar instance variables (except Manager)
532: creationTime = ((Long) stream.readObject()).longValue();
533: id = (String) stream.readObject();
534: lastAccessedTime = ((Long) stream.readObject()).longValue();
535: this AccessedTime = ((Long) stream.readObject()).longValue();
536: maxInactiveInterval = ((Integer) stream.readObject())
537: .intValue();
538: isNew = ((Boolean) stream.readObject()).booleanValue();
539: isValid = ((Boolean) stream.readObject()).booleanValue();
540:
541: attributes = (Hashtable) stream.readObject();
542: }
543:
544: /**
545: * Write a serialized version of this session object to the specified
546: * object output stream.
547: * <p>
548: * <b>IMPLEMENTATION NOTE</b>: The owning Manager will not be stored
549: * in the serialized representation of this Session. After calling
550: * <code>readObject()</code>, you must set the associated Manager
551: * explicitly.
552: * <p>
553: * <b>IMPLEMENTATION NOTE</b>: Any attribute that is not Serializable
554: * will be silently ignored. If you do not want any such attributes,
555: * be sure the <code>distributable</code> property of our associated
556: * Manager is set to <code>true</code>.
557: * <p>
558: * <b>IMPLEMENTATION NOTE</b>: If we can't serialize the object stored in
559: * the session, then check to see if it implements
560: * HttpSessionBindingListener and then call its
561: * valueUnbound method, allowing it to save its state
562: * correctly instead of just being lost into the etherworld
563: *
564: * @param stream The output stream to write to
565: *
566: * @exception IOException if an input/output error occurs
567: */
568: private void writeObject(ObjectOutputStream stream)
569: throws IOException {
570:
571: // Write the scalar instance variables (except Manager)
572: stream.writeObject(new Long(creationTime));
573: stream.writeObject(id);
574: stream.writeObject(new Long(lastAccessedTime));
575: stream.writeObject(new Long(this AccessedTime));
576: stream.writeObject(new Integer(maxInactiveInterval));
577: stream.writeObject(new Boolean(isNew));
578: stream.writeObject(new Boolean(isValid));
579:
580: if (attributes.size() > 0) {
581: // Accumulate the names of serializable attributes
582: Hashtable results = new Hashtable(attributes.size());
583:
584: for (Enumeration e = attributes.keys(); e.hasMoreElements();) {
585: String key = (String) e.nextElement();
586: Object value = attributes.get(key);
587: if (value instanceof Serializable) {
588: results.put(key, value);
589: }
590: // if we can't serialize the object stored in
591: // the session, then check to see if it implements
592: // HttpSessionBindingListener and then call its
593: // valueUnbound method, allowing it to save its state
594: // correctly instead of just being lost into the etherworld
595: else if (value instanceof HttpSessionBindingListener) {
596: try {
597: ((HttpSessionBindingListener) value)
598: .valueUnbound(new HttpSessionBindingEvent(
599: this , key));
600: } catch (Exception f) {
601: // JTest Mist
602: f.hashCode();
603: // ignored
604: }
605: }
606: }
607: stream.writeObject(results);
608: } else {
609: stream.writeObject(new Hashtable());
610: }
611: }
612: }
613:
614: class SessionContextImpl implements HttpSessionContext {
615:
616: /**
617: *
618: * @deprecated
619: */
620:
621: public HttpSession getSession(String sessionId) {
622: return null;
623: }
624:
625: /**
626: *
627: * @deprecated
628: */
629:
630: public Enumeration getIds() {
631: // cheap hack to get an empty enum
632: Vector v = new Vector();
633:
634: return v.elements();
635: }
636: }
|