001: // ========================================================================
002: // $Id: AbstractSessionManager.java,v 1.3 2005-08-30 08:10:34 draganr Exp $
003: // Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
004: // ------------------------------------------------------------------------
005: // Licensed under the Apache License, Version 2.0 (the "License");
006: // you may not use this file except in compliance with the License.
007: // You may obtain a copy of the License at
008: // http://www.apache.org/licenses/LICENSE-2.0
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014: // ========================================================================
015:
016: package org.mortbay.jetty.servlet;
017:
018: import java.util.ArrayList;
019: import java.util.Collections;
020: import java.util.ConcurrentModificationException;
021: import java.util.Enumeration;
022: import java.util.EventListener;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027: import java.util.Random;
028:
029: import javax.servlet.ServletContext;
030: import javax.servlet.http.Cookie;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpSession;
033: import javax.servlet.http.HttpSessionAttributeListener;
034: import javax.servlet.http.HttpSessionBindingEvent;
035: import javax.servlet.http.HttpSessionBindingListener;
036: import javax.servlet.http.HttpSessionContext;
037: import javax.servlet.http.HttpSessionEvent;
038: import javax.servlet.http.HttpSessionListener;
039:
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042: import org.mortbay.http.HttpOnlyCookie;
043: import org.mortbay.util.LazyList;
044: import org.mortbay.util.LogSupport;
045: import org.mortbay.util.MultiMap;
046:
047: /* ------------------------------------------------------------ */
048: /** An Abstract implementation of SessionManager.
049: * The partial implementation of SessionManager interface provides
050: * the majority of the handling required to implement a
051: * SessionManager. Concrete implementations of SessionManager based
052: * on AbstractSessionManager need only implement the newSession method
053: * to return a specialized version of the Session inner class that
054: * provides an attribute Map.
055: * <p>
056: * If the property
057: * org.mortbay.jetty.servlet.AbstractSessionManager.23Notifications is set to
058: * true, the 2.3 servlet spec notification style will be used.
059: * <p>
060: * @version $Id: AbstractSessionManager.java,v 1.3 2005-08-30 08:10:34 draganr Exp $
061: * @author Greg Wilkins (gregw)
062: */
063: public abstract class AbstractSessionManager implements SessionManager {
064: private static Log log = LogFactory
065: .getLog(AbstractSessionManager.class);
066:
067: /* ------------------------------------------------------------ */
068: public final static int __distantFuture = 60 * 60 * 24 * 7 * 52
069: * 20;
070: private final static String __NEW_SESSION_ID = "org.mortbay.jetty.newSessionId";
071:
072: /* ------------------------------------------------------------ */
073: /* global Map of ID to session */
074: protected static MultiMap __allSessions = new MultiMap();
075:
076: /* ------------------------------------------------------------ */
077: // Setting of max inactive interval for new sessions
078: // -1 means no timeout
079: private int _dftMaxIdleSecs = -1;
080: private int _scavengePeriodMs = 30000;
081: private String _workerName;
082: protected transient ArrayList _sessionListeners = new ArrayList();
083: protected transient ArrayList _sessionAttributeListeners = new ArrayList();
084: protected transient Map _sessions;
085: protected transient Random _random;
086: protected transient ServletHandler _handler;
087: protected int _minSessions = 0;
088: protected int _maxSessions = 0;
089: protected boolean _crossContextSessionIDs = false;
090: protected boolean _secureCookies = false;
091: protected boolean _httpOnly = false;
092: protected boolean _invalidateGlobal = true;
093:
094: private transient SessionScavenger _scavenger = null;
095:
096: /* ------------------------------------------------------------ */
097: public AbstractSessionManager() {
098: this (null);
099: }
100:
101: /* ------------------------------------------------------------ */
102: public AbstractSessionManager(Random random) {
103: _random = random;
104: }
105:
106: /* ------------------------------------------------------------ */
107: /**
108: * @return True if requested session ID are first considered for new
109: * @deprecated use getCrossContextSessionIDs
110: * session IDs
111: */
112: public boolean getUseRequestedId() {
113: return _crossContextSessionIDs;
114: }
115:
116: /* ------------------------------------------------------------ */
117: /** Set Use Requested ID.
118: * @deprectated use setCrossContextSessionIDs
119: * @param useRequestedId True if requested session ID are first considered for new
120: * session IDs
121: */
122: public void setUseRequestedId(boolean useRequestedId) {
123: _crossContextSessionIDs = useRequestedId;
124: }
125:
126: /* ------------------------------------------------------------ */
127: /**
128: * @return True if cross context session IDs are first considered for new
129: * session IDs
130: */
131: public boolean getCrossContextSessionIDs() {
132: return _crossContextSessionIDs;
133: }
134:
135: /* ------------------------------------------------------------ */
136: /** Set Cross Context sessions IDs
137: * This option activates a mode where a requested session ID can be used to create a
138: * new session. This facilitates the sharing of session cookies when cross context
139: * dispatches use sessions.
140: *
141: * @param useRequestedId True if cross context session ID are first considered for new
142: * session IDs
143: */
144: public void setCrossContextSessionIDs(boolean useRequestedId) {
145: _crossContextSessionIDs = useRequestedId;
146: }
147:
148: /* ------------------------------------------------------------ */
149: public void initialize(ServletHandler handler) {
150: _handler = handler;
151: }
152:
153: /* ------------------------------------------------------------ */
154: public Map getSessionMap() {
155: return Collections.unmodifiableMap(_sessions);
156: }
157:
158: /* ------------------------------------------------------------ */
159: public int getSessions() {
160: return _sessions.size();
161: }
162:
163: /* ------------------------------------------------------------ */
164: public int getMinSessions() {
165: return _minSessions;
166: }
167:
168: /* ------------------------------------------------------------ */
169: public int getMaxSessions() {
170: return _maxSessions;
171: }
172:
173: /* ------------------------------------------------------------ */
174: public void resetStats() {
175: _minSessions = _sessions.size();
176: _maxSessions = _sessions.size();
177: }
178:
179: /* ------------------------------------------------------------ */
180: /* new Session ID.
181: * If the request has a requestedSessionID which is unique, that is used.
182: * The session ID is created as a unique random long, represented as in a
183: * base between 30 and 36, selected by timestamp.
184: * If the request has a jvmRoute attribute, that is appended as a
185: * worker tag, else any worker tag set on the manager is appended.
186: * @param request
187: * @param created
188: * @return Session ID.
189: */
190: private String newSessionId(HttpServletRequest request, long created) {
191: synchronized (__allSessions) {
192: // A requested session ID can only be used if it is in the global map of
193: // ID but not in this contexts map. Ie it is an ID in use by another context
194: // in this server and thus we are doing a cross context dispatch.
195: if (_crossContextSessionIDs) {
196: String requested_id = (String) request
197: .getAttribute(__NEW_SESSION_ID);
198: if (requested_id == null)
199: requested_id = request.getRequestedSessionId();
200: if (requested_id != null && requested_id != null
201: && !__allSessions.containsKey(requested_id)
202: && !_sessions.containsKey(requested_id))
203: return requested_id;
204: }
205:
206: // pick a new unique ID!
207: String id = null;
208: while (id == null || id.length() == 0
209: || __allSessions.containsKey(id)) {
210: long r = _random.nextLong();
211: if (r < 0)
212: r = -r;
213: id = Long.toString(r, 30 + (int) (created % 7));
214: String worker = (String) request
215: .getAttribute("org.mortbay.http.ajp.JVMRoute");
216: if (worker != null)
217: id += "." + worker;
218: else if (_workerName != null)
219: id += "." + _workerName;
220: }
221: return id;
222: }
223: }
224:
225: /* ------------------------------------------------------------ */
226: public HttpSession getHttpSession(String id) {
227: synchronized (this ) {
228: return (HttpSession) _sessions.get(id);
229: }
230: }
231:
232: /* ------------------------------------------------------------ */
233: public HttpSession newHttpSession(HttpServletRequest request) {
234: Session session = newSession(request);
235: session.setMaxInactiveInterval(_dftMaxIdleSecs);
236: synchronized (__allSessions) {
237: synchronized (this ) {
238: _sessions.put(session.getId(), session);
239: __allSessions.add(session.getId(), session);
240: if (_sessions.size() > this ._maxSessions)
241: this ._maxSessions = _sessions.size();
242: }
243: }
244:
245: HttpSessionEvent event = new HttpSessionEvent(session);
246:
247: for (int i = 0; i < _sessionListeners.size(); i++)
248: ((HttpSessionListener) _sessionListeners.get(i))
249: .sessionCreated(event);
250:
251: if (getCrossContextSessionIDs())
252: request.setAttribute(__NEW_SESSION_ID, session.getId());
253: return session;
254: }
255:
256: /* ------------------------------------------------------------ */
257: public Cookie getSessionCookie(HttpSession session,
258: boolean requestIsSecure) {
259: if (_handler.isUsingCookies()) {
260: Cookie cookie = _handler.getSessionManager().getHttpOnly() ? new HttpOnlyCookie(
261: SessionManager.__SessionCookie, session.getId())
262: : new Cookie(SessionManager.__SessionCookie,
263: session.getId());
264: String domain = _handler.getServletContext()
265: .getInitParameter(SessionManager.__SessionDomain);
266: String maxAge = _handler.getServletContext()
267: .getInitParameter(SessionManager.__MaxAge);
268: String path = _handler.getServletContext()
269: .getInitParameter(SessionManager.__SessionPath);
270: if (path == null)
271: path = getCrossContextSessionIDs() ? "/" : _handler
272: .getHttpContext().getContextPath();
273: if (path == null || path.length() == 0)
274: path = "/";
275:
276: if (domain != null)
277: cookie.setDomain(domain);
278: if (maxAge != null)
279: cookie.setMaxAge(Integer.parseInt(maxAge));
280: else
281: cookie.setMaxAge(-1);
282:
283: cookie.setSecure(requestIsSecure && getSecureCookies());
284: cookie.setPath(path);
285:
286: return cookie;
287: }
288: return null;
289: }
290:
291: /* ------------------------------------------------------------ */
292: protected abstract Session newSession(HttpServletRequest request);
293:
294: /* ------------------------------------------------------------ */
295: /** Get the workname.
296: * If set, the workername is dot appended to the session ID
297: * and can be used to assist session affinity in a load balancer.
298: * @return String or null
299: */
300: public String getWorkerName() {
301: return _workerName;
302: }
303:
304: /* ------------------------------------------------------------ */
305: /** Set the workname.
306: * If set, the workername is dot appended to the session ID
307: * and can be used to assist session affinity in a load balancer.
308: * @param workerName
309: */
310: public void setWorkerName(String workerName) {
311: _workerName = workerName;
312: }
313:
314: /* ------------------------------------------------------------ */
315: /**
316: * @return seconds
317: */
318: public int getMaxInactiveInterval() {
319: return _dftMaxIdleSecs;
320: }
321:
322: /* ------------------------------------------------------------ */
323: /**
324: * @param seconds
325: */
326: public void setMaxInactiveInterval(int seconds) {
327: _dftMaxIdleSecs = seconds;
328: if (_dftMaxIdleSecs > 0
329: && _scavengePeriodMs > _dftMaxIdleSecs * 100)
330: setScavengePeriod((_dftMaxIdleSecs + 9) / 10);
331: }
332:
333: /* ------------------------------------------------------------ */
334: /**
335: * @return seconds
336: */
337: public int getScavengePeriod() {
338: return _scavengePeriodMs / 1000;
339: }
340:
341: /* ------------------------------------------------------------ */
342: /**
343: * @param seconds
344: */
345: public void setScavengePeriod(int seconds) {
346: if (seconds == 0)
347: seconds = 60;
348:
349: int old_period = _scavengePeriodMs;
350: int period = seconds * 1000;
351: if (period > 60000)
352: period = 60000;
353: if (period < 1000)
354: period = 1000;
355:
356: if (period != old_period) {
357: synchronized (this ) {
358: _scavengePeriodMs = period;
359: if (_scavenger != null)
360: _scavenger.interrupt();
361: }
362: }
363: }
364:
365: /* ------------------------------------------------------------ */
366: /**
367: * @return Returns the httpOnly.
368: */
369: public boolean getHttpOnly() {
370: return _httpOnly;
371: }
372:
373: /* ------------------------------------------------------------ */
374: /**
375: * @param httpOnly The httpOnly to set.
376: */
377: public void setHttpOnly(boolean httpOnly) {
378: _httpOnly = httpOnly;
379: }
380:
381: /* ------------------------------------------------------------ */
382: /**
383: * @return Returns the secureCookies.
384: */
385: public boolean getSecureCookies() {
386: return _secureCookies;
387: }
388:
389: /* ------------------------------------------------------------ */
390: /**
391: * @param secureCookies The secureCookies to set.
392: */
393: public void setSecureCookies(boolean secureCookies) {
394: _secureCookies = secureCookies;
395: }
396:
397: /* ------------------------------------------------------------ */
398: public boolean isInvalidateGlobal() {
399: return _invalidateGlobal;
400: }
401:
402: /* ------------------------------------------------------------ */
403: /**
404: * @param global True if session invalidation should be global.
405: * ie Sessions in other contexts with the same ID (linked by cross context dispatch
406: * or shared session cookie) are invalidated as a group.
407: */
408: public void setInvalidateGlobal(boolean global) {
409: _invalidateGlobal = global;
410: }
411:
412: /* ------------------------------------------------------------ */
413: public void addEventListener(EventListener listener)
414: throws IllegalArgumentException {
415:
416: if (listener instanceof HttpSessionAttributeListener)
417: _sessionAttributeListeners.add(listener);
418: if (listener instanceof HttpSessionListener)
419: _sessionListeners.add(listener);
420: }
421:
422: /* ------------------------------------------------------------ */
423: public void removeEventListener(EventListener listener) {
424: if (listener instanceof HttpSessionAttributeListener)
425: _sessionAttributeListeners.remove(listener);
426: if (listener instanceof HttpSessionListener)
427: _sessionListeners.remove(listener);
428: }
429:
430: /* ------------------------------------------------------------ */
431: public boolean isStarted() {
432: return _scavenger != null;
433: }
434:
435: /* ------------------------------------------------------------ */
436: public void start() throws Exception {
437: if (_random == null) {
438: log.debug("New random session seed");
439: _random = new Random();
440: } else if (log.isDebugEnabled())
441: log.debug("Initializing random session key: " + _random);
442: _random.nextLong();
443:
444: if (_sessions == null)
445: _sessions = new HashMap();
446:
447: // Start the session scavenger if we haven't already
448: if (_scavenger == null) {
449: _scavenger = new SessionScavenger();
450: _scavenger.start();
451: }
452: }
453:
454: /* ------------------------------------------------------------ */
455: public void stop() {
456: // Invalidate all sessions to cause unbind events
457: ArrayList sessions = new ArrayList(_sessions.values());
458: for (Iterator i = sessions.iterator(); i.hasNext();) {
459: Session session = (Session) i.next();
460: session.invalidate();
461: }
462: _sessions.clear();
463:
464: // stop the scavenger
465: SessionScavenger scavenger = _scavenger;
466: _scavenger = null;
467: if (scavenger != null)
468: scavenger.interrupt();
469: }
470:
471: /* -------------------------------------------------------------- */
472: /** Find sessions that have timed out and invalidate them.
473: * This runs in the SessionScavenger thread.
474: */
475: private void scavenge() {
476: Thread thread = Thread.currentThread();
477: ClassLoader old_loader = thread.getContextClassLoader();
478: try {
479: if (_handler == null)
480: return;
481:
482: ClassLoader loader = _handler.getClassLoader();
483: if (loader != null)
484: thread.setContextClassLoader(loader);
485:
486: long now = System.currentTimeMillis();
487:
488: // Since Hashtable enumeration is not safe over deletes,
489: // we build a list of stale sessions, then go back and invalidate them
490: Object stale = null;
491:
492: synchronized (AbstractSessionManager.this ) {
493: // For each session
494: for (Iterator i = _sessions.values().iterator(); i
495: .hasNext();) {
496: Session session = (Session) i.next();
497: long idleTime = session._maxIdleMs;
498: if (idleTime > 0
499: && session._accessed + idleTime < now) {
500: // Found a stale session, add it to the list
501: stale = LazyList.add(stale, session);
502: }
503: }
504: }
505:
506: // Remove the stale sessions
507: for (int i = LazyList.size(stale); i-- > 0;) {
508: // check it has not been accessed in the meantime
509: Session session = (Session) LazyList.get(stale, i);
510: long idleTime = session._maxIdleMs;
511: if (idleTime > 0
512: && session._accessed + idleTime < System
513: .currentTimeMillis()) {
514: session.invalidate();
515: int nbsess = this ._sessions.size();
516: if (nbsess < this ._minSessions)
517: this ._minSessions = nbsess;
518: }
519: }
520: } finally {
521: thread.setContextClassLoader(old_loader);
522: }
523: }
524:
525: /* ------------------------------------------------------------ */
526: /* ------------------------------------------------------------ */
527: /* -------------------------------------------------------------- */
528: /** SessionScavenger is a background thread that kills off old sessions */
529: class SessionScavenger extends Thread {
530: public void run() {
531: int period = -1;
532: try {
533: while (isStarted()) {
534: try {
535: if (period != _scavengePeriodMs) {
536: if (log.isDebugEnabled())
537: log.debug("Session scavenger period = "
538: + _scavengePeriodMs / 1000
539: + "s");
540: period = _scavengePeriodMs;
541: }
542: sleep(period > 1000 ? period : 1000);
543: AbstractSessionManager.this .scavenge();
544: } catch (InterruptedException ex) {
545: continue;
546: } catch (Error e) {
547: log.warn(LogSupport.EXCEPTION, e);
548: } catch (Exception e) {
549: log.warn(LogSupport.EXCEPTION, e);
550: }
551: }
552: } finally {
553: AbstractSessionManager.this ._scavenger = null;
554: log.debug("Session scavenger exited");
555: }
556: }
557:
558: SessionScavenger() {
559: super ("SessionScavenger");
560: setDaemon(true);
561: }
562:
563: } // SessionScavenger
564:
565: /* ------------------------------------------------------------ */
566: /* ------------------------------------------------------------ */
567: /* ------------------------------------------------------------ */
568: public abstract class Session implements SessionManager.Session {
569: Map _values;
570: boolean _invalid = false;
571: boolean _newSession = true;
572: long _created = System.currentTimeMillis();
573: long _accessed = _created;
574: long _maxIdleMs = _dftMaxIdleSecs * 1000;
575: String _id;
576:
577: /* ------------------------------------------------------------- */
578: protected Session(HttpServletRequest request) {
579: _id = newSessionId(request, _created);
580: if (_dftMaxIdleSecs >= 0)
581: _maxIdleMs = _dftMaxIdleSecs * 1000;
582: }
583:
584: /* ------------------------------------------------------------ */
585: protected abstract Map newAttributeMap();
586:
587: /* ------------------------------------------------------------ */
588: public void access() {
589: _newSession = false;
590: _accessed = System.currentTimeMillis();
591: }
592:
593: /* ------------------------------------------------------------ */
594: public boolean isValid() {
595: return !_invalid;
596: }
597:
598: /* ------------------------------------------------------------ */
599: public ServletContext getServletContext() {
600: return _handler.getServletContext();
601: }
602:
603: /* ------------------------------------------------------------- */
604: public String getId() throws IllegalStateException {
605: return _id;
606: }
607:
608: /* ------------------------------------------------------------- */
609: public long getCreationTime() throws IllegalStateException {
610: if (_invalid)
611: throw new IllegalStateException();
612: return _created;
613: }
614:
615: /* ------------------------------------------------------------- */
616: public long getLastAccessedTime() throws IllegalStateException {
617: if (_invalid)
618: throw new IllegalStateException();
619: return _accessed;
620: }
621:
622: /* ------------------------------------------------------------- */
623: public int getMaxInactiveInterval() {
624: if (_invalid)
625: throw new IllegalStateException();
626: return (int) (_maxIdleMs / 1000);
627: }
628:
629: /* ------------------------------------------------------------- */
630: /**
631: * @deprecated
632: */
633: public HttpSessionContext getSessionContext()
634: throws IllegalStateException {
635: if (_invalid)
636: throw new IllegalStateException();
637: return SessionContext.NULL_IMPL;
638: }
639:
640: /* ------------------------------------------------------------- */
641: public void setMaxInactiveInterval(int secs) {
642: _maxIdleMs = (long) secs * 1000;
643: if (_maxIdleMs > 0 && (_maxIdleMs / 10) < _scavengePeriodMs)
644: AbstractSessionManager.this
645: .setScavengePeriod((secs + 9) / 10);
646: }
647:
648: /* ------------------------------------------------------------- */
649: public void invalidate() throws IllegalStateException {
650: if (log.isDebugEnabled())
651: log.debug("Invalidate session " + getId() + " in "
652: + _handler.getHttpContext());
653: try {
654: // Notify listeners and unbind values
655: synchronized (this ) {
656: if (_invalid)
657: throw new IllegalStateException();
658:
659: if (_sessionListeners != null) {
660: HttpSessionEvent event = new HttpSessionEvent(
661: this );
662: for (int i = 0; i < _sessionListeners.size(); i++)
663: ((HttpSessionListener) _sessionListeners
664: .get(i)).sessionDestroyed(event);
665: }
666:
667: if (_values != null) {
668: Iterator iter = _values.keySet().iterator();
669: while (iter.hasNext()) {
670: String key = (String) iter.next();
671: Object value = _values.get(key);
672: iter.remove();
673: unbindValue(key, value);
674:
675: if (_sessionAttributeListeners.size() > 0) {
676: HttpSessionBindingEvent event = new HttpSessionBindingEvent(
677: this , key, value);
678:
679: for (int i = 0; i < _sessionAttributeListeners
680: .size(); i++) {
681: ((HttpSessionAttributeListener) _sessionAttributeListeners
682: .get(i))
683: .attributeRemoved(event);
684: }
685: }
686: }
687: }
688: }
689: } finally {
690: // Remove session from context and global maps
691: synchronized (__allSessions) {
692: synchronized (_sessions) {
693: _invalid = true;
694: _sessions.remove(getId());
695: __allSessions.removeValue(getId(), this );
696:
697: if (isInvalidateGlobal()) {
698: // Don't iterate as other sessions may also be globally invalidating
699: while (__allSessions.containsKey(getId())) {
700: Session session = (Session) __allSessions
701: .getValue(getId(), 0);
702: session.invalidate();
703: }
704: }
705: }
706: }
707: }
708: }
709:
710: /* ------------------------------------------------------------- */
711: public boolean isNew() throws IllegalStateException {
712: if (_invalid)
713: throw new IllegalStateException();
714: return _newSession;
715: }
716:
717: /* ------------------------------------------------------------ */
718: public synchronized Object getAttribute(String name) {
719: if (_invalid)
720: throw new IllegalStateException();
721: if (_values == null)
722: return null;
723: return _values.get(name);
724: }
725:
726: /* ------------------------------------------------------------ */
727: public synchronized Enumeration getAttributeNames() {
728: if (_invalid)
729: throw new IllegalStateException();
730: List names = _values == null ? Collections.EMPTY_LIST
731: : new ArrayList(_values.keySet());
732: return Collections.enumeration(names);
733: }
734:
735: /* ------------------------------------------------------------ */
736: public synchronized void setAttribute(String name, Object value) {
737: if (_invalid)
738: throw new IllegalStateException();
739: if (_values == null)
740: _values = newAttributeMap();
741: Object oldValue = _values.put(name, value);
742:
743: if (value == null || !value.equals(oldValue)) {
744: unbindValue(name, oldValue);
745: bindValue(name, value);
746:
747: if (_sessionAttributeListeners.size() > 0) {
748: HttpSessionBindingEvent event = new HttpSessionBindingEvent(
749: this , name, oldValue == null ? value
750: : oldValue);
751:
752: for (int i = 0; i < _sessionAttributeListeners
753: .size(); i++) {
754: HttpSessionAttributeListener l = (HttpSessionAttributeListener) _sessionAttributeListeners
755: .get(i);
756:
757: if (oldValue == null)
758: l.attributeAdded(event);
759: else if (value == null)
760: l.attributeRemoved(event);
761: else
762: l.attributeReplaced(event);
763: }
764: }
765: }
766: }
767:
768: /* ------------------------------------------------------------ */
769: public synchronized void removeAttribute(String name) {
770: if (_invalid)
771: throw new IllegalStateException();
772: if (_values == null)
773: return;
774:
775: Object old = _values.remove(name);
776: if (old != null) {
777: unbindValue(name, old);
778: if (_sessionAttributeListeners.size() > 0) {
779: HttpSessionBindingEvent event = new HttpSessionBindingEvent(
780: this , name, old);
781:
782: for (int i = 0; i < _sessionAttributeListeners
783: .size(); i++) {
784: HttpSessionAttributeListener l = (HttpSessionAttributeListener) _sessionAttributeListeners
785: .get(i);
786: l.attributeRemoved(event);
787: }
788: }
789: }
790: }
791:
792: /* ------------------------------------------------------------- */
793: /**
794: * @deprecated As of Version 2.2, this method is
795: * replaced by {@link #getAttribute}
796: */
797: public Object getValue(String name)
798: throws IllegalStateException {
799: return getAttribute(name);
800: }
801:
802: /* ------------------------------------------------------------- */
803: /**
804: * @deprecated As of Version 2.2, this method is
805: * replaced by {@link #getAttributeNames}
806: */
807: public synchronized String[] getValueNames()
808: throws IllegalStateException {
809: if (_invalid)
810: throw new IllegalStateException();
811: if (_values == null)
812: return new String[0];
813: String[] a = new String[_values.size()];
814: return (String[]) _values.keySet().toArray(a);
815: }
816:
817: /* ------------------------------------------------------------- */
818: /**
819: * @deprecated As of Version 2.2, this method is
820: * replaced by {@link #setAttribute}
821: */
822: public void putValue(java.lang.String name,
823: java.lang.Object value) throws IllegalStateException {
824: setAttribute(name, value);
825: }
826:
827: /* ------------------------------------------------------------- */
828: /**
829: * @deprecated As of Version 2.2, this method is
830: * replaced by {@link #removeAttribute}
831: */
832: public void removeValue(java.lang.String name)
833: throws IllegalStateException {
834: removeAttribute(name);
835: }
836:
837: /* ------------------------------------------------------------- */
838: /** If value implements HttpSessionBindingListener, call valueBound() */
839: private void bindValue(java.lang.String name, Object value) {
840: if (value != null
841: && value instanceof HttpSessionBindingListener)
842: ((HttpSessionBindingListener) value)
843: .valueBound(new HttpSessionBindingEvent(this ,
844: name));
845: }
846:
847: /* ------------------------------------------------------------- */
848: /** If value implements HttpSessionBindingListener, call valueUnbound() */
849: private void unbindValue(java.lang.String name, Object value) {
850: if (value != null
851: && value instanceof HttpSessionBindingListener)
852: ((HttpSessionBindingListener) value)
853: .valueUnbound(new HttpSessionBindingEvent(this,
854: name));
855: }
856: }
857:
858: }
|