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