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 static java.lang.Math.round;
17  
18  import java.util.Arrays;
19  import java.util.Collections;
20  import java.util.Enumeration;
21  import java.util.EventListener;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  import java.util.concurrent.CopyOnWriteArrayList;
27  
28  import javax.servlet.ServletRequest;
29  import javax.servlet.SessionCookieConfig;
30  import javax.servlet.SessionTrackingMode;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpSession;
33  import javax.servlet.http.HttpSessionAttributeListener;
34  import javax.servlet.http.HttpSessionBindingEvent;
35  import javax.servlet.http.HttpSessionContext;
36  import javax.servlet.http.HttpSessionEvent;
37  import javax.servlet.http.HttpSessionListener;
38  
39  import org.eclipse.jetty.http.HttpCookie;
40  import org.eclipse.jetty.server.AbstractConnector;
41  import org.eclipse.jetty.server.Request;
42  import org.eclipse.jetty.server.Server;
43  import org.eclipse.jetty.server.SessionIdManager;
44  import org.eclipse.jetty.server.SessionManager;
45  import org.eclipse.jetty.server.handler.ContextHandler;
46  import org.eclipse.jetty.util.component.AbstractLifeCycle;
47  import org.eclipse.jetty.util.log.Logger;
48  import org.eclipse.jetty.util.statistic.CounterStatistic;
49  import org.eclipse.jetty.util.statistic.SampleStatistic;
50  
51  /* ------------------------------------------------------------ */
52  /**
53   * An Abstract implementation of SessionManager. The partial implementation of
54   * SessionManager interface provides the majority of the handling required to
55   * implement a SessionManager. Concrete implementations of SessionManager based
56   * on AbstractSessionManager need only implement the newSession method to return
57   * a specialised version of the Session inner class that provides an attribute
58   * Map.
59   * <p>
60   */
61  @SuppressWarnings("deprecation")
62  public abstract class AbstractSessionManager extends AbstractLifeCycle implements SessionManager
63  {
64      final static Logger __log = SessionHandler.LOG;
65  
66      public Set<SessionTrackingMode> __defaultSessionTrackingModes =
67          Collections.unmodifiableSet(
68              new HashSet<SessionTrackingMode>(
69                      Arrays.asList(new SessionTrackingMode[]{SessionTrackingMode.COOKIE,SessionTrackingMode.URL})));
70          
71      /* ------------------------------------------------------------ */
72      public final static int __distantFuture=60*60*24*7*52*20;
73  
74      static final HttpSessionContext __nullSessionContext=new HttpSessionContext()
75      {
76          public HttpSession getSession(String sessionId)
77          {
78              return null;
79          }
80          
81          @SuppressWarnings({ "rawtypes", "unchecked" })
82          public Enumeration getIds()
83          {
84              return Collections.enumeration(Collections.EMPTY_LIST);
85          }
86      };
87      
88      private boolean _usingCookies=true;
89  
90      /* ------------------------------------------------------------ */
91      // Setting of max inactive interval for new sessions
92      // -1 means no timeout
93      protected int _dftMaxIdleSecs=-1;
94      protected SessionHandler _sessionHandler;
95      protected boolean _httpOnly=false;
96      protected SessionIdManager _sessionIdManager;
97      protected boolean _secureCookies=false;
98      protected boolean _secureRequestOnly=true;
99  
100     protected final List<HttpSessionAttributeListener> _sessionAttributeListeners = new CopyOnWriteArrayList<HttpSessionAttributeListener>();
101     protected final List<HttpSessionListener> _sessionListeners= new CopyOnWriteArrayList<HttpSessionListener>();
102 
103     protected ClassLoader _loader;
104     protected ContextHandler.Context _context;
105     protected String _sessionCookie=__DefaultSessionCookie;
106     protected String _sessionIdPathParameterName = __DefaultSessionIdPathParameterName;
107     protected String _sessionIdPathParameterNamePrefix =";"+ _sessionIdPathParameterName +"=";
108     protected String _sessionDomain;
109     protected String _sessionPath;
110     protected int _maxCookieAge=-1;
111     protected int _refreshCookieAge;
112     protected boolean _nodeIdInSessionId;
113     protected boolean _checkingRemoteSessionIdEncoding;
114     protected String _sessionComment;
115 
116     public Set<SessionTrackingMode> _sessionTrackingModes;
117 
118     private boolean _usingURLs;
119     
120     protected final CounterStatistic _sessionsStats = new CounterStatistic();
121     protected final SampleStatistic _sessionTimeStats = new SampleStatistic();
122     
123     /* ------------------------------------------------------------ */
124     public AbstractSessionManager()
125     {
126         setSessionTrackingModes(__defaultSessionTrackingModes);
127     }
128 
129     /* ------------------------------------------------------------ */
130     public ContextHandler.Context getContext()
131     {
132         return _context;
133     }
134 
135     /* ------------------------------------------------------------ */
136     public ContextHandler getContextHandler()
137     {
138         return _context.getContextHandler();
139     }
140     
141     /* ------------------------------------------------------------ */
142     public HttpCookie access(HttpSession session,boolean secure)
143     {
144         long now=System.currentTimeMillis();
145 
146         AbstractSession s = ((SessionIf)session).getSession();
147 
148        if (s.access(now))
149        {
150             // Do we need to refresh the cookie?
151             if (isUsingCookies() &&
152                 (s.isIdChanged() ||
153                 (getSessionCookieConfig().getMaxAge()>0 && getRefreshCookieAge()>0 && ((now-s.getCookieSetTime())/1000>getRefreshCookieAge()))
154                 )
155                )
156             {
157                 HttpCookie cookie=getSessionCookie(session,_context==null?"/":(_context.getContextPath()),secure);
158                 s.cookieSet();
159                 s.setIdChanged(false);
160                 return cookie;
161             }
162         }
163         return null;
164     }
165 
166     /* ------------------------------------------------------------ */
167     public void addEventListener(EventListener listener)
168     {
169         if (listener instanceof HttpSessionAttributeListener)
170             _sessionAttributeListeners.add((HttpSessionAttributeListener)listener);
171         if (listener instanceof HttpSessionListener)
172             _sessionListeners.add((HttpSessionListener)listener);
173     }
174 
175     /* ------------------------------------------------------------ */
176     public void clearEventListeners()
177     {
178         _sessionAttributeListeners.clear();
179         _sessionListeners.clear();
180     }
181 
182     /* ------------------------------------------------------------ */
183     public void complete(HttpSession session)
184     {
185         AbstractSession s = ((SessionIf)session).getSession();
186         s.complete();
187     }
188 
189     /* ------------------------------------------------------------ */
190     @Override
191     public void doStart() throws Exception
192     {
193         _context=ContextHandler.getCurrentContext();
194         _loader=Thread.currentThread().getContextClassLoader();
195 
196         if (_sessionIdManager==null)
197         {
198             final Server server=getSessionHandler().getServer();
199             synchronized (server)
200             {
201                 _sessionIdManager=server.getSessionIdManager();
202                 if (_sessionIdManager==null)
203                 {
204                     _sessionIdManager=new HashSessionIdManager();
205                     server.setSessionIdManager(_sessionIdManager);
206                 }
207             }
208         }
209         if (!_sessionIdManager.isStarted())
210             _sessionIdManager.start();
211 
212         // Look for a session cookie name
213         if (_context!=null)
214         {
215             String tmp=_context.getInitParameter(SessionManager.__SessionCookieProperty);
216             if (tmp!=null)
217                 _sessionCookie=tmp;
218 
219             tmp=_context.getInitParameter(SessionManager.__SessionIdPathParameterNameProperty);
220             if (tmp!=null)
221                 setSessionIdPathParameterName(tmp);
222 
223             // set up the max session cookie age if it isn't already
224             if (_maxCookieAge==-1)
225             {
226                 tmp=_context.getInitParameter(SessionManager.__MaxAgeProperty);
227                 if (tmp!=null)
228                     _maxCookieAge=Integer.parseInt(tmp.trim());
229             }
230 
231             // set up the session domain if it isn't already
232             if (_sessionDomain==null)
233                 _sessionDomain=_context.getInitParameter(SessionManager.__SessionDomainProperty);
234 
235             // set up the sessionPath if it isn't already
236             if (_sessionPath==null)
237                 _sessionPath=_context.getInitParameter(SessionManager.__SessionPathProperty);
238             
239             tmp=_context.getInitParameter(SessionManager.__CheckRemoteSessionEncoding);
240             if (tmp!=null)
241                 _checkingRemoteSessionIdEncoding=Boolean.parseBoolean(tmp);
242         }
243 
244         super.doStart();
245     }
246 
247     /* ------------------------------------------------------------ */
248     @Override
249     public void doStop() throws Exception
250     {
251         super.doStop();
252 
253         invalidateSessions();
254 
255         _loader=null;
256     }
257 
258     /* ------------------------------------------------------------ */
259     /**
260      * @return Returns the httpOnly.
261      */
262     public boolean getHttpOnly()
263     {
264         return _httpOnly;
265     }
266 
267     /* ------------------------------------------------------------ */
268     public HttpSession getHttpSession(String nodeId)
269     {
270         String cluster_id = getSessionIdManager().getClusterId(nodeId);
271 
272         AbstractSession session = getSession(cluster_id);
273         if (session!=null && !session.getNodeId().equals(nodeId))
274             session.setIdChanged(true);
275         return session;
276     }
277 
278     /* ------------------------------------------------------------ */
279     /**
280      * @return Returns the metaManager used for cross context session management
281      * @deprecated Use {@link #getSessionIdManager()}
282      */
283     public SessionIdManager getIdManager()
284     {
285         return getSessionIdManager();
286     }
287     
288     /* ------------------------------------------------------------ */
289     /**
290      * @return Returns the SessionIdManager used for cross context session management
291      */
292     public SessionIdManager getSessionIdManager()
293     {
294         return _sessionIdManager;
295     }
296 
297 
298     /* ------------------------------------------------------------ */
299     /**
300      * @return seconds
301      */
302     @Override
303     public int getMaxInactiveInterval()
304     {
305         return _dftMaxIdleSecs;
306     }
307     
308     /* ------------------------------------------------------------ */
309     /**
310      * @see #getSessionsMax()
311      */
312     @Deprecated
313     public int getMaxSessions()
314     {
315         return getSessionsMax();
316     }
317 
318     /* ------------------------------------------------------------ */
319     /**
320      * @return maximum number of sessions
321      */
322     public int getSessionsMax()
323     {
324         return (int)_sessionsStats.getMax();
325     }
326 
327     /* ------------------------------------------------------------ */
328     /**
329      * @return total number of sessions
330      */
331     public int getSessionsTotal()
332     {
333         return (int)_sessionsStats.getTotal();
334     }
335 
336     /* ------------------------------------------------------------ */
337     /**
338      * @deprecated use {@link #getSessionIdManager()}
339      */
340     @Deprecated
341     public SessionIdManager getMetaManager()
342     {
343         return getSessionIdManager();
344     }
345 
346     /* ------------------------------------------------------------ */
347     /**
348      * @deprecated always returns 0. no replacement available.
349      */
350     @Deprecated
351     public int getMinSessions()
352     {
353         return 0;
354     }
355 
356     /* ------------------------------------------------------------ */
357     public int getRefreshCookieAge()
358     {
359         return _refreshCookieAge;
360     }
361 
362 
363     /* ------------------------------------------------------------ */
364     /**
365      * @return same as SessionCookieConfig.getSecure(). If true, session
366      * cookies are ALWAYS marked as secure. If false, a session cookie is
367      * ONLY marked as secure if _secureRequestOnly == true and it is a HTTPS request.
368      */
369     public boolean getSecureCookies()
370     {
371         return _secureCookies;
372     }
373     
374     /* ------------------------------------------------------------ */
375     /**
376      * @return true if session cookie is to be marked as secure only on HTTPS requests
377      */
378     public boolean isSecureRequestOnly()
379     {
380         return _secureRequestOnly;
381     }
382     
383     
384     /* ------------------------------------------------------------ */
385     /**
386      * @return if true, session cookie will be marked as secure only iff 
387      * HTTPS request. Can be overridden by setting SessionCookieConfig.setSecure(true),
388      * in which case the session cookie will be marked as secure on both HTTPS and HTTP.
389      */
390     public void setSecureRequestOnly(boolean secureRequestOnly)
391     {
392         _secureRequestOnly = secureRequestOnly;
393     }
394 
395     
396     
397     /* ------------------------------------------------------------ */
398     public String getSessionCookie()
399     {
400         return _sessionCookie;
401     }
402 
403     /* ------------------------------------------------------------ */
404     /** 
405      * A sessioncookie is marked as secure IFF any of the following conditions are true:
406      * <ol>
407      * <li>SessionCookieConfig.setSecure == true</li>
408      * <li>SessionCookieConfig.setSecure == false && _secureRequestOnly==true && request is HTTPS</li>
409      * </ol>
410      * According to SessionCookieConfig javadoc, case 1 can be used when:
411      * "... even though the request that initiated the session came over HTTP, 
412      * is to support a topology where the web container is front-ended by an 
413      * SSL offloading load balancer. In this case, the traffic between the client 
414      * and the load balancer will be over HTTPS, whereas the traffic between the 
415      * load balancer and the web container will be over HTTP."
416      * 
417      * For case 2, you can use _secureRequestOnly to determine if you want the
418      * Servlet Spec 3.0  default behaviour when SessionCookieConfig.setSecure==false, 
419      * which is:
420      * "they shall be marked as secure only if the request that initiated the 
421      * corresponding session was also secure"
422      * 
423      * The default for _secureRequestOnly is true, which gives the above behaviour. If
424      * you set it to false, then a session cookie is NEVER marked as secure, even if
425      * the initiating request was secure.
426      * 
427      * @see org.eclipse.jetty.server.SessionManager#getSessionCookie(javax.servlet.http.HttpSession, java.lang.String, boolean)
428      */
429     public HttpCookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure)
430     {
431         if (isUsingCookies())
432         {
433             String sessionPath = (_sessionPath==null) ? contextPath : _sessionPath;
434             sessionPath = (sessionPath==null||sessionPath.length()==0) ? "/" : sessionPath;
435             String id = getNodeId(session);
436             HttpCookie cookie = null;
437             if (_sessionComment == null)
438             {
439                 cookie = new HttpCookie(
440                                         _sessionCookie,
441                                         id,
442                                         _sessionDomain,
443                                         sessionPath,
444                                         _cookieConfig.getMaxAge(),
445                                         _cookieConfig.isHttpOnly(),
446                                         _cookieConfig.isSecure() || (isSecureRequestOnly() && requestIsSecure));                  
447             }
448             else
449             {
450                 cookie = new HttpCookie(
451                                         _sessionCookie,
452                                         id,
453                                         _sessionDomain,
454                                         sessionPath,
455                                         _cookieConfig.getMaxAge(),
456                                         _cookieConfig.isHttpOnly(),
457                                         _cookieConfig.isSecure() || (isSecureRequestOnly() && requestIsSecure),
458                                         _sessionComment,
459                                         1);    
460             }
461 
462             return cookie;
463         }
464         return null;
465     }
466 
467     public String getSessionDomain()
468     {
469         return _sessionDomain;
470     }
471 
472     /* ------------------------------------------------------------ */
473     /**
474      * @return Returns the sessionHandler.
475      */
476     public SessionHandler getSessionHandler()
477     {
478         return _sessionHandler;
479     }
480 
481     /* ------------------------------------------------------------ */
482     /**
483      * @deprecated  Need to review if it is needed.
484      */
485     @SuppressWarnings("rawtypes")
486     public Map getSessionMap()
487     {
488         throw new UnsupportedOperationException();
489     }
490 
491    
492 
493     /* ------------------------------------------------------------ */
494     public int getSessions()
495     {
496         return (int)_sessionsStats.getCurrent();
497     }
498 
499     /* ------------------------------------------------------------ */
500     public String getSessionIdPathParameterName()
501     {
502         return _sessionIdPathParameterName;
503     }
504 
505     /* ------------------------------------------------------------ */
506     public String getSessionIdPathParameterNamePrefix()
507     {
508         return _sessionIdPathParameterNamePrefix;
509     }
510 
511     /* ------------------------------------------------------------ */
512     /**
513      * @return Returns the usingCookies.
514      */
515     public boolean isUsingCookies()
516     {
517         return _usingCookies;
518     }
519 
520     /* ------------------------------------------------------------ */
521     public boolean isValid(HttpSession session)
522     {
523         AbstractSession s = ((SessionIf)session).getSession();
524         return s.isValid();
525     }
526 
527     /* ------------------------------------------------------------ */
528     public String getClusterId(HttpSession session)
529     {
530         AbstractSession s = ((SessionIf)session).getSession();
531         return s.getClusterId();
532     }
533 
534     /* ------------------------------------------------------------ */
535     public String getNodeId(HttpSession session)
536     {
537         AbstractSession s = ((SessionIf)session).getSession();
538         return s.getNodeId();
539     }
540 
541     /* ------------------------------------------------------------ */
542     /**
543      * Create a new HttpSession for a request
544      */
545     public HttpSession newHttpSession(HttpServletRequest request)
546     {
547         AbstractSession session=newSession(request);
548         session.setMaxInactiveInterval(_dftMaxIdleSecs);
549         addSession(session,true);
550         return session;
551     }
552 
553     /* ------------------------------------------------------------ */
554     public void removeEventListener(EventListener listener)
555     {
556         if (listener instanceof HttpSessionAttributeListener)
557             _sessionAttributeListeners.remove(listener);
558         if (listener instanceof HttpSessionListener)
559             _sessionListeners.remove(listener);
560     }
561     
562     /* ------------------------------------------------------------ */
563     /**
564      * @see #statsReset()
565      */
566     @Deprecated
567     public void resetStats()
568     {
569         statsReset();
570     }
571 
572     /* ------------------------------------------------------------ */
573     /**
574      * Reset statistics values
575      */
576     public void statsReset()
577     {
578         _sessionsStats.reset(getSessions());
579         _sessionTimeStats.reset();
580     }
581 
582     /* ------------------------------------------------------------ */
583     /**
584      * @param httpOnly
585      *            The httpOnly to set.
586      */
587     public void setHttpOnly(boolean httpOnly)
588     {
589         _httpOnly=httpOnly;
590     }
591 
592     /* ------------------------------------------------------------ */
593     /**
594      * @param metaManager The metaManager used for cross context session management.
595      * @deprecated use {@link #setSessionIdManager(SessionIdManager)}
596      */
597     public void setIdManager(SessionIdManager metaManager)
598     {
599         setSessionIdManager(metaManager);
600     }
601     
602     /* ------------------------------------------------------------ */
603     /**
604      * @param metaManager The metaManager used for cross context session management.
605      */
606     public void setSessionIdManager(SessionIdManager metaManager)
607     {
608         _sessionIdManager=metaManager;
609     }
610 
611 
612 
613     /* ------------------------------------------------------------ */
614     /**
615      * @param seconds
616      */
617     public void setMaxInactiveInterval(int seconds)
618     {
619         _dftMaxIdleSecs=seconds;
620     }
621 
622 
623     /* ------------------------------------------------------------ */
624     public void setRefreshCookieAge(int ageInSeconds)
625     {
626         _refreshCookieAge=ageInSeconds;
627     }
628 
629 
630 
631     public void setSessionCookie(String cookieName)
632     {
633         _sessionCookie=cookieName;
634     }
635 
636 
637 
638     /* ------------------------------------------------------------ */
639     /**
640      * @param sessionHandler
641      *            The sessionHandler to set.
642      */
643     public void setSessionHandler(SessionHandler sessionHandler)
644     {
645         _sessionHandler=sessionHandler;
646     }
647 
648  
649     /* ------------------------------------------------------------ */
650     public void setSessionIdPathParameterName(String param)
651     {
652         _sessionIdPathParameterName =(param==null||"none".equals(param))?null:param;
653         _sessionIdPathParameterNamePrefix =(param==null||"none".equals(param))?null:(";"+ _sessionIdPathParameterName +"=");
654     }
655     /* ------------------------------------------------------------ */
656     /**
657      * @param usingCookies
658      *            The usingCookies to set.
659      */
660     public void setUsingCookies(boolean usingCookies)
661     {
662         _usingCookies=usingCookies;
663     }
664 
665 
666     protected abstract void addSession(AbstractSession session);
667 
668     /* ------------------------------------------------------------ */
669     /**
670      * Add the session Registers the session with this manager and registers the
671      * session ID with the sessionIDManager;
672      */
673     protected void addSession(AbstractSession session, boolean created)
674     {
675         synchronized (_sessionIdManager)
676         {
677             _sessionIdManager.addSession(session);
678             addSession(session);
679         }
680 
681         if (created)
682         {
683             _sessionsStats.increment();
684             if (_sessionListeners!=null)
685             {
686                 HttpSessionEvent event=new HttpSessionEvent(session);
687                 for (HttpSessionListener listener : _sessionListeners)
688                     listener.sessionCreated(event);
689             }
690         }
691     }
692 
693     /* ------------------------------------------------------------ */
694     /**
695      * Get a known existing session
696      * @param idInCluster The session ID in the cluster, stripped of any worker name.
697      * @return A Session or null if none exists.
698      */
699     public abstract AbstractSession getSession(String idInCluster);
700 
701     protected abstract void invalidateSessions() throws Exception;
702 
703 
704     /* ------------------------------------------------------------ */
705     /**
706      * Create a new session instance
707      * @param request
708      * @return the new session
709      */
710     protected abstract AbstractSession newSession(HttpServletRequest request);
711 
712 
713     /* ------------------------------------------------------------ */
714     /**
715      * @return true if the cluster node id (worker id) is returned as part of the session id by {@link HttpSession#getId()}. Default is false.
716      */
717     public boolean isNodeIdInSessionId()
718     {
719         return _nodeIdInSessionId;
720     }
721 
722     /* ------------------------------------------------------------ */
723     /**
724      * @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.
725      */
726     public void setNodeIdInSessionId(boolean nodeIdInSessionId)
727     {
728         _nodeIdInSessionId=nodeIdInSessionId;
729     }
730 
731     /* ------------------------------------------------------------ */
732     /** Remove session from manager
733      * @param session The session to remove
734      * @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
735      * {@link SessionIdManager#invalidateAll(String)} should be called.
736      */
737     public void removeSession(HttpSession session, boolean invalidate)
738     {
739         AbstractSession s = ((SessionIf)session).getSession();
740         removeSession(s,invalidate);
741     }
742 
743     /* ------------------------------------------------------------ */
744     /** Remove session from manager
745      * @param session The session to remove
746      * @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
747      * {@link SessionIdManager#invalidateAll(String)} should be called.
748      */
749     public void removeSession(AbstractSession session, boolean invalidate)
750     {
751         // Remove session from context and global maps
752         boolean removed = removeSession(session.getClusterId());
753         
754         if (removed)
755         {
756             _sessionsStats.decrement();
757             _sessionTimeStats.set(round((System.currentTimeMillis() - session.getCreationTime())/1000.0));
758             
759             // Remove session from all context and global id maps
760             _sessionIdManager.removeSession(session);
761             if (invalidate)
762                 _sessionIdManager.invalidateAll(session.getClusterId());
763             
764             if (invalidate && _sessionListeners!=null)
765             {
766                 HttpSessionEvent event=new HttpSessionEvent(session);
767                 for (HttpSessionListener listener : _sessionListeners)
768                     listener.sessionDestroyed(event);
769             }
770         }
771     }
772 
773     /* ------------------------------------------------------------ */
774     protected abstract boolean removeSession(String idInCluster);
775     
776     /* ------------------------------------------------------------ */
777     /**
778      * @return maximum amount of time session remained valid
779      */
780     public long getSessionTimeMax()
781     {
782         return _sessionTimeStats.getMax();
783     }
784 
785     /* ------------------------------------------------------------ */
786     public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
787     {
788         return __defaultSessionTrackingModes;
789     }
790 
791     /* ------------------------------------------------------------ */
792     public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
793     {
794         return Collections.unmodifiableSet(_sessionTrackingModes);
795     }
796 
797     /* ------------------------------------------------------------ */
798     @Override
799     public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
800     {
801         _sessionTrackingModes=new HashSet<SessionTrackingMode>(sessionTrackingModes);
802         _usingCookies=_sessionTrackingModes.contains(SessionTrackingMode.COOKIE);
803         _usingURLs=_sessionTrackingModes.contains(SessionTrackingMode.URL);
804     }
805 
806     /* ------------------------------------------------------------ */
807     @Override
808     public boolean isUsingURLs()
809     {
810         return _usingURLs;
811     }
812 
813 
814     /* ------------------------------------------------------------ */
815     public SessionCookieConfig getSessionCookieConfig()
816     {
817         return _cookieConfig;
818     } 
819 
820     /* ------------------------------------------------------------ */
821     private SessionCookieConfig _cookieConfig =
822         new SessionCookieConfig()
823         {
824             @Override
825             public String getComment()
826             {
827                 return _sessionComment;
828             }
829 
830             @Override
831             public String getDomain()
832             {
833                 return _sessionDomain;
834             }
835 
836             @Override
837             public int getMaxAge()
838             {
839                 return _maxCookieAge;
840             }
841 
842             @Override
843             public String getName()
844             {
845                 return _sessionCookie;
846             }
847 
848             @Override
849             public String getPath()
850             {
851                 return _sessionPath;
852             }
853 
854             @Override
855             public boolean isHttpOnly()
856             {
857                 return _httpOnly;
858             }
859 
860             @Override
861             public boolean isSecure()
862             {
863                 return _secureCookies;
864             }
865 
866             @Override
867             public void setComment(String comment)
868             {
869                 _sessionComment = comment; 
870             }
871 
872             @Override
873             public void setDomain(String domain)
874             {
875                 _sessionDomain=domain;
876             }
877 
878             @Override
879             public void setHttpOnly(boolean httpOnly)
880             {
881                 _httpOnly=httpOnly;
882             }
883 
884             @Override
885             public void setMaxAge(int maxAge)
886             {
887                 _maxCookieAge=maxAge;
888             }
889 
890             @Override
891             public void setName(String name)
892             {
893                 _sessionCookie=name;
894             }
895 
896             @Override
897             public void setPath(String path)
898             {
899                 _sessionPath=path;
900             }
901 
902             @Override
903             public void setSecure(boolean secure)
904             {
905                 _secureCookies=secure;
906             }
907         
908         };
909 
910 
911     /* ------------------------------------------------------------ */
912     /**
913      * @return total amount of time all sessions remained valid
914      */
915     public long getSessionTimeTotal()
916     {
917         return _sessionTimeStats.getTotal();
918     }
919     
920     /* ------------------------------------------------------------ */
921     /**
922      * @return mean amount of time session remained valid
923      */
924     public double getSessionTimeMean()
925     {
926         return _sessionTimeStats.getMean();
927     }
928     
929     /* ------------------------------------------------------------ */
930     /**
931      * @return standard deviation of amount of time session remained valid
932      */
933     public double getSessionTimeStdDev()
934     {
935         return _sessionTimeStats.getStdDev();
936     }
937 
938     /* ------------------------------------------------------------ */
939     /**
940      * @see org.eclipse.jetty.server.SessionManager#isCheckingRemoteSessionIdEncoding()
941      */
942     public boolean isCheckingRemoteSessionIdEncoding()
943     {
944         return _checkingRemoteSessionIdEncoding;
945     }
946 
947     /* ------------------------------------------------------------ */
948     /**
949      * @see org.eclipse.jetty.server.SessionManager#setCheckingRemoteSessionIdEncoding(boolean)
950      */
951     public void setCheckingRemoteSessionIdEncoding(boolean remote)
952     {
953         _checkingRemoteSessionIdEncoding=remote;
954     }
955     
956     /* ------------------------------------------------------------ */
957     /* ------------------------------------------------------------ */
958     /* ------------------------------------------------------------ */
959     /**
960      * Interface that any session wrapper should implement so that
961      * SessionManager may access the Jetty session implementation.
962      *
963      */
964     public interface SessionIf extends HttpSession
965     {
966         public AbstractSession getSession();
967     }
968 
969     public void doSessionAttributeListeners(AbstractSession session, String name, Object old, Object value)
970     {
971         if (!_sessionAttributeListeners.isEmpty())
972         {
973             HttpSessionBindingEvent event=new HttpSessionBindingEvent(session,name,old==null?value:old);
974 
975             for (HttpSessionAttributeListener l : _sessionAttributeListeners)
976             {
977                 if (old==null)
978                     l.attributeAdded(event);
979                 else if (value==null)
980                     l.attributeRemoved(event);
981                 else
982                     l.attributeReplaced(event);
983             }
984         }
985     }
986 }