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