0001: /*
0002: * Copyright 1999,2004 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.apache.catalina.cluster.session;
0018:
0019: import java.beans.PropertyChangeSupport;
0020: import java.io.IOException;
0021: import java.io.NotSerializableException;
0022: import java.io.ObjectInputStream;
0023: import java.io.ObjectOutputStream;
0024: import java.io.Serializable;
0025: import java.lang.reflect.Method;
0026: import java.security.AccessController;
0027: import java.security.Principal;
0028: import java.security.PrivilegedAction;
0029: import java.util.ArrayList;
0030: import java.util.Enumeration;
0031: import java.util.HashMap;
0032: import java.util.Iterator;
0033:
0034: import javax.servlet.ServletContext;
0035: import javax.servlet.http.HttpSession;
0036: import javax.servlet.http.HttpSessionActivationListener;
0037: import javax.servlet.http.HttpSessionAttributeListener;
0038: import javax.servlet.http.HttpSessionBindingEvent;
0039: import javax.servlet.http.HttpSessionBindingListener;
0040: import javax.servlet.http.HttpSessionContext;
0041: import javax.servlet.http.HttpSessionEvent;
0042: import javax.servlet.http.HttpSessionListener;
0043:
0044: import org.apache.catalina.Context;
0045: import org.apache.catalina.Manager;
0046: import org.apache.catalina.Session;
0047: import org.apache.catalina.SessionEvent;
0048: import org.apache.catalina.SessionListener;
0049: import org.apache.catalina.util.Enumerator;
0050: import org.apache.catalina.util.StringManager;
0051:
0052: import org.apache.catalina.session.ManagerBase;
0053: import org.apache.catalina.session.Constants;
0054: import org.apache.catalina.cluster.ClusterSession;
0055: import org.apache.catalina.realm.GenericPrincipal;
0056:
0057: /**
0058: *
0059: * Similar to the StandardSession, this code is identical, but for update
0060: * and some small issues, simply copied in the first release.
0061: * This session will keep track of deltas during a request.
0062: * <p>
0063: * <b>IMPLEMENTATION NOTE</b>: An instance of this class represents both the
0064: * internal (Session) and application level (HttpSession) view of the session.
0065: * However, because the class itself is not declared public, Java logic outside
0066: * of the <code>org.apache.catalina.session</code> package cannot cast an
0067: * HttpSession view of this instance back to a Session view.
0068: * <p>
0069: * <b>IMPLEMENTATION NOTE</b>: If you add fields to this class, you must
0070: * make sure that you carry them over in the read/writeObject methods so
0071: * that this class is properly serialized.
0072: *
0073: * @author Filip Hanik
0074: * @author Craig R. McClanahan
0075: * @author Sean Legassick
0076: * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
0077: * @version $Revision: 1.24 $ $Date: 2004/06/02 14:10:01 $
0078: */
0079:
0080: public class DeltaSession implements HttpSession, Session,
0081: Serializable, ClusterSession {
0082:
0083: public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
0084: .getLog(DeltaManager.class);
0085:
0086: // ----------------------------------------------------------- Constructors
0087:
0088: /**
0089: * Construct a new Session associated with the specified Manager.
0090: *
0091: * @param manager The manager with which this Session is associated
0092: */
0093: public DeltaSession(Manager manager) {
0094:
0095: super ();
0096: this .manager = manager;
0097: if (manager instanceof ManagerBase)
0098: this .debug = ((ManagerBase) manager).getDebug();
0099:
0100: }
0101:
0102: // ----------------------------------------------------- Instance Variables
0103:
0104: /**
0105: * The dummy attribute value serialized when a NotSerializableException is
0106: * encountered in <code>writeObject()</code>.
0107: */
0108: private static final String NOT_SERIALIZED = "___NOT_SERIALIZABLE_EXCEPTION___";
0109:
0110: /**
0111: * The collection of user data attributes associated with this Session.
0112: */
0113: private HashMap attributes = new HashMap();
0114:
0115: /**
0116: * The authentication type used to authenticate our cached Principal,
0117: * if any. NOTE: This value is not included in the serialized
0118: * version of this object.
0119: */
0120: private transient String authType = null;
0121:
0122: /**
0123: * The <code>java.lang.Method</code> for the
0124: * <code>fireContainerEvent()</code> method of the
0125: * <code>org.apache.catalina.core.StandardContext</code> method,
0126: * if our Context implementation is of this class. This value is
0127: * computed dynamically the first time it is needed, or after
0128: * a session reload (since it is declared transient).
0129: */
0130: private transient Method containerEventMethod = null;
0131:
0132: /**
0133: * The method signature for the <code>fireContainerEvent</code> method.
0134: */
0135: private static final Class containerEventTypes[] = { String.class,
0136: Object.class };
0137:
0138: /**
0139: * The time this session was created, in milliseconds since midnight,
0140: * January 1, 1970 GMT.
0141: */
0142: private long creationTime = 0L;
0143:
0144: /**
0145: * The debugging detail level for this component. NOTE: This value
0146: * is not included in the serialized version of this object.
0147: */
0148: private transient int debug = 0;
0149:
0150: /**
0151: * We are currently processing a session expiration, so bypass
0152: * certain IllegalStateException tests. NOTE: This value is not
0153: * included in the serialized version of this object.
0154: */
0155: private transient boolean expiring = false;
0156:
0157: /**
0158: * The facade associated with this session. NOTE: This value is not
0159: * included in the serialized version of this object.
0160: */
0161: private transient DeltaSessionFacade facade = null;
0162:
0163: /**
0164: * The session identifier of this Session.
0165: */
0166: private String id = null;
0167:
0168: /**
0169: * Descriptive information describing this Session implementation.
0170: */
0171: private static final String info = "DeltaSession/1.0";
0172:
0173: /**
0174: * The last accessed time for this Session.
0175: */
0176: private long lastAccessedTime = creationTime;
0177:
0178: /**
0179: * The session event listeners for this Session.
0180: */
0181: private transient ArrayList listeners = new ArrayList();
0182:
0183: /**
0184: * The Manager with which this Session is associated.
0185: */
0186: private transient Manager manager = null;
0187:
0188: /**
0189: * The maximum time interval, in seconds, between client requests before
0190: * the servlet container may invalidate this session. A negative time
0191: * indicates that the session should never time out.
0192: */
0193: private int maxInactiveInterval = -1;
0194:
0195: /**
0196: * Flag indicating whether this session is new or not.
0197: */
0198: private boolean isNew = false;
0199:
0200: /**
0201: * Flag indicating whether this session is valid or not.
0202: */
0203: private boolean isValid = false;
0204:
0205: /**
0206: * Internal notes associated with this session by Catalina components
0207: * and event listeners. <b>IMPLEMENTATION NOTE:</b> This object is
0208: * <em>not</em> saved and restored across session serializations!
0209: */
0210: private transient HashMap notes = new HashMap();
0211:
0212: /**
0213: * The authenticated Principal associated with this session, if any.
0214: * <b>IMPLEMENTATION NOTE:</b> This object is <i>not</i> saved and
0215: * restored across session serializations!
0216: */
0217: private transient Principal principal = null;
0218:
0219: /**
0220: * The string manager for this package.
0221: */
0222: private static StringManager sm = StringManager
0223: .getManager(Constants.Package);
0224:
0225: /**
0226: * The HTTP session context associated with this session.
0227: */
0228: private static HttpSessionContext sessionContext = null;
0229:
0230: /**
0231: * The property change support for this component. NOTE: This value
0232: * is not included in the serialized version of this object.
0233: */
0234: private transient PropertyChangeSupport support = new PropertyChangeSupport(
0235: this );
0236:
0237: /**
0238: * The current accessed time for this session.
0239: */
0240: private long this AccessedTime = creationTime;
0241:
0242: /**
0243: * only the primary session will expire, or be able to
0244: * expire due to inactivity. This is set to false
0245: * as soon as I receive this session over the wire in
0246: * a session message. That means that someone else has
0247: * made a request on another server.
0248: */
0249: private transient boolean isPrimarySession = true;
0250:
0251: /**
0252: * The delta request contains all the action info
0253: *
0254: */
0255: private transient DeltaRequest deltaRequest = null;
0256:
0257: /**
0258: * Last time the session was replicatd, used for distributed
0259: * expiring of session
0260: */
0261: private transient long lastTimeReplicated = System
0262: .currentTimeMillis();
0263:
0264: /**
0265: * The access count for this session
0266: */
0267: protected transient int accessCount = 0;
0268:
0269: // ----------------------------------------------------- Session Properties
0270:
0271: /**
0272: * returns true if this session is the primary session, if that is the
0273: * case, the manager can expire it upon timeout.
0274: */
0275: public boolean isPrimarySession() {
0276: return isPrimarySession;
0277: }
0278:
0279: /**
0280: * Sets whether this is the primary session or not.
0281: * @param primarySession Flag value
0282: */
0283: public void setPrimarySession(boolean primarySession) {
0284: this .isPrimarySession = primarySession;
0285: }
0286:
0287: /**
0288: * Return the authentication type used to authenticate our cached
0289: * Principal, if any.
0290: */
0291: public String getAuthType() {
0292:
0293: return (this .authType);
0294:
0295: }
0296:
0297: /**
0298: * Set the authentication type used to authenticate our cached
0299: * Principal, if any.
0300: *
0301: * @param authType The new cached authentication type
0302: */
0303: public void setAuthType(String authType) {
0304:
0305: String oldAuthType = this .authType;
0306: this .authType = authType;
0307: support.firePropertyChange("authType", oldAuthType,
0308: this .authType);
0309:
0310: }
0311:
0312: /**
0313: * Set the creation time for this session. This method is called by the
0314: * Manager when an existing Session instance is reused.
0315: *
0316: * @param time The new creation time
0317: */
0318: public void setCreationTime(long time) {
0319:
0320: this .creationTime = time;
0321: this .lastAccessedTime = time;
0322: this .this AccessedTime = time;
0323:
0324: }
0325:
0326: /**
0327: * Return the session identifier for this session.
0328: */
0329: public String getId() {
0330:
0331: return (this .id);
0332:
0333: }
0334:
0335: /**
0336: * Set the session identifier for this session.
0337: *
0338: * @param id The new session identifier
0339: */
0340: public void setId(String id) {
0341:
0342: if ((this .id != null) && (manager != null))
0343: manager.remove(this );
0344:
0345: this .id = id;
0346:
0347: if (manager != null)
0348: manager.add(this );
0349: tellNew();
0350: }
0351:
0352: /**
0353: * Inform the listeners about the new session.
0354: *
0355: */
0356: public void tellNew() {
0357:
0358: // Notify interested session event listeners
0359: fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
0360:
0361: // Notify interested application event listeners
0362: Context context = (Context) manager.getContainer();
0363: //fix for standalone manager without container
0364: if (context != null) {
0365: Object listeners[] = context
0366: .getApplicationLifecycleListeners();
0367: if (listeners != null) {
0368: HttpSessionEvent event = new HttpSessionEvent(
0369: getSession());
0370: for (int i = 0; i < listeners.length; i++) {
0371: if (!(listeners[i] instanceof HttpSessionListener))
0372: continue;
0373: HttpSessionListener listener = (HttpSessionListener) listeners[i];
0374: try {
0375: fireContainerEvent(context,
0376: "beforeSessionCreated", listener);
0377: listener.sessionCreated(event);
0378: fireContainerEvent(context,
0379: "afterSessionCreated", listener);
0380: } catch (Throwable t) {
0381: try {
0382: fireContainerEvent(context,
0383: "afterSessionCreated", listener);
0384: } catch (Exception e) {
0385: ;
0386: }
0387: // FIXME - should we do anything besides log these?
0388: log
0389: .error(
0390: sm
0391: .getString("standardSession.sessionEvent"),
0392: t);
0393: }
0394: }
0395: }
0396: }//end if
0397: //end fix
0398:
0399: }
0400:
0401: /**
0402: * Return descriptive information about this Session implementation and
0403: * the corresponding version number, in the format
0404: * <code><description>/<version></code>.
0405: */
0406: public String getInfo() {
0407:
0408: return (this .info);
0409:
0410: }
0411:
0412: /**
0413: * Return the last time the client sent a request associated with this
0414: * session, as the number of milliseconds since midnight, January 1, 1970
0415: * GMT. Actions that your application takes, such as getting or setting
0416: * a value associated with the session, do not affect the access time.
0417: */
0418: public long getLastAccessedTime() {
0419: if (!isValid) {
0420: throw new IllegalStateException(sm
0421: .getString("standardSession.getLastAccessedTime"));
0422:
0423: }
0424: return (this .lastAccessedTime);
0425:
0426: }
0427:
0428: /**
0429: * Return the Manager within which this Session is valid.
0430: */
0431: public Manager getManager() {
0432:
0433: return (this .manager);
0434:
0435: }
0436:
0437: /**
0438: * Set the Manager within which this Session is valid.
0439: *
0440: * @param manager The new Manager
0441: */
0442: public void setManager(Manager manager) {
0443:
0444: this .manager = manager;
0445:
0446: }
0447:
0448: /**
0449: * Return the maximum time interval, in seconds, between client requests
0450: * before the servlet container will invalidate the session. A negative
0451: * time indicates that the session should never time out.
0452: */
0453: public int getMaxInactiveInterval() {
0454:
0455: return (this .maxInactiveInterval);
0456:
0457: }
0458:
0459: /**
0460: * Set the maximum time interval, in seconds, between client requests
0461: * before the servlet container will invalidate the session. A negative
0462: * time indicates that the session should never time out.
0463: *
0464: * @param interval The new maximum interval
0465: */
0466: public void setMaxInactiveInterval(int interval) {
0467: setMaxInactiveInterval(interval, true);
0468: }
0469:
0470: public void setMaxInactiveInterval(int interval,
0471: boolean addDeltaRequest) {
0472:
0473: this .maxInactiveInterval = interval;
0474: if (isValid && interval == 0) {
0475: expire();
0476: } else {
0477: if (addDeltaRequest && (deltaRequest != null))
0478: deltaRequest.setMaxInactiveInterval(interval);
0479: }
0480:
0481: }
0482:
0483: /**
0484: * Set the <code>isNew</code> flag for this session.
0485: *
0486: * @param isNew The new value for the <code>isNew</code> flag
0487: */
0488: public void setNew(boolean isNew) {
0489: setNew(isNew, true);
0490: }
0491:
0492: public void setNew(boolean isNew, boolean addDeltaRequest) {
0493: this .isNew = isNew;
0494: if (addDeltaRequest && (deltaRequest != null))
0495: deltaRequest.setNew(isNew);
0496: }
0497:
0498: /**
0499: * Return the authenticated Principal that is associated with this Session.
0500: * This provides an <code>Authenticator</code> with a means to cache a
0501: * previously authenticated Principal, and avoid potentially expensive
0502: * <code>Realm.authenticate()</code> calls on every request. If there
0503: * is no current associated Principal, return <code>null</code>.
0504: */
0505: public Principal getPrincipal() {
0506:
0507: return (this .principal);
0508:
0509: }
0510:
0511: /**
0512: * Set the authenticated Principal that is associated with this Session.
0513: * This provides an <code>Authenticator</code> with a means to cache a
0514: * previously authenticated Principal, and avoid potentially expensive
0515: * <code>Realm.authenticate()</code> calls on every request.
0516: *
0517: * @param principal The new Principal, or <code>null</code> if none
0518: */
0519: public void setPrincipal(Principal principal) {
0520: setPrincipal(principal, true);
0521: }
0522:
0523: public void setPrincipal(Principal principal,
0524: boolean addDeltaRequest) {
0525: Principal oldPrincipal = this .principal;
0526: this .principal = principal;
0527: support.firePropertyChange("principal", oldPrincipal,
0528: this .principal);
0529: if (addDeltaRequest && (deltaRequest != null))
0530: deltaRequest.setPrincipal(principal);
0531: }
0532:
0533: /**
0534: * Return the <code>HttpSession</code> for which this object
0535: * is the facade.
0536: */
0537: public HttpSession getSession() {
0538:
0539: if (facade == null) {
0540: if (System.getSecurityManager() != null) {
0541: final DeltaSession fsession = this ;
0542: facade = (DeltaSessionFacade) AccessController
0543: .doPrivileged(new PrivilegedAction() {
0544: public Object run() {
0545: return new DeltaSessionFacade(fsession);
0546: }
0547: });
0548: } else {
0549: facade = new DeltaSessionFacade(this );
0550: }
0551: }
0552: return (facade);
0553:
0554: }
0555:
0556: /**
0557: * Return the <code>isValid</code> flag for this session.
0558: */
0559: public boolean isValid() {
0560:
0561: if (this .expiring) {
0562: return true;
0563: }
0564:
0565: if (!this .isValid) {
0566: return false;
0567: }
0568:
0569: if (accessCount > 0) {
0570: return true;
0571: }
0572:
0573: if (maxInactiveInterval >= 0) {
0574: long timeNow = System.currentTimeMillis();
0575: int timeIdle = (int) ((timeNow - lastAccessedTime) / 1000L);
0576: if ((timeIdle >= maxInactiveInterval)
0577: && (isPrimarySession())) {
0578: expire(true);
0579: } else if (timeIdle >= (2 * maxInactiveInterval)) {
0580: //if the session has been idle twice as long as allowed,
0581: //the primary session has probably crashed, and no other
0582: //requests are coming in. that is why we do this. otherwise
0583: //we would have a memory leak
0584: expire(true, false);
0585: }
0586: }
0587:
0588: return (this .isValid);
0589: }
0590:
0591: /**
0592: * Set the <code>isValid</code> flag for this session.
0593: *
0594: * @param isValid The new value for the <code>isValid</code> flag
0595: */
0596: public void setValid(boolean isValid) {
0597:
0598: this .isValid = isValid;
0599: }
0600:
0601: // ------------------------------------------------- Session Public Methods
0602:
0603: /**
0604: * Update the accessed time information for this session. This method
0605: * should be called by the context when a request comes in for a particular
0606: * session, even if the application does not reference it.
0607: */
0608: public void access() {
0609:
0610: this .lastAccessedTime = this .this AccessedTime;
0611: this .this AccessedTime = System.currentTimeMillis();
0612:
0613: evaluateIfValid();
0614:
0615: accessCount++;
0616: }
0617:
0618: public void endAccess() {
0619: isNew = false;
0620: accessCount--;
0621: }
0622:
0623: /**
0624: * Add a session event listener to this component.
0625: */
0626: public void addSessionListener(SessionListener listener) {
0627:
0628: synchronized (listeners) {
0629: listeners.add(listener);
0630: }
0631:
0632: }
0633:
0634: /**
0635: * Perform the internal processing required to invalidate this session,
0636: * without triggering an exception if the session has already expired.
0637: */
0638: public void expire() {
0639:
0640: expire(true);
0641:
0642: }
0643:
0644: /**
0645: * Perform the internal processing required to invalidate this session,
0646: * without triggering an exception if the session has already expired.
0647: *
0648: * @param notify Should we notify listeners about the demise of
0649: * this session?
0650: */
0651: public void expire(boolean notify) {
0652: expire(notify, true);
0653: }
0654:
0655: public void expire(boolean notify, boolean notifyCluster) {
0656:
0657: // Mark this session as "being expired" if needed
0658: if (expiring)
0659: return;
0660: String expiredId = getId();
0661:
0662: synchronized (this ) {
0663:
0664: if (manager == null)
0665: return;
0666:
0667: expiring = true;
0668:
0669: // Notify interested application event listeners
0670: // FIXME - Assumes we call listeners in reverse order
0671: Context context = (Context) manager.getContainer();
0672: //fix for standalone manager without container
0673: if (context != null) {
0674: Object listeners[] = context
0675: .getApplicationLifecycleListeners();
0676: if (notify && (listeners != null)) {
0677: HttpSessionEvent event = new HttpSessionEvent(
0678: getSession());
0679: for (int i = 0; i < listeners.length; i++) {
0680: int j = (listeners.length - 1) - i;
0681: if (!(listeners[j] instanceof HttpSessionListener))
0682: continue;
0683: HttpSessionListener listener = (HttpSessionListener) listeners[j];
0684: try {
0685: fireContainerEvent(context,
0686: "beforeSessionDestroyed", listener);
0687: listener.sessionDestroyed(event);
0688: fireContainerEvent(context,
0689: "afterSessionDestroyed", listener);
0690: } catch (Throwable t) {
0691: try {
0692: fireContainerEvent(context,
0693: "afterSessionDestroyed",
0694: listener);
0695: } catch (Exception e) {
0696: ;
0697: }
0698: // FIXME - should we do anything besides log these?
0699: log
0700: .error(
0701: sm
0702: .getString("standardSession.sessionEvent"),
0703: t);
0704: }
0705: }
0706: }
0707: }//end if
0708: //end fix
0709: accessCount = 0;
0710: setValid(false);
0711:
0712: // Remove this session from our manager's active sessions
0713: if (manager != null)
0714: manager.remove(this );
0715:
0716: // Notify interested session event listeners
0717: if (notify) {
0718: fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
0719: }
0720:
0721: // We have completed expire of this session
0722: expiring = false;
0723:
0724: // Unbind any objects associated with this session
0725: String keys[] = keys();
0726: for (int i = 0; i < keys.length; i++)
0727: removeAttributeInternal(keys[i], notify, false);
0728:
0729: if (notifyCluster) {
0730: log.debug("Notifying cluster of expiration primary="
0731: + isPrimarySession() + " id=" + expiredId);
0732: ((DeltaManager) manager).sessionExpired(expiredId);
0733: }
0734:
0735: }
0736:
0737: }
0738:
0739: /**
0740: * Return the object bound with the specified name to the internal notes
0741: * for this session, or <code>null</code> if no such binding exists.
0742: *
0743: * @param name Name of the note to be returned
0744: */
0745: public Object getNote(String name) {
0746:
0747: synchronized (notes) {
0748: return (notes.get(name));
0749: }
0750:
0751: }
0752:
0753: /**
0754: * Return an Iterator containing the String names of all notes bindings
0755: * that exist for this session.
0756: */
0757: public Iterator getNoteNames() {
0758:
0759: synchronized (notes) {
0760: return (notes.keySet().iterator());
0761: }
0762:
0763: }
0764:
0765: /**
0766: * Release all object references, and initialize instance variables, in
0767: * preparation for reuse of this object.
0768: */
0769: public void recycle() {
0770:
0771: // Reset the instance variables associated with this Session
0772: attributes.clear();
0773: setAuthType(null);
0774: creationTime = 0L;
0775: expiring = false;
0776: id = null;
0777: lastAccessedTime = 0L;
0778: maxInactiveInterval = -1;
0779: accessCount = 0;
0780: notes.clear();
0781: setPrincipal(null);
0782: isNew = false;
0783: isValid = false;
0784: manager = null;
0785: deltaRequest.clear();
0786:
0787: }
0788:
0789: /**
0790: * Remove any object bound to the specified name in the internal notes
0791: * for this session.
0792: *
0793: * @param name Name of the note to be removed
0794: */
0795: public void removeNote(String name) {
0796:
0797: synchronized (notes) {
0798: notes.remove(name);
0799: }
0800:
0801: }
0802:
0803: /**
0804: * Remove a session event listener from this component.
0805: */
0806: public void removeSessionListener(SessionListener listener) {
0807:
0808: synchronized (listeners) {
0809: listeners.remove(listener);
0810: }
0811:
0812: }
0813:
0814: /**
0815: * Bind an object to a specified name in the internal notes associated
0816: * with this session, replacing any existing binding for this name.
0817: *
0818: * @param name Name to which the object should be bound
0819: * @param value Object to be bound to the specified name
0820: */
0821: public void setNote(String name, Object value) {
0822:
0823: synchronized (notes) {
0824: notes.put(name, value);
0825: }
0826:
0827: }
0828:
0829: /**
0830: * Return a string representation of this object.
0831: */
0832: public String toString() {
0833:
0834: StringBuffer sb = new StringBuffer();
0835: sb.append("StandardSession[");
0836: sb.append(id);
0837: sb.append("]");
0838: return (sb.toString());
0839:
0840: }
0841:
0842: // ------------------------------------------------ Session Package Methods
0843:
0844: /**
0845: * Read a serialized version of the contents of this session object from
0846: * the specified object input stream, without requiring that the
0847: * StandardSession itself have been serialized.
0848: *
0849: * @param stream The object input stream to read from
0850: *
0851: * @exception ClassNotFoundException if an unknown class is specified
0852: * @exception IOException if an input/output error occurs
0853: */
0854: public void readObjectData(ObjectInputStream stream)
0855: throws ClassNotFoundException, IOException {
0856:
0857: readObject(stream);
0858:
0859: }
0860:
0861: /**
0862: * Write a serialized version of the contents of this session object to
0863: * the specified object output stream, without requiring that the
0864: * StandardSession itself have been serialized.
0865: *
0866: * @param stream The object output stream to write to
0867: *
0868: * @exception IOException if an input/output error occurs
0869: */
0870: public void writeObjectData(ObjectOutputStream stream)
0871: throws IOException {
0872:
0873: writeObject(stream);
0874:
0875: }
0876:
0877: public void resetDeltaRequest() {
0878: if (deltaRequest == null) {
0879: deltaRequest = new DeltaRequest(getId(), false);
0880: } else {
0881: deltaRequest.reset();
0882: deltaRequest.setSessionId(getId());
0883: }
0884: }
0885:
0886: public DeltaRequest getDeltaRequest() {
0887: if (deltaRequest == null)
0888: resetDeltaRequest();
0889: return deltaRequest;
0890: }
0891:
0892: // ------------------------------------------------- HttpSession Properties
0893:
0894: /**
0895: * Return the time when this session was created, in milliseconds since
0896: * midnight, January 1, 1970 GMT.
0897: *
0898: * @exception IllegalStateException if this method is called on an
0899: * invalidated session
0900: */
0901: public long getCreationTime() {
0902:
0903: if (!expiring && !isValid)
0904: throw new IllegalStateException(sm
0905: .getString("standardSession.getCreationTime.ise"));
0906:
0907: return (this .creationTime);
0908:
0909: }
0910:
0911: /**
0912: * Return the ServletContext to which this session belongs.
0913: */
0914: public ServletContext getServletContext() {
0915:
0916: if (manager == null)
0917: return (null);
0918: Context context = (Context) manager.getContainer();
0919: if (context == null)
0920: return (null);
0921: else
0922: return (context.getServletContext());
0923:
0924: }
0925:
0926: /**
0927: * Return the session context with which this session is associated.
0928: *
0929: * @deprecated As of Version 2.1, this method is deprecated and has no
0930: * replacement. It will be removed in a future version of the
0931: * Java Servlet API.
0932: */
0933: public HttpSessionContext getSessionContext() {
0934:
0935: if (sessionContext == null)
0936: sessionContext = new StandardSessionContext();
0937: return (sessionContext);
0938:
0939: }
0940:
0941: // ----------------------------------------------HttpSession Public Methods
0942:
0943: /**
0944: * Return the object bound with the specified name in this session, or
0945: * <code>null</code> if no object is bound with that name.
0946: *
0947: * @param name Name of the attribute to be returned
0948: *
0949: * @exception IllegalStateException if this method is called on an
0950: * invalidated session
0951: */
0952: public Object getAttribute(String name) {
0953:
0954: if (!isValid())
0955: throw new IllegalStateException(sm
0956: .getString("standardSession.getAttribute.ise"));
0957:
0958: synchronized (attributes) {
0959: return (attributes.get(name));
0960: }
0961:
0962: }
0963:
0964: /**
0965: * Return an <code>Enumeration</code> of <code>String</code> objects
0966: * containing the names of the objects bound to this session.
0967: *
0968: * @exception IllegalStateException if this method is called on an
0969: * invalidated session
0970: */
0971: public Enumeration getAttributeNames() {
0972:
0973: if (!isValid())
0974: throw new IllegalStateException(sm
0975: .getString("standardSession.getAttributeNames.ise"));
0976:
0977: synchronized (attributes) {
0978: return (new Enumerator(attributes.keySet(), true));
0979: }
0980:
0981: }
0982:
0983: /**
0984: * Return the object bound with the specified name in this session, or
0985: * <code>null</code> if no object is bound with that name.
0986: *
0987: * @param name Name of the value to be returned
0988: *
0989: * @exception IllegalStateException if this method is called on an
0990: * invalidated session
0991: *
0992: * @deprecated As of Version 2.2, this method is replaced by
0993: * <code>getAttribute()</code>
0994: */
0995: public Object getValue(String name) {
0996:
0997: return (getAttribute(name));
0998:
0999: }
1000:
1001: /**
1002: * Return the set of names of objects bound to this session. If there
1003: * are no such objects, a zero-length array is returned.
1004: *
1005: * @exception IllegalStateException if this method is called on an
1006: * invalidated session
1007: *
1008: * @deprecated As of Version 2.2, this method is replaced by
1009: * <code>getAttributeNames()</code>
1010: */
1011: public String[] getValueNames() {
1012:
1013: if (!isValid())
1014: throw new IllegalStateException(sm
1015: .getString("standardSession.getValueNames.ise"));
1016:
1017: return (keys());
1018:
1019: }
1020:
1021: /**
1022: * Invalidates this session and unbinds any objects bound to it.
1023: *
1024: * @exception IllegalStateException if this method is called on
1025: * an invalidated session
1026: */
1027: public void invalidate() {
1028:
1029: if (!isValid())
1030: throw new IllegalStateException(sm
1031: .getString("standardSession.invalidate.ise"));
1032:
1033: // Cause this session to expire
1034: expire();
1035:
1036: }
1037:
1038: /**
1039: * Return <code>true</code> if the client does not yet know about the
1040: * session, or if the client chooses not to join the session. For
1041: * example, if the server used only cookie-based sessions, and the client
1042: * has disabled the use of cookies, then a session would be new on each
1043: * request.
1044: *
1045: * @exception IllegalStateException if this method is called on an
1046: * invalidated session
1047: */
1048: public boolean isNew() {
1049:
1050: if (!isValid())
1051: throw new IllegalStateException(sm
1052: .getString("standardSession.isNew.ise"));
1053:
1054: return (this .isNew);
1055:
1056: }
1057:
1058: /**
1059: * Bind an object to this session, using the specified name. If an object
1060: * of the same name is already bound to this session, the object is
1061: * replaced.
1062: * <p>
1063: * After this method executes, and if the object implements
1064: * <code>HttpSessionBindingListener</code>, the container calls
1065: * <code>valueBound()</code> on the object.
1066: *
1067: * @param name Name to which the object is bound, cannot be null
1068: * @param value Object to be bound, cannot be null
1069: *
1070: * @exception IllegalStateException if this method is called on an
1071: * invalidated session
1072: *
1073: * @deprecated As of Version 2.2, this method is replaced by
1074: * <code>setAttribute()</code>
1075: */
1076: public void putValue(String name, Object value) {
1077:
1078: setAttribute(name, value);
1079:
1080: }
1081:
1082: /**
1083: * Remove the object bound with the specified name from this session. If
1084: * the session does not have an object bound with this name, this method
1085: * does nothing.
1086: * <p>
1087: * After this method executes, and if the object implements
1088: * <code>HttpSessionBindingListener</code>, the container calls
1089: * <code>valueUnbound()</code> on the object.
1090: *
1091: * @param name Name of the object to remove from this session.
1092: *
1093: * @exception IllegalStateException if this method is called on an
1094: * invalidated session
1095: */
1096: public void removeAttribute(String name) {
1097:
1098: removeAttribute(name, true);
1099:
1100: }
1101:
1102: /**
1103: * Remove the object bound with the specified name from this session. If
1104: * the session does not have an object bound with this name, this method
1105: * does nothing.
1106: * <p>
1107: * After this method executes, and if the object implements
1108: * <code>HttpSessionBindingListener</code>, the container calls
1109: * <code>valueUnbound()</code> on the object.
1110: *
1111: * @param name Name of the object to remove from this session.
1112: * @param notify Should we notify interested listeners that this
1113: * attribute is being removed?
1114: *
1115: * @exception IllegalStateException if this method is called on an
1116: * invalidated session
1117: */
1118: public void removeAttribute(String name, boolean notify) {
1119: removeAttribute(name, notify, true);
1120: }
1121:
1122: public void removeAttribute(String name, boolean notify,
1123: boolean addDeltaRequest) {
1124:
1125: // Validate our current state
1126: if (!isValid())
1127: throw new IllegalStateException(sm
1128: .getString("standardSession.removeAttribute.ise"));
1129: removeAttributeInternal(name, notify, addDeltaRequest);
1130: }
1131:
1132: /**
1133: * Remove the object bound with the specified name from this session. If
1134: * the session does not have an object bound with this name, this method
1135: * does nothing.
1136: * <p>
1137: * After this method executes, and if the object implements
1138: * <code>HttpSessionBindingListener</code>, the container calls
1139: * <code>valueUnbound()</code> on the object.
1140: *
1141: * @param name Name of the object to remove from this session.
1142: *
1143: * @exception IllegalStateException if this method is called on an
1144: * invalidated session
1145: *
1146: * @deprecated As of Version 2.2, this method is replaced by
1147: * <code>removeAttribute()</code>
1148: */
1149: public void removeValue(String name) {
1150:
1151: removeAttribute(name);
1152:
1153: }
1154:
1155: /**
1156: * Bind an object to this session, using the specified name. If an object
1157: * of the same name is already bound to this session, the object is
1158: * replaced.
1159: * <p>
1160: * After this method executes, and if the object implements
1161: * <code>HttpSessionBindingListener</code>, the container calls
1162: * <code>valueBound()</code> on the object.
1163: *
1164: * @param name Name to which the object is bound, cannot be null
1165: * @param value Object to be bound, cannot be null
1166: *
1167: * @exception IllegalArgumentException if an attempt is made to add a
1168: * non-serializable object in an environment marked distributable.
1169: * @exception IllegalStateException if this method is called on an
1170: * invalidated session
1171: */
1172: public void setAttribute(String name, Object value) {
1173: setAttribute(name, value, true);
1174: }
1175:
1176: public void setAttribute(String name, Object value,
1177: boolean addDeltaRequest) {
1178:
1179: // Name cannot be null
1180: if (name == null)
1181: throw new IllegalArgumentException(sm
1182: .getString("standardSession.setAttribute.namenull"));
1183:
1184: // Null value is the same as removeAttribute()
1185: if (value == null) {
1186: removeAttribute(name);
1187: return;
1188: }
1189:
1190: if (!(value instanceof java.io.Serializable)) {
1191: throw new IllegalArgumentException("Attribute [" + name
1192: + "] is not serializable");
1193: }
1194:
1195: if (addDeltaRequest && (deltaRequest != null))
1196: deltaRequest.setAttribute(name, value);
1197:
1198: // Validate our current state
1199: if (!isValid())
1200: throw new IllegalStateException(sm
1201: .getString("standardSession.setAttribute.ise"));
1202: if ((manager != null) && manager.getDistributable()
1203: && !(value instanceof Serializable))
1204: throw new IllegalArgumentException(sm
1205: .getString("standardSession.setAttribute.iae"));
1206:
1207: // Construct an event with the new value
1208: HttpSessionBindingEvent event = null;
1209:
1210: // Call the valueBound() method if necessary
1211: if (value instanceof HttpSessionBindingListener) {
1212: event = new HttpSessionBindingEvent(getSession(), name,
1213: value);
1214: try {
1215: ((HttpSessionBindingListener) value).valueBound(event);
1216: } catch (Exception x) {
1217: log.error(
1218: "Session binding listener throw an exception",
1219: x);
1220: }
1221: }
1222:
1223: // Replace or add this attribute
1224: Object unbound = attributes.put(name, value);
1225:
1226: // Call the valueUnbound() method if necessary
1227: if ((unbound != null)
1228: && (unbound instanceof HttpSessionBindingListener)) {
1229: try {
1230: ((HttpSessionBindingListener) unbound)
1231: .valueUnbound(new HttpSessionBindingEvent(
1232: (HttpSession) getSession(), name));
1233: } catch (Exception x) {
1234: log.error(
1235: "Session binding listener throw an exception",
1236: x);
1237: }
1238:
1239: }
1240:
1241: // Notify interested application event listeners
1242: Context context = (Context) manager.getContainer();
1243: //fix for standalone manager without container
1244: if (context != null) {
1245: Object listeners[] = context.getApplicationEventListeners();
1246: if (listeners == null)
1247: return;
1248: for (int i = 0; i < listeners.length; i++) {
1249: if (!(listeners[i] instanceof HttpSessionAttributeListener))
1250: continue;
1251: HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i];
1252: try {
1253: if (unbound != null) {
1254: fireContainerEvent(context,
1255: "beforeSessionAttributeReplaced",
1256: listener);
1257: if (event == null) {
1258: event = new HttpSessionBindingEvent(
1259: getSession(), name, unbound);
1260: }
1261: listener.attributeReplaced(event);
1262: fireContainerEvent(context,
1263: "afterSessionAttributeReplaced",
1264: listener);
1265: } else {
1266: fireContainerEvent(context,
1267: "beforeSessionAttributeAdded", listener);
1268: if (event == null) {
1269: event = new HttpSessionBindingEvent(
1270: getSession(), name, unbound);
1271: }
1272: listener.attributeAdded(event);
1273: fireContainerEvent(context,
1274: "afterSessionAttributeAdded", listener);
1275: }
1276: } catch (Throwable t) {
1277: try {
1278: if (unbound != null) {
1279: fireContainerEvent(context,
1280: "afterSessionAttributeReplaced",
1281: listener);
1282: } else {
1283: fireContainerEvent(context,
1284: "afterSessionAttributeAdded",
1285: listener);
1286: }
1287: } catch (Exception e) {
1288: ;
1289: }
1290: // FIXME - should we do anything besides log these?
1291: log
1292: .error(
1293: sm
1294: .getString("standardSession.attributeEvent"),
1295: t);
1296: }
1297: } //for
1298: }//end if
1299: //end fix
1300:
1301: }
1302:
1303: // -------------------------------------------- HttpSession Private Methods
1304:
1305: /**
1306: * Read a serialized version of this session object from the specified
1307: * object input stream.
1308: * <p>
1309: * <b>IMPLEMENTATION NOTE</b>: The reference to the owning Manager
1310: * is not restored by this method, and must be set explicitly.
1311: *
1312: * @param stream The input stream to read from
1313: *
1314: * @exception ClassNotFoundException if an unknown class is specified
1315: * @exception IOException if an input/output error occurs
1316: */
1317: private void readObject(ObjectInputStream stream)
1318: throws ClassNotFoundException, IOException {
1319:
1320: // Deserialize the scalar instance variables (except Manager)
1321: authType = null; // Transient only
1322: creationTime = ((Long) stream.readObject()).longValue();
1323: lastAccessedTime = ((Long) stream.readObject()).longValue();
1324: maxInactiveInterval = ((Integer) stream.readObject())
1325: .intValue();
1326: isNew = ((Boolean) stream.readObject()).booleanValue();
1327: isValid = ((Boolean) stream.readObject()).booleanValue();
1328: this AccessedTime = ((Long) stream.readObject()).longValue();
1329: boolean hasPrincipal = stream.readBoolean();
1330: principal = null;
1331: if (hasPrincipal) {
1332: principal = SerializablePrincipal.readPrincipal(stream,
1333: getManager().getContainer().getRealm());
1334: }
1335:
1336: // setId((String) stream.readObject());
1337: id = (String) stream.readObject();
1338: if (log.isDebugEnabled())
1339: log.debug("readObject() loading session " + id);
1340:
1341: // Deserialize the attribute count and attribute values
1342: if (attributes == null)
1343: attributes = new HashMap();
1344: int n = ((Integer) stream.readObject()).intValue();
1345: boolean isValidSave = isValid;
1346: isValid = true;
1347: for (int i = 0; i < n; i++) {
1348: String name = (String) stream.readObject();
1349: Object value = (Object) stream.readObject();
1350: if ((value instanceof String)
1351: && (value.equals(NOT_SERIALIZED)))
1352: continue;
1353: // if (log.isDebugEnabled())
1354: // log.debug(" loading attribute '" + name +
1355: // "' with value '" + value + "'");
1356: synchronized (attributes) {
1357: attributes.put(name, value);
1358: }
1359: }
1360: isValid = isValidSave;
1361: }
1362:
1363: /**
1364: * Write a serialized version of this session object to the specified
1365: * object output stream.
1366: * <p>
1367: * <b>IMPLEMENTATION NOTE</b>: The owning Manager will not be stored
1368: * in the serialized representation of this Session. After calling
1369: * <code>readObject()</code>, you must set the associated Manager
1370: * explicitly.
1371: * <p>
1372: * <b>IMPLEMENTATION NOTE</b>: Any attribute that is not Serializable
1373: * will be unbound from the session, with appropriate actions if it
1374: * implements HttpSessionBindingListener. If you do not want any such
1375: * attributes, be sure the <code>distributable</code> property of the
1376: * associated Manager is set to <code>true</code>.
1377: *
1378: * @param stream The output stream to write to
1379: *
1380: * @exception IOException if an input/output error occurs
1381: */
1382: private void writeObject(ObjectOutputStream stream)
1383: throws IOException {
1384:
1385: // Write the scalar instance variables (except Manager)
1386: stream.writeObject(new Long(creationTime));
1387: stream.writeObject(new Long(lastAccessedTime));
1388: stream.writeObject(new Integer(maxInactiveInterval));
1389: stream.writeObject(new Boolean(isNew));
1390: stream.writeObject(new Boolean(isValid));
1391: stream.writeObject(new Long(this AccessedTime));
1392: stream.writeBoolean(getPrincipal() != null);
1393: if (getPrincipal() != null) {
1394: SerializablePrincipal.writePrincipal(
1395: (GenericPrincipal) principal, stream);
1396: }
1397:
1398: stream.writeObject(id);
1399: if (log.isDebugEnabled())
1400: log.debug("writeObject() storing session " + id);
1401:
1402: // Accumulate the names of serializable and non-serializable attributes
1403: String keys[] = keys();
1404: ArrayList saveNames = new ArrayList();
1405: ArrayList saveValues = new ArrayList();
1406: for (int i = 0; i < keys.length; i++) {
1407: Object value = null;
1408: synchronized (attributes) {
1409: value = attributes.get(keys[i]);
1410: }
1411: if (value == null)
1412: continue;
1413: else if (value instanceof Serializable) {
1414: saveNames.add(keys[i]);
1415: saveValues.add(value);
1416: }
1417: }
1418:
1419: // Serialize the attribute count and the Serializable attributes
1420: int n = saveNames.size();
1421: stream.writeObject(new Integer(n));
1422: for (int i = 0; i < n; i++) {
1423: stream.writeObject((String) saveNames.get(i));
1424: try {
1425: stream.writeObject(saveValues.get(i));
1426: // if (log.isDebugEnabled())
1427: // log.debug(" storing attribute '" + saveNames.get(i) +
1428: // "' with value '" + saveValues.get(i) + "'");
1429: } catch (NotSerializableException e) {
1430: log.error(sm.getString(
1431: "standardSession.notSerializable", saveNames
1432: .get(i), id), e);
1433: stream.writeObject(NOT_SERIALIZED);
1434: log.error(" storing attribute '" + saveNames.get(i)
1435: + "' with value NOT_SERIALIZED");
1436: }
1437: }
1438:
1439: }
1440:
1441: private void evaluateIfValid() {
1442: /*
1443: * If this session has expired or is in the process of expiring or
1444: * will never expire, return
1445: */
1446: if (!this .isValid || expiring || maxInactiveInterval < 0)
1447: return;
1448:
1449: isValid();
1450:
1451: }
1452:
1453: // -------------------------------------------------------- Private Methods
1454:
1455: /**
1456: * Fire container events if the Context implementation is the
1457: * <code>org.apache.catalina.core.StandardContext</code>.
1458: *
1459: * @param context Context for which to fire events
1460: * @param type Event type
1461: * @param data Event data
1462: *
1463: * @exception Exception occurred during event firing
1464: */
1465: private void fireContainerEvent(Context context, String type,
1466: Object data) throws Exception {
1467:
1468: if (!"org.apache.catalina.core.StandardContext".equals(context
1469: .getClass().getName())) {
1470: return; // Container events are not supported
1471: }
1472: // NOTE: Race condition is harmless, so do not synchronize
1473: if (containerEventMethod == null) {
1474: containerEventMethod = context.getClass().getMethod(
1475: "fireContainerEvent", containerEventTypes);
1476: }
1477: Object containerEventParams[] = new Object[2];
1478: containerEventParams[0] = type;
1479: containerEventParams[1] = data;
1480: containerEventMethod.invoke(context, containerEventParams);
1481:
1482: }
1483:
1484: /**
1485: * Notify all session event listeners that a particular event has
1486: * occurred for this Session. The default implementation performs
1487: * this notification synchronously using the calling thread.
1488: *
1489: * @param type Event type
1490: * @param data Event data
1491: */
1492: public void fireSessionEvent(String type, Object data) {
1493: if (listeners.size() < 1)
1494: return;
1495: SessionEvent event = new SessionEvent(this , type, data);
1496: SessionListener list[] = new SessionListener[0];
1497: synchronized (listeners) {
1498: list = (SessionListener[]) listeners.toArray(list);
1499: }
1500:
1501: for (int i = 0; i < list.length; i++) {
1502: ((SessionListener) list[i]).sessionEvent(event);
1503: }
1504:
1505: }
1506:
1507: /**
1508: * Return the names of all currently defined session attributes
1509: * as an array of Strings. If there are no defined attributes, a
1510: * zero-length array is returned.
1511: */
1512: protected String[] keys() {
1513:
1514: String results[] = new String[0];
1515: synchronized (attributes) {
1516: return ((String[]) attributes.keySet().toArray(results));
1517: }
1518:
1519: }
1520:
1521: /**
1522: * Return the value of an attribute without a check for validity.
1523: */
1524: protected Object getAttributeInternal(String name) {
1525:
1526: synchronized (attributes) {
1527: return (attributes.get(name));
1528: }
1529:
1530: }
1531:
1532: protected void removeAttributeInternal(String name, boolean notify,
1533: boolean addDeltaRequest) {
1534:
1535: // Remove this attribute from our collection
1536: Object value = attributes.remove(name);
1537: if (value == null)
1538: return;
1539:
1540: if (addDeltaRequest && (deltaRequest != null))
1541: deltaRequest.removeAttribute(name);
1542:
1543: // Do we need to do valueUnbound() and attributeRemoved() notification?
1544: if (!notify) {
1545: return;
1546: }
1547:
1548: // Call the valueUnbound() method if necessary
1549: HttpSessionBindingEvent event = new HttpSessionBindingEvent(
1550: (HttpSession) getSession(), name, value);
1551: if ((value != null)
1552: && (value instanceof HttpSessionBindingListener))
1553: try {
1554: ((HttpSessionBindingListener) value)
1555: .valueUnbound(event);
1556: } catch (Exception x) {
1557: log.error(
1558: "Session binding listener throw an exception",
1559: x);
1560: }
1561:
1562: // Notify interested application event listeners
1563: Context context = (Context) manager.getContainer();
1564: //fix for standalone manager without container
1565: if (context != null) {
1566: Object listeners[] = context.getApplicationEventListeners();
1567: if (listeners == null)
1568: return;
1569: for (int i = 0; i < listeners.length; i++) {
1570: if (!(listeners[i] instanceof HttpSessionAttributeListener))
1571: continue;
1572: HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i];
1573: try {
1574: fireContainerEvent(context,
1575: "beforeSessionAttributeRemoved", listener);
1576: listener.attributeRemoved(event);
1577: fireContainerEvent(context,
1578: "afterSessionAttributeRemoved", listener);
1579: } catch (Throwable t) {
1580: try {
1581: fireContainerEvent(context,
1582: "afterSessionAttributeRemoved",
1583: listener);
1584: } catch (Exception e) {
1585: ;
1586: }
1587: // FIXME - should we do anything besides log these?
1588: log
1589: .error(
1590: sm
1591: .getString("standardSession.attributeEvent"),
1592: t);
1593: }
1594: } //for
1595: }//end if
1596: //end fix
1597:
1598: }
1599:
1600: protected long getLastTimeReplicated() {
1601: return lastTimeReplicated;
1602: }
1603:
1604: protected void setLastTimeReplicated(long lastTimeReplicated) {
1605: this .lastTimeReplicated = lastTimeReplicated;
1606: }
1607:
1608: protected void setAccessCount(int accessCount) {
1609: this .accessCount = accessCount;
1610: }
1611:
1612: protected int getAccessCount() {
1613: return accessCount;
1614: }
1615:
1616: }
1617:
1618: // -------------------------------------------------------------- Private Class
1619:
1620: /**
1621: * This class is a dummy implementation of the <code>HttpSessionContext</code>
1622: * interface, to conform to the requirement that such an object be returned
1623: * when <code>HttpSession.getSessionContext()</code> is called.
1624: *
1625: * @author Craig R. McClanahan
1626: *
1627: * @deprecated As of Java Servlet API 2.1 with no replacement. The
1628: * interface will be removed in a future version of this API.
1629: */
1630:
1631: final class StandardSessionContext implements HttpSessionContext {
1632:
1633: private HashMap dummy = new HashMap();
1634:
1635: /**
1636: * Return the session identifiers of all sessions defined
1637: * within this context.
1638: *
1639: * @deprecated As of Java Servlet API 2.1 with no replacement.
1640: * This method must return an empty <code>Enumeration</code>
1641: * and will be removed in a future version of the API.
1642: */
1643: public Enumeration getIds() {
1644:
1645: return (new Enumerator(dummy));
1646:
1647: }
1648:
1649: /**
1650: * Return the <code>HttpSession</code> associated with the
1651: * specified session identifier.
1652: *
1653: * @param id Session identifier for which to look up a session
1654: *
1655: * @deprecated As of Java Servlet API 2.1 with no replacement.
1656: * This method must return null and will be removed in a
1657: * future version of the API.
1658: */
1659: public HttpSession getSession(String id) {
1660:
1661: return (null);
1662:
1663: }
1664:
1665: }
|