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