View Javadoc

1   // ========================================================================
2   // Copyright (c) 1999-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.server.session;
15  
16  import java.io.Serializable;
17  import java.util.ArrayList;
18  import java.util.Collections;
19  import java.util.Enumeration;
20  import java.util.EventListener;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  
25  import javax.servlet.ServletContext;
26  import javax.servlet.http.Cookie;
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpSession;
29  import javax.servlet.http.HttpSessionActivationListener;
30  import javax.servlet.http.HttpSessionAttributeListener;
31  import javax.servlet.http.HttpSessionBindingEvent;
32  import javax.servlet.http.HttpSessionBindingListener;
33  import javax.servlet.http.HttpSessionContext;
34  import javax.servlet.http.HttpSessionEvent;
35  import javax.servlet.http.HttpSessionListener;
36  
37  import org.eclipse.jetty.http.HttpCookie;
38  import org.eclipse.jetty.server.Server;
39  import org.eclipse.jetty.server.SessionIdManager;
40  import org.eclipse.jetty.server.SessionManager;
41  import org.eclipse.jetty.server.handler.ContextHandler;
42  import org.eclipse.jetty.util.LazyList;
43  import org.eclipse.jetty.util.component.AbstractLifeCycle;
44  
45  /* ------------------------------------------------------------ */
46  /**
47   * An Abstract implementation of SessionManager. The partial implementation of
48   * SessionManager interface provides the majority of the handling required to
49   * implement a SessionManager. Concrete implementations of SessionManager based
50   * on AbstractSessionManager need only implement the newSession method to return
51   * a specialized version of the Session inner class that provides an attribute
52   * Map.
53   * <p>
54   * If the property
55   * org.eclipse.jetty.servlet.AbstractSessionManager.23Notifications is set to
56   * true, the 2.3 servlet spec notification style will be used.
57   * <p>
58   *
59   * 
60   */
61  public abstract class AbstractSessionManager extends AbstractLifeCycle implements SessionManager
62  {
63      /* ------------------------------------------------------------ */
64      public final static int __distantFuture=60*60*24*7*52*20;
65  
66      private static final HttpSessionContext __nullSessionContext=new NullSessionContext();
67  
68      private boolean _usingCookies=true;
69  
70      /* ------------------------------------------------------------ */
71      // Setting of max inactive interval for new sessions
72      // -1 means no timeout
73      protected int _dftMaxIdleSecs=-1;
74      protected SessionHandler _sessionHandler;
75      protected boolean _httpOnly=false;
76      protected int _maxSessions=0;
77  
78      protected int _minSessions=0;
79      protected SessionIdManager _sessionIdManager;
80      protected boolean _secureCookies=false;
81      protected Object _sessionAttributeListeners;
82      protected Object _sessionListeners;
83  
84      protected ClassLoader _loader;
85      protected ContextHandler.Context _context;
86      protected String _sessionCookie=__DefaultSessionCookie;
87      protected String _sessionIdPathParameterName = __DefaultSessionIdPathParameterName;
88      protected String _sessionIdPathParameterNamePrefix =";"+ _sessionIdPathParameterName +"=";
89      protected String _sessionDomain;
90      protected String _sessionPath;
91      protected int _maxCookieAge=-1;
92      protected int _refreshCookieAge;
93      protected boolean _nodeIdInSessionId;
94  
95      /* ------------------------------------------------------------ */
96      public AbstractSessionManager()
97      {
98      }
99  
100     /* ------------------------------------------------------------ */
101     public HttpCookie access(HttpSession session,boolean secure)
102     {
103         long now=System.currentTimeMillis();
104 
105         Session s = ((SessionIf)session).getSession();
106         s.access(now);
107 
108         // Do we need to refresh the cookie?
109         if (isUsingCookies() &&
110             (s.isIdChanged() ||
111              (getMaxCookieAge()>0 && getRefreshCookieAge()>0 && ((now-s.getCookieSetTime())/1000>getRefreshCookieAge()))
112             )
113            )
114         {
115             HttpCookie cookie=getSessionCookie(session,_context.getContextPath(),secure);
116             s.cookieSet();
117             s.setIdChanged(false);
118             return cookie;
119         }
120 
121         return null;
122     }
123 
124     /* ------------------------------------------------------------ */
125     public void addEventListener(EventListener listener)
126     {
127         if (listener instanceof HttpSessionAttributeListener)
128             _sessionAttributeListeners=LazyList.add(_sessionAttributeListeners,listener);
129         if (listener instanceof HttpSessionListener)
130             _sessionListeners=LazyList.add(_sessionListeners,listener);
131     }
132 
133     /* ------------------------------------------------------------ */
134     public void clearEventListeners()
135     {
136         _sessionAttributeListeners=null;
137         _sessionListeners=null;
138     }
139 
140     /* ------------------------------------------------------------ */
141     public void complete(HttpSession session)
142     {
143         Session s = ((SessionIf)session).getSession();
144         s.complete();
145     }
146 
147     /* ------------------------------------------------------------ */
148     public void doStart() throws Exception
149     {
150         _context=ContextHandler.getCurrentContext();
151         _loader=Thread.currentThread().getContextClassLoader();
152 
153         if (_sessionIdManager==null)
154         {
155             final Server server=getSessionHandler().getServer();
156             synchronized (server)
157             {
158                 _sessionIdManager=server.getSessionIdManager();
159                 if (_sessionIdManager==null)
160                 {
161                     _sessionIdManager=new HashSessionIdManager();
162                     server.setSessionIdManager(_sessionIdManager);
163                 }
164             }
165         }
166         if (!_sessionIdManager.isStarted())
167             _sessionIdManager.start();
168 
169         // Look for a session cookie name
170         String tmp=_context.getInitParameter(SessionManager.__SessionCookieProperty);
171         if (tmp!=null)
172             _sessionCookie=tmp;
173 
174         tmp=_context.getInitParameter(SessionManager.__SessionIdPathParameterNameProperty);
175         if (tmp!=null)
176         {
177             setSessionIdPathParameterName(tmp);
178         }
179 
180         // set up the max session cookie age if it isn't already
181         if (_maxCookieAge==-1)
182         {
183             if (_context!=null)
184             {
185                 String str=_context.getInitParameter(SessionManager.__MaxAgeProperty);
186                 if (str!=null)
187                     _maxCookieAge=Integer.parseInt(str.trim());
188             }
189         }
190         // set up the session domain if it isn't already
191         if (_sessionDomain==null)
192         {
193             // only try the context initParams
194             if (_context!=null)
195                 _sessionDomain=_context.getInitParameter(SessionManager.__SessionDomainProperty);
196         }
197 
198         // set up the sessionPath if it isn't already
199         if (_sessionPath==null)
200         {
201             // only the context initParams
202             if (_context!=null)
203                 _sessionPath=_context.getInitParameter(SessionManager.__SessionPathProperty);
204         }
205 
206         super.doStart();
207     }
208 
209     /* ------------------------------------------------------------ */
210     public void doStop() throws Exception
211     {
212         super.doStop();
213 
214         invalidateSessions();
215 
216         _loader=null;
217     }
218 
219     /* ------------------------------------------------------------ */
220     /**
221      * @return Returns the httpOnly.
222      */
223     public boolean getHttpOnly()
224     {
225         return _httpOnly;
226     }
227 
228     /* ------------------------------------------------------------ */
229     public HttpSession getHttpSession(String nodeId)
230     {
231         String cluster_id = getIdManager().getClusterId(nodeId);
232 
233         synchronized (this)
234         {
235             Session session = getSession(cluster_id);
236 
237             if (session!=null && !session.getNodeId().equals(nodeId))
238                 session.setIdChanged(true);
239             return session;
240         }
241     }
242 
243     /* ------------------------------------------------------------ */
244     /* ------------------------------------------------------------ */
245     /**
246      * @return Returns the metaManager used for cross context session management
247      */
248     public SessionIdManager getIdManager()
249     {
250         return _sessionIdManager;
251     }
252 
253     /* ------------------------------------------------------------ */
254     public int getMaxCookieAge()
255     {
256         return _maxCookieAge;
257     }
258 
259     /* ------------------------------------------------------------ */
260     /**
261      * @return seconds
262      */
263     public int getMaxInactiveInterval()
264     {
265         return _dftMaxIdleSecs;
266     }
267 
268     /* ------------------------------------------------------------ */
269     public int getMaxSessions()
270     {
271         return _maxSessions;
272     }
273 
274     /* ------------------------------------------------------------ */
275     /**
276      * @deprecated use {@link #getIdManager()}
277      */
278     public SessionIdManager getMetaManager()
279     {
280         return getIdManager();
281     }
282 
283     /* ------------------------------------------------------------ */
284     public int getMinSessions()
285     {
286         return _minSessions;
287     }
288 
289     /* ------------------------------------------------------------ */
290     public int getRefreshCookieAge()
291     {
292         return _refreshCookieAge;
293     }
294 
295 
296     /* ------------------------------------------------------------ */
297     /**
298      * @return Returns the secureCookies.
299      */
300     public boolean getSecureCookies()
301     {
302         return _secureCookies;
303     }
304 
305     /* ------------------------------------------------------------ */
306     public String getSessionCookie()
307     {
308         return _sessionCookie;
309     }
310 
311     /* ------------------------------------------------------------ */
312     public HttpCookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure)
313     {
314         if (isUsingCookies())
315         {
316             String id = getNodeId(session);
317             HttpCookie cookie=new HttpCookie(
318                     _sessionCookie,
319                     id,
320                     _sessionDomain,
321                     (contextPath==null||contextPath.length()==0)?"/":contextPath,
322                     getMaxCookieAge(),
323                     getHttpOnly(),
324                     requestIsSecure&&getSecureCookies());      
325                     
326             return cookie;
327         }
328         return null;
329     }
330 
331     public String getSessionDomain()
332     {
333         return _sessionDomain;
334     }
335 
336     /* ------------------------------------------------------------ */
337     /**
338      * @return Returns the sessionHandler.
339      */
340     public SessionHandler getSessionHandler()
341     {
342         return _sessionHandler;
343     }
344 
345     /* ------------------------------------------------------------ */
346     /**
347      * @deprecated.  Need to review if it is needed.
348      */
349     public abstract Map getSessionMap();
350 
351     /* ------------------------------------------------------------ */
352     public String getSessionPath()
353     {
354         return _sessionPath;
355     }
356 
357     /* ------------------------------------------------------------ */
358     public abstract int getSessions();
359 
360     /* ------------------------------------------------------------ */
361     public String getSessionIdPathParameterName()
362     {
363         return _sessionIdPathParameterName;
364     }
365 
366     /* ------------------------------------------------------------ */
367     public String getSessionIdPathParameterNamePrefix()
368     {
369         return _sessionIdPathParameterNamePrefix;
370     }
371 
372     /* ------------------------------------------------------------ */
373     /**
374      * @return Returns the usingCookies.
375      */
376     public boolean isUsingCookies()
377     {
378         return _usingCookies;
379     }
380 
381     /* ------------------------------------------------------------ */
382     public boolean isValid(HttpSession session)
383     {
384         Session s = ((SessionIf)session).getSession();
385         return s.isValid();
386     }
387 
388     /* ------------------------------------------------------------ */
389     public String getClusterId(HttpSession session)
390     {
391         Session s = ((SessionIf)session).getSession();
392         return s.getClusterId();
393     }
394 
395     /* ------------------------------------------------------------ */
396     public String getNodeId(HttpSession session)
397     {
398         Session s = ((SessionIf)session).getSession();
399         return s.getNodeId();
400     }
401 
402     /* ------------------------------------------------------------ */
403     /**
404      * Create a new HttpSession for a request
405      */
406     public HttpSession newHttpSession(HttpServletRequest request)
407     {
408         Session session=newSession(request);
409         session.setMaxInactiveInterval(_dftMaxIdleSecs);
410         addSession(session,true);
411         return session;
412     }
413 
414     /* ------------------------------------------------------------ */
415     public void removeEventListener(EventListener listener)
416     {
417         if (listener instanceof HttpSessionAttributeListener)
418             _sessionAttributeListeners=LazyList.remove(_sessionAttributeListeners,listener);
419         if (listener instanceof HttpSessionListener)
420             _sessionListeners=LazyList.remove(_sessionListeners,listener);
421     }
422 
423     /* ------------------------------------------------------------ */
424     public void resetStats()
425     {
426         _minSessions=getSessions();
427         _maxSessions=getSessions();
428     }
429 
430     /* ------------------------------------------------------------ */
431     /**
432      * @param httpOnly
433      *            The httpOnly to set.
434      */
435     public void setHttpOnly(boolean httpOnly)
436     {
437         _httpOnly=httpOnly;
438     }
439 
440 
441     /* ------------------------------------------------------------ */
442     /**
443      * @param metaManager The metaManager used for cross context session management.
444      */
445     public void setIdManager(SessionIdManager metaManager)
446     {
447         _sessionIdManager=metaManager;
448     }
449 
450     /* ------------------------------------------------------------ */
451     public void setMaxCookieAge(int maxCookieAgeInSeconds)
452     {
453         _maxCookieAge=maxCookieAgeInSeconds;
454 
455         if (_maxCookieAge>0 && _refreshCookieAge==0)
456             _refreshCookieAge=_maxCookieAge/3;
457 
458     }
459 
460     /* ------------------------------------------------------------ */
461     /**
462      * @param seconds
463      */
464     public void setMaxInactiveInterval(int seconds)
465     {
466         _dftMaxIdleSecs=seconds;
467     }
468 
469     /* ------------------------------------------------------------ */
470     /**
471      * @deprecated use {@link #setIdManager(SessionIdManager)}
472      */
473     public void setMetaManager(SessionIdManager metaManager)
474     {
475         setIdManager(metaManager);
476     }
477 
478     /* ------------------------------------------------------------ */
479     public void setRefreshCookieAge(int ageInSeconds)
480     {
481         _refreshCookieAge=ageInSeconds;
482     }
483 
484 
485     /* ------------------------------------------------------------ */
486     /**
487      * @param secureCookies
488      *            The secureCookies to set.
489      */
490     public void setSecureCookies(boolean secureCookies)
491     {
492         _secureCookies=secureCookies;
493     }
494 
495     public void setSessionCookie(String cookieName)
496     {
497         _sessionCookie=cookieName;
498     }
499 
500     public void setSessionDomain(String domain)
501     {
502         _sessionDomain=domain;
503     }
504 
505     /* ------------------------------------------------------------ */
506     /**
507      * @param sessionHandler
508      *            The sessionHandler to set.
509      */
510     public void setSessionHandler(SessionHandler sessionHandler)
511     {
512         _sessionHandler=sessionHandler;
513     }
514 
515     /* ------------------------------------------------------------ */
516     public void setSessionPath(String path)
517     {
518         _sessionPath=path;
519     }
520 
521     /* ------------------------------------------------------------ */
522     public void setSessionIdPathParameterName(String param)
523     {
524         _sessionIdPathParameterName =(param==null||"none".equals(param))?null:param;
525         _sessionIdPathParameterNamePrefix =(param==null||"none".equals(param))?null:(";"+ _sessionIdPathParameterName +"=");
526     }
527     /* ------------------------------------------------------------ */
528     /**
529      * @param usingCookies
530      *            The usingCookies to set.
531      */
532     public void setUsingCookies(boolean usingCookies)
533     {
534         _usingCookies=usingCookies;
535     }
536 
537 
538     protected abstract void addSession(Session session);
539 
540     /* ------------------------------------------------------------ */
541     /**
542      * Add the session Registers the session with this manager and registers the
543      * session ID with the sessionIDManager;
544      */
545     protected void addSession(Session session, boolean created)
546     {
547         //noinspection SynchronizeOnNonFinalField
548         synchronized (_sessionIdManager)
549         {
550             _sessionIdManager.addSession(session);
551             synchronized (this)
552             {
553                 addSession(session);
554                 if (getSessions()>this._maxSessions)
555                     this._maxSessions=getSessions();
556             }
557         }
558 
559         if (!created)
560         {
561             session.didActivate();
562         }
563         else if (_sessionListeners!=null)
564         {
565             HttpSessionEvent event=new HttpSessionEvent(session);
566             for (int i=0; i<LazyList.size(_sessionListeners); i++)
567                 ((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionCreated(event);
568         }
569     }
570 
571     /* ------------------------------------------------------------ */
572     /**
573      * Get a known existingsession
574      * @param idInCluster The session ID in the cluster, stripped of any worker name.
575      * @return A Session or null if none exists.
576      */
577     public abstract Session getSession(String idInCluster);
578 
579     protected abstract void invalidateSessions();
580 
581 
582     /* ------------------------------------------------------------ */
583     /**
584      * Create a new session instance
585      * @param request
586      * @return
587      */
588     protected abstract Session newSession(HttpServletRequest request);
589 
590 
591 
592     /* ------------------------------------------------------------ */
593     /**
594      * @return true if the cluster node id (worker id) is returned as part of the session id by {@link HttpSession#getId()}. Default is false.
595      */
596     public boolean isNodeIdInSessionId()
597     {
598         return _nodeIdInSessionId;
599     }
600 
601     /* ------------------------------------------------------------ */
602     /**
603      * @param nodeIdInSessionId true if the cluster node id (worker id) will be returned as part of the session id by {@link HttpSession#getId()}. Default is false.
604      */
605     public void setNodeIdInSessionId(boolean nodeIdInSessionId)
606     {
607         _nodeIdInSessionId=nodeIdInSessionId;
608     }
609 
610     /* ------------------------------------------------------------ */
611     /** Remove session from manager
612      * @param session The session to remove
613      * @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
614      * {@link SessionIdManager#invalidateAll(String)} should be called.
615      */
616     public void removeSession(HttpSession session, boolean invalidate)
617     {
618         Session s = ((SessionIf)session).getSession();
619         removeSession(s,invalidate);
620     }
621 
622     /* ------------------------------------------------------------ */
623     /** Remove session from manager
624      * @param session The session to remove
625      * @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
626      * {@link SessionIdManager#invalidateAll(String)} should be called.
627      */
628     public void removeSession(Session session, boolean invalidate)
629     {
630         // Remove session from context and global maps
631         //noinspection SynchronizeOnNonFinalField
632         synchronized (_sessionIdManager)
633         {
634             boolean removed = false;
635 
636             synchronized (this)
637             {
638                 //take this session out of the map of sessions for this context
639                 if (getSession(session.getClusterId()) != null)
640                 {
641                     removed = true;
642                     removeSession(session.getClusterId());
643                 }
644             }
645 
646             if (removed)
647             {
648                 // Remove session from all context and global id maps
649                 _sessionIdManager.removeSession(session);
650                 if (invalidate)
651                     _sessionIdManager.invalidateAll(session.getClusterId());
652             }
653         }
654 
655         if (invalidate && _sessionListeners!=null)
656         {
657             HttpSessionEvent event=new HttpSessionEvent(session);
658             for (int i=LazyList.size(_sessionListeners); i-->0;)
659                 ((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionDestroyed(event);
660         }
661         if (!invalidate)
662         {
663             session.willPassivate();
664         }
665     }
666 
667     /* ------------------------------------------------------------ */
668     protected abstract void removeSession(String idInCluster);
669 
670     /* ------------------------------------------------------------ */
671     /**
672      * Null returning implementation of HttpSessionContext
673      *
674      * 
675      */
676     public static class NullSessionContext implements HttpSessionContext
677     {
678         /* ------------------------------------------------------------ */
679         private NullSessionContext()
680         {
681         }
682 
683         /* ------------------------------------------------------------ */
684         /**
685          * @deprecated From HttpSessionContext
686          */
687         public Enumeration getIds()
688         {
689             return Collections.enumeration(Collections.EMPTY_LIST);
690         }
691 
692         /* ------------------------------------------------------------ */
693         /**
694          * @deprecated From HttpSessionContext
695          */
696         public HttpSession getSession(String id)
697         {
698             return null;
699         }
700     }
701 
702     /* ------------------------------------------------------------ */
703     /* ------------------------------------------------------------ */
704     /* ------------------------------------------------------------ */
705     /**
706      * Interface that any session wrapper should implement so that
707      * SessionManager may access the Jetty session implementation.
708      *
709      */
710     public interface SessionIf extends HttpSession
711     {
712         public Session getSession();
713     }
714 
715     /* ------------------------------------------------------------ */
716     /* ------------------------------------------------------------ */
717     /* ------------------------------------------------------------ */
718     /**
719      *
720      * <p>
721      * Implements {@link javax.servlet.HttpSession} from the {@link javax.servlet} package.
722      * </p>
723      * 
724      *
725      */
726     public abstract class Session implements SessionIf, Serializable
727     {
728         protected final String _clusterId; // ID unique within cluster
729         protected final String _nodeId;    // ID unique within node
730         protected boolean _idChanged;
731         protected final long _created;
732         protected long _cookieSet;
733         protected long _accessed;
734         protected long _lastAccessed;
735         protected boolean _invalid;
736         protected boolean _doInvalidate;
737         protected long _maxIdleMs=_dftMaxIdleSecs*1000;
738         protected boolean _newSession;
739         protected Map _values;
740         protected int _requests;
741 
742         /* ------------------------------------------------------------- */
743         protected Session(HttpServletRequest request)
744         {
745             _newSession=true;
746             _created=System.currentTimeMillis();
747             _clusterId=_sessionIdManager.newSessionId(request,_created);
748             _nodeId=_sessionIdManager.getNodeId(_clusterId,request);
749             _accessed=_created;
750             _requests=1;
751         }
752 
753         /* ------------------------------------------------------------- */
754         protected Session(long created, String clusterId)
755         {
756             _created=created;
757             _clusterId=clusterId;
758             _nodeId=_sessionIdManager.getNodeId(_clusterId,null);
759             _accessed=_created;
760         }
761 
762         /* ------------------------------------------------------------- */
763         public Session getSession()
764         {
765             return this;
766         }
767 
768         /* ------------------------------------------------------------- */
769         protected void initValues()
770         {
771             _values=newAttributeMap();
772         }
773 
774         /* ------------------------------------------------------------ */
775         public Object getAttribute(String name)
776         {
777             synchronized (this)
778             {
779                 if (_invalid)
780                     throw new IllegalStateException();
781 
782                 if (null == _values)
783                     return null;
784 
785                 return _values.get(name);
786             }
787         }
788 
789         /* ------------------------------------------------------------ */
790         public Enumeration getAttributeNames()
791         {
792             synchronized (this)
793             {
794                 if (_invalid)
795                     throw new IllegalStateException();
796                 List names=_values==null?Collections.EMPTY_LIST:new ArrayList(_values.keySet());
797                 return Collections.enumeration(names);
798             }
799         }
800 
801         /* ------------------------------------------------------------- */
802         public long getCookieSetTime()
803         {
804             return _cookieSet;
805         }
806 
807         /* ------------------------------------------------------------- */
808         public long getCreationTime() throws IllegalStateException
809         {
810             if (_invalid)
811                 throw new IllegalStateException();
812             return _created;
813         }
814 
815         /* ------------------------------------------------------------ */
816         public String getId() throws IllegalStateException
817         {
818             return _nodeIdInSessionId?_nodeId:_clusterId;
819         }
820 
821         /* ------------------------------------------------------------- */
822         protected String getNodeId()
823         {
824             return _nodeId;
825         }
826 
827         /* ------------------------------------------------------------- */
828         protected String getClusterId()
829         {
830             return _clusterId;
831         }
832 
833         /* ------------------------------------------------------------- */
834         public long getLastAccessedTime() throws IllegalStateException
835         {
836             if (_invalid)
837                 throw new IllegalStateException();
838             return _lastAccessed;
839         }
840 
841         /* ------------------------------------------------------------- */
842         public int getMaxInactiveInterval()
843         {
844             if (_invalid)
845                 throw new IllegalStateException();
846             return (int)(_maxIdleMs/1000);
847         }
848 
849         /* ------------------------------------------------------------ */
850         /*
851          * @see javax.servlet.http.HttpSession#getServletContext()
852          */
853         public ServletContext getServletContext()
854         {
855             return _context;
856         }
857 
858         /* ------------------------------------------------------------- */
859         /**
860          * @deprecated
861          */
862         public HttpSessionContext getSessionContext() throws IllegalStateException
863         {
864             if (_invalid)
865                 throw new IllegalStateException();
866             return __nullSessionContext;
867         }
868 
869         /* ------------------------------------------------------------- */
870         /**
871          * @deprecated As of Version 2.2, this method is replaced by
872          *             {@link #getAttribute}
873          */
874         public Object getValue(String name) throws IllegalStateException
875         {
876             return getAttribute(name);
877         }
878 
879         /* ------------------------------------------------------------- */
880         /**
881          * @deprecated As of Version 2.2, this method is replaced by
882          *             {@link #getAttributeNames}
883          */
884         public String[] getValueNames() throws IllegalStateException
885         {
886             synchronized(this)
887             {
888                 if (_invalid)
889                     throw new IllegalStateException();
890                 if (_values==null)
891                     return new String[0];
892                 String[] a=new String[_values.size()];
893                 return (String[])_values.keySet().toArray(a);
894             }
895         }
896 
897         /* ------------------------------------------------------------ */
898         protected void access(long time)
899         {
900             synchronized(this)
901             {
902                 _newSession=false;
903                 _lastAccessed=_accessed;
904                 _accessed=time;
905                 _requests++;
906             }
907         }
908 
909         /* ------------------------------------------------------------ */
910         protected void complete()
911         {
912             synchronized(this)
913             {
914                 _requests--;
915                 if (_doInvalidate && _requests<=0  )
916                     doInvalidate();
917             }
918         }
919 
920 
921         /* ------------------------------------------------------------- */
922         protected void timeout() throws IllegalStateException
923         {
924             // remove session from context and invalidate other sessions with same ID.
925             removeSession(this,true);
926 
927             // Notify listeners and unbind values
928             synchronized (this)
929             {
930                 if (_requests<=0)
931                     doInvalidate();
932                 else
933                     _doInvalidate=true;
934             }
935         }
936 
937         /* ------------------------------------------------------------- */
938         public void invalidate() throws IllegalStateException
939         {
940             // remove session from context and invalidate other sessions with same ID.
941             removeSession(this,true);
942             doInvalidate();
943         }
944 
945         /* ------------------------------------------------------------- */
946         protected void doInvalidate() throws IllegalStateException
947         {
948             try
949             {
950                 // Notify listeners and unbind values
951                 if (_invalid)
952                     throw new IllegalStateException();
953 
954                 while (_values!=null && _values.size()>0)
955                 {
956                     ArrayList keys;
957                     synchronized (this)
958                     {
959                         keys=new ArrayList(_values.keySet());
960                     }
961 
962                     Iterator iter=keys.iterator();
963                     while (iter.hasNext())
964                     {
965                         String key=(String)iter.next();
966 
967                         Object value;
968                         synchronized (this)
969                         {
970                             value=_values.remove(key);
971                         }
972                         unbindValue(key,value);
973 
974                         if (_sessionAttributeListeners!=null)
975                         {
976                             HttpSessionBindingEvent event=new HttpSessionBindingEvent(this,key,value);
977 
978                             for (int i=0; i<LazyList.size(_sessionAttributeListeners); i++)
979                                 ((HttpSessionAttributeListener)LazyList.get(_sessionAttributeListeners,i)).attributeRemoved(event);
980                         }
981                     }
982                 }
983             }
984             finally
985             {
986                 // mark as invalid
987                 _invalid=true;
988             }
989         }
990 
991         /* ------------------------------------------------------------- */
992         public boolean isIdChanged()
993         {
994             return _idChanged;
995         }
996 
997         /* ------------------------------------------------------------- */
998         public boolean isNew() throws IllegalStateException
999         {
1000             if (_invalid)
1001                 throw new IllegalStateException();
1002             return _newSession;
1003         }
1004 
1005         /* ------------------------------------------------------------- */
1006         /**
1007          * @deprecated As of Version 2.2, this method is replaced by
1008          *             {@link #setAttribute}
1009          */
1010         public void putValue(java.lang.String name, java.lang.Object value) throws IllegalStateException
1011         {
1012             setAttribute(name,value);
1013         }
1014 
1015         /* ------------------------------------------------------------ */
1016         public void removeAttribute(String name)
1017         {
1018             Object old;
1019             synchronized(this)
1020             {
1021                 if (_invalid)
1022                     throw new IllegalStateException();
1023                 if (_values==null)
1024                     return;
1025 
1026                 old=_values.remove(name);
1027             }
1028 
1029             if (old!=null)
1030             {
1031                 unbindValue(name,old);
1032                 if (_sessionAttributeListeners!=null)
1033                 {
1034                     HttpSessionBindingEvent event=new HttpSessionBindingEvent(this,name,old);
1035 
1036                     for (int i=0; i<LazyList.size(_sessionAttributeListeners); i++)
1037                         ((HttpSessionAttributeListener)LazyList.get(_sessionAttributeListeners,i)).attributeRemoved(event);
1038                 }
1039             }
1040 
1041         }
1042 
1043         /* ------------------------------------------------------------- */
1044         /**
1045          * @deprecated As of Version 2.2, this method is replaced by
1046          *             {@link #removeAttribute}
1047          */
1048         public void removeValue(java.lang.String name) throws IllegalStateException
1049         {
1050             removeAttribute(name);
1051         }
1052 
1053         /* ------------------------------------------------------------ */
1054         public void setAttribute(String name, Object value)
1055         {
1056             Object old_value;
1057             if (value==null)
1058             {
1059                 removeAttribute(name);
1060                 return;
1061             }
1062 
1063             synchronized(this)
1064             {
1065                 if (_invalid)
1066                     throw new IllegalStateException();
1067                 if (_values==null)
1068                     _values=newAttributeMap();
1069                 old_value=_values.put(name,value);
1070             }
1071 
1072             if (old_value==null || !value.equals(old_value))
1073             {
1074                 unbindValue(name,old_value);
1075                 bindValue(name,value);
1076 
1077                 if (_sessionAttributeListeners!=null)
1078                 {
1079                     HttpSessionBindingEvent event=new HttpSessionBindingEvent(this,name,old_value==null?value:old_value);
1080 
1081                     for (int i=0; i<LazyList.size(_sessionAttributeListeners); i++)
1082                     {
1083                         HttpSessionAttributeListener l=(HttpSessionAttributeListener)LazyList.get(_sessionAttributeListeners,i);
1084 
1085                         if (old_value==null)
1086                             l.attributeAdded(event);
1087                         else
1088                             l.attributeReplaced(event);
1089                     }
1090                 }
1091             }
1092         }
1093 
1094         /* ------------------------------------------------------------- */
1095         public void setIdChanged(boolean changed)
1096         {
1097             _idChanged=changed;
1098         }
1099 
1100         /* ------------------------------------------------------------- */
1101         public void setMaxInactiveInterval(int secs)
1102         {
1103             _maxIdleMs=(long)secs*1000;
1104         }
1105 
1106         /* ------------------------------------------------------------- */
1107         public String toString()
1108         {
1109             return this.getClass().getName()+":"+getId()+"@"+hashCode();
1110         }
1111 
1112         /* ------------------------------------------------------------- */
1113         /** If value implements HttpSessionBindingListener, call valueBound() */
1114         protected void bindValue(java.lang.String name, Object value)
1115         {
1116             if (value!=null&&value instanceof HttpSessionBindingListener)
1117                 ((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this,name));
1118         }
1119 
1120         /* ------------------------------------------------------------ */
1121         protected boolean isValid()
1122         {
1123             return !_invalid;
1124         }
1125 
1126         /* ------------------------------------------------------------ */
1127         protected abstract Map newAttributeMap();
1128 
1129         /* ------------------------------------------------------------- */
1130         protected void cookieSet()
1131         {
1132             _cookieSet=_accessed;
1133         }
1134 
1135         /* ------------------------------------------------------------- */
1136         /** If value implements HttpSessionBindingListener, call valueUnbound() */
1137         protected void unbindValue(java.lang.String name, Object value)
1138         {
1139             if (value!=null&&value instanceof HttpSessionBindingListener)
1140                 ((HttpSessionBindingListener)value).valueUnbound(new HttpSessionBindingEvent(this,name));
1141         }
1142 
1143         /* ------------------------------------------------------------- */
1144         protected void willPassivate()
1145         {
1146             synchronized(this)
1147             {
1148                 HttpSessionEvent event = new HttpSessionEvent(this);
1149                 for (Iterator iter = _values.values().iterator(); iter.hasNext();)
1150                 {
1151                     Object value = iter.next();
1152                     if (value instanceof HttpSessionActivationListener)
1153                     {
1154                         HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
1155                         listener.sessionWillPassivate(event);
1156                     }
1157                 }
1158             }
1159         }
1160 
1161         /* ------------------------------------------------------------- */
1162         protected void didActivate()
1163         {
1164             synchronized(this)
1165             {
1166                 HttpSessionEvent event = new HttpSessionEvent(this);
1167                 for (Iterator iter = _values.values().iterator(); iter.hasNext();)
1168                 {
1169                     Object value = iter.next();
1170                     if (value instanceof HttpSessionActivationListener)
1171                     {
1172                         HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
1173                         listener.sessionDidActivate(event);
1174                     }
1175                 }
1176             }
1177         }
1178     }
1179 }