View Javadoc
1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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  
19  
20  package org.eclipse.jetty.server.session;
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.Enumeration;
25  import java.util.Iterator;
26  import java.util.Set;
27  import java.util.concurrent.TimeUnit;
28  import java.util.concurrent.TimeoutException;
29  
30  import javax.servlet.ServletContext;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpSessionActivationListener;
33  import javax.servlet.http.HttpSessionBindingEvent;
34  import javax.servlet.http.HttpSessionBindingListener;
35  import javax.servlet.http.HttpSessionContext;
36  import javax.servlet.http.HttpSessionEvent;
37  
38  import org.eclipse.jetty.io.IdleTimeout;
39  import org.eclipse.jetty.util.log.Log;
40  import org.eclipse.jetty.util.log.Logger;
41  import org.eclipse.jetty.util.thread.Locker;
42  import org.eclipse.jetty.util.thread.Locker.Lock;
43  
44  
45  
46  
47  /**
48   * Session
49   *
50   * A heavy-weight Session object representing a HttpSession. Session objects
51   * relating to a context are kept in a {@link SessionCache}. The purpose of
52   * the SessionCache is to keep the working set of Session objects in memory
53   * so that they may be accessed quickly, and facilitate the sharing of a
54   * Session object amongst multiple simultaneous requests referring to the
55   * same session id.
56   * 
57   * The {@link SessionHandler} coordinates 
58   * the lifecycle of Session objects with the help of the SessionCache.
59   * 
60   * @see SessionHandler
61   * @see org.eclipse.jetty.server.SessionIdManager
62   */
63  public class Session implements SessionHandler.SessionIf
64  {
65      private  final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
66      
67      
68      /**
69       * 
70       */
71      public final static String SESSION_CREATED_SECURE="org.eclipse.jetty.security.sessionCreatedSecure";
72      
73      
74      /**
75       * State
76       *
77       * Validity states of a session
78       */
79      public enum State {VALID, INVALID, INVALIDATING};
80      
81      
82      
83  
84      
85      protected SessionData _sessionData; //the actual data associated with a session
86      protected SessionHandler _handler; //the manager of the session
87      protected String _extendedId; //the _id plus the worker name
88      protected long _requests;
89      protected boolean _idChanged; 
90      protected boolean _newSession;
91      protected State _state = State.VALID; //state of the session:valid,invalid or being invalidated
92      protected Locker _lock = new Locker(); //sync lock
93      protected boolean _resident = false;
94      protected SessionInactivityTimeout _sessionInactivityTimer = null;
95      
96      
97  
98      /* ------------------------------------------------------------- */
99      /**
100      * SessionInactivityTimeout
101      * 
102      * Each Session has a timer associated with it that fires whenever 
103      * it has been idle (ie not referenced by a request) for a 
104      * configurable amount of time, or the Session expires. 
105      * 
106      * @see SessionCache
107      *
108      */
109     public class SessionInactivityTimeout extends IdleTimeout
110     {
111         /**
112          * 
113          */
114         public SessionInactivityTimeout()
115         {
116             super(getSessionHandler().getScheduler());
117         }
118 
119         /** 
120          * @see org.eclipse.jetty.io.IdleTimeout#onIdleExpired(java.util.concurrent.TimeoutException)
121          */
122         @Override
123         protected void onIdleExpired(TimeoutException timeout)
124         {
125             //called when the timer goes off
126             if (LOG.isDebugEnabled()) LOG.debug("Timer expired for session {}", getId());
127            getSessionHandler().sessionInactivityTimerExpired(Session.this);
128         }
129 
130         /** 
131          * @see org.eclipse.jetty.io.IdleTimeout#isOpen()
132          */
133         @Override
134         public boolean isOpen()
135         {
136             // Called to determine if the timer should be reset
137             // True if:
138             // 1. the session is still valid
139             // BUT if passivated out to disk, do we really want this timer to keep going off?
140             try (Lock lock = _lock.lockIfNotHeld())
141             {
142                 return isValid() && isResident();
143             }
144         }
145 
146         /** 
147          * @see org.eclipse.jetty.io.IdleTimeout#setIdleTimeout(long)
148          */
149         @Override
150         public void setIdleTimeout(long idleTimeout)
151         {
152             if (LOG.isDebugEnabled()) LOG.debug("setIdleTimeout called: "+idleTimeout);
153             super.setIdleTimeout(idleTimeout);
154         }
155 
156     }
157 
158 
159 
160     /* ------------------------------------------------------------- */
161     /**
162      * Create a new session
163      * @param handler the SessionHandler that manages this session
164      * @param request the request the session should be based on
165      * @param data the session data
166      */
167     public Session (SessionHandler handler, HttpServletRequest request, SessionData data)
168     {
169         _handler = handler;
170         _sessionData = data;
171         _newSession = true;
172         _sessionData.setDirty(true);
173         _requests = 1; //access will not be called on this new session, but we are obviously in a request
174     }
175     
176     
177 
178     /* ------------------------------------------------------------- */
179     /**
180      * Re-inflate an existing session from some eg persistent store.
181      * 
182      * @param handler the SessionHandler managing the session
183      * @param data the session data
184      */
185     public Session (SessionHandler handler, SessionData data)
186     {
187         _handler = handler;
188         _sessionData = data;
189     }
190     
191 
192     /* ------------------------------------------------------------- */
193     /**
194      *  Returns the current number of requests that are active in the
195      *  Session.
196      *  
197      * @return the number of active requests for this session
198      */
199     public long getRequests()
200     {
201         try (Lock lock = _lock.lockIfNotHeld())
202         {
203             return _requests;
204         }
205     }
206     
207     
208 
209     
210 
211     /* ------------------------------------------------------------- */
212     public void setExtendedId (String extendedId)
213     {
214         _extendedId = extendedId;
215     }
216     
217     /* ------------------------------------------------------------- */
218     protected void cookieSet()
219     {
220         try (Lock lock = _lock.lockIfNotHeld())
221         {
222            _sessionData.setCookieSet(_sessionData.getAccessed());
223         }
224     }
225     /* ------------------------------------------------------------ */
226     protected boolean access(long time)
227     {
228         try (Lock lock = _lock.lockIfNotHeld())
229         {
230             if (!isValid())
231                 return false;
232             _newSession=false;
233             long lastAccessed = _sessionData.getAccessed();
234             _sessionData.setAccessed(time);
235             _sessionData.setLastAccessed(lastAccessed);
236            _sessionData.calcAndSetExpiry(time);
237             if (isExpiredAt(time))
238             {
239                 invalidate();
240                 return false;
241             }
242             _requests++;
243             return true;
244         }
245     }
246     
247     /* ------------------------------------------------------------ */
248     protected void complete()
249     {
250         try (Lock lock = _lock.lockIfNotHeld())
251         {
252             _requests--;
253         }
254     }
255 
256     
257 
258     /* ------------------------------------------------------------- */
259     /** Check to see if session has expired as at the time given.
260      * 
261      * @param time the time since the epoch in ms
262      * @return true if expired
263      */
264     protected boolean isExpiredAt(long time)
265     {
266         try (Lock lock = _lock.lockIfNotHeld())
267         {
268             return _sessionData.isExpiredAt(time);
269         }
270     }
271     
272     
273     /* ------------------------------------------------------------- */
274     /** Check if the Session has been idle longer than a number of seconds.
275      * 
276      * @param sec the number of seconds
277      * @return true if the session has been idle longer than the interval
278      */
279     protected boolean isIdleLongerThan (int sec)
280     {
281         long now = System.currentTimeMillis();
282         try (Lock lock = _lock.lockIfNotHeld())
283         {
284             return ((_sessionData.getAccessed() + (sec*1000)) <= now);
285         }
286     }
287     
288   
289 
290     /* ------------------------------------------------------------ */
291     /**
292      * Call binding and attribute listeners based on the new and old
293      * values of the attribute.
294      * 
295      * @param name name of the attribute
296      * @param newValue  new value of the attribute
297      * @param oldValue previous value of the attribute
298      */
299     protected void callSessionAttributeListeners (String name, Object newValue, Object oldValue)
300     {
301         if (newValue==null || !newValue.equals(oldValue))
302         {
303             if (oldValue!=null)
304                 unbindValue(name,oldValue);
305             if (newValue!=null)
306                 bindValue(name,newValue);
307 
308             if (_handler == null)
309                 throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
310             _handler.doSessionAttributeListeners(this,name,oldValue,newValue);
311         }
312     }
313 
314     
315     
316     /* ------------------------------------------------------------- */
317     /**
318      * Unbind value if value implements {@link HttpSessionBindingListener} (calls {@link HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)}) 
319      * @param name the name with which the object is bound or unbound  
320      * @param value the bound value
321      */
322     public void unbindValue(java.lang.String name, Object value)
323     {
324         if (value!=null&&value instanceof HttpSessionBindingListener)
325             ((HttpSessionBindingListener)value).valueUnbound(new HttpSessionBindingEvent(this,name));
326     }
327     
328 
329     /* ------------------------------------------------------------- */
330     /** 
331      * Bind value if value implements {@link HttpSessionBindingListener} (calls {@link HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)}) 
332      * @param name the name with which the object is bound or unbound  
333      * @param value the bound value
334      */
335     public void bindValue(java.lang.String name, Object value)
336     {
337         if (value!=null&&value instanceof HttpSessionBindingListener)
338             ((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this,name));
339     }
340 
341 
342     /* ------------------------------------------------------------- */
343     /**
344      * Call the activation listeners. This must be called holding the
345      * lock.
346      */
347     public void didActivate()
348     {
349         HttpSessionEvent event = new HttpSessionEvent(this);
350         for (Iterator<String> iter = _sessionData.getKeys().iterator(); iter.hasNext();)
351         {
352             Object value = _sessionData.getAttribute(iter.next());
353             if (value instanceof HttpSessionActivationListener)
354             {
355                 HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
356                 listener.sessionDidActivate(event);
357             }
358         }
359     }
360 
361 
362     /* ------------------------------------------------------------- */
363     /**
364      * Call the passivation listeners. This must be called holding the
365      * lock
366      */
367     public void willPassivate()
368     {
369         HttpSessionEvent event = new HttpSessionEvent(this);
370         for (Iterator<String> iter = _sessionData.getKeys().iterator(); iter.hasNext();)
371         {
372             Object value = _sessionData.getAttribute(iter.next());
373             if (value instanceof HttpSessionActivationListener)
374             {
375                 HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
376                 listener.sessionWillPassivate(event);
377             }
378         }
379     }
380 
381     /* ------------------------------------------------------------ */
382     public boolean isValid()
383     {
384         try (Lock lock = _lock.lockIfNotHeld())
385         {
386             return _state==State.VALID;
387         }
388     }
389 
390 
391     /* ------------------------------------------------------------- */
392     public long getCookieSetTime()
393     {
394         try (Lock lock = _lock.lockIfNotHeld())
395         {
396             return _sessionData.getCookieSet();
397         }
398     }
399 
400 
401     /* ------------------------------------------------------------- */
402     @Override
403     public long getCreationTime() throws IllegalStateException
404     {
405         try (Lock lock = _lock.lockIfNotHeld())
406         {
407             checkValidForRead();
408             return _sessionData.getCreated();
409         }
410     }
411 
412 
413 
414     /** 
415      * @see javax.servlet.http.HttpSession#getId()
416      */
417     @Override
418     public String getId()
419     {
420         try (Lock lock = _lock.lockIfNotHeld())
421         {
422             return _sessionData.getId();
423         }
424     }
425 
426     
427     public String getExtendedId()
428     {
429         return _extendedId;
430     }
431     
432     public String getContextPath()
433     {
434         return _sessionData.getContextPath();
435     }
436 
437     
438     public String getVHost ()
439     {
440         return _sessionData.getVhost();
441     }
442     
443 
444     /** 
445      * @see javax.servlet.http.HttpSession#getLastAccessedTime()
446      */
447     @Override
448     public long getLastAccessedTime()
449     {
450         try (Lock lock = _lock.lockIfNotHeld())
451         {
452             return _sessionData.getLastAccessed();
453         }
454     }
455 
456     /** 
457      * @see javax.servlet.http.HttpSession#getServletContext()
458      */
459     @Override
460     public ServletContext getServletContext()
461     {
462         if (_handler == null)
463             throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
464        return _handler._context;
465     }
466 
467     /** 
468      * @see javax.servlet.http.HttpSession#setMaxInactiveInterval(int)
469      */
470     @Override
471     public void setMaxInactiveInterval(int secs)
472     {
473         try (Lock lock = _lock.lockIfNotHeld())
474         {
475             _sessionData.setMaxInactiveMs((long)secs*1000L);  
476             _sessionData.calcAndSetExpiry();
477             _sessionData.setDirty(true);
478             updateInactivityTimer();
479             if (LOG.isDebugEnabled())
480             {
481                 if (secs <= 0)
482                     LOG.debug("Session {} is now immortal (maxInactiveInterval={})", _sessionData.getId(), secs);
483                 else
484                     LOG.debug("Session {} maxInactiveInterval={}", _sessionData.getId(), secs);
485             }
486         }
487     }
488     
489     
490     /**
491      * Set the inactivity timer to the smaller of the session maxInactivity
492      * (ie session-timeout from web.xml), or the inactive eviction time.
493      */
494     public void updateInactivityTimer ()
495     {
496         try (Lock lock = _lock.lockIfNotHeld())
497         {
498             if (LOG.isDebugEnabled())LOG.debug("updateInactivityTimer");
499 
500             long maxInactive =  _sessionData.getMaxInactiveMs();        
501             int evictionPolicy = getSessionHandler().getSessionCache().getEvictionPolicy();
502 
503             if (maxInactive <= 0)
504             {
505                 //sessions are immortal, they never expire
506                 if (evictionPolicy < SessionCache.EVICT_ON_INACTIVITY)
507                 {
508                     //we do not want to evict inactive sessions
509                     setInactivityTimer(-1L);
510                     if (LOG.isDebugEnabled()) LOG.debug("Session is immortal && no inactivity eviction: timer cancelled");
511                 }
512                 else
513                 {
514                     //sessions are immortal but we want to evict after inactivity
515                     setInactivityTimer(TimeUnit.SECONDS.toMillis(evictionPolicy));
516                     if (LOG.isDebugEnabled()) LOG.debug("Session is immortal; evict after {} sec inactivity", evictionPolicy);
517                 }                    
518             }
519             else
520             {
521                 //sessions are not immortal
522                 if (evictionPolicy < SessionCache.EVICT_ON_INACTIVITY)
523                 {
524                     //don't want to evict inactive sessions, set the timer for the session's maxInactive setting
525                     setInactivityTimer(_sessionData.getMaxInactiveMs());
526                     if (LOG.isDebugEnabled()) LOG.debug("No inactive session eviction");
527                 }
528                 else
529                 {
530                     //set the time to the lesser of the session's maxInactive and eviction timeout
531                     setInactivityTimer(Math.min(maxInactive, TimeUnit.SECONDS.toMillis(evictionPolicy)));
532                     if (LOG.isDebugEnabled()) LOG.debug("Inactivity timer set to lesser of maxInactive={} and inactivityEvict={}", maxInactive, evictionPolicy);
533                 }
534             }
535         }
536     }
537     
538     /**
539      * Set the inactivity timer
540      * 
541      * @param ms value in millisec, -1 disables it
542      */
543     private void setInactivityTimer (long ms)
544     {
545         if (_sessionInactivityTimer == null)
546             _sessionInactivityTimer = new SessionInactivityTimeout();
547         _sessionInactivityTimer.setIdleTimeout(ms);
548     }
549 
550 
551     /**
552      * 
553      */
554     public void stopInactivityTimer ()
555     {
556         try (Lock lock = _lock.lockIfNotHeld())
557         {
558             if (_sessionInactivityTimer != null)
559             {
560                 _sessionInactivityTimer.setIdleTimeout(-1);
561                 _sessionInactivityTimer = null;
562                 if (LOG.isDebugEnabled()) LOG.debug("Session timer stopped");
563             }
564         }
565     }
566 
567     /** 
568      * @see javax.servlet.http.HttpSession#getMaxInactiveInterval()
569      */
570     @Override
571     public int getMaxInactiveInterval()
572     {
573         try (Lock lock = _lock.lockIfNotHeld())
574         {
575             return (int)(_sessionData.getMaxInactiveMs()/1000);
576         }
577     }
578 
579     /** 
580      * @see javax.servlet.http.HttpSession#getSessionContext()
581      */
582     @Override
583     @Deprecated
584     public HttpSessionContext getSessionContext()
585     {
586         checkValidForRead();
587         return SessionHandler.__nullSessionContext;
588     }
589 
590     
591     public SessionHandler getSessionHandler()
592     {
593         return _handler;
594     }
595     
596     
597     /* ------------------------------------------------------------- */
598     /**
599      * Check that the session can be modified.
600      * 
601      * @throws IllegalStateException if the session is invalid
602      */
603     protected void checkValidForWrite() throws IllegalStateException
604     {    
605         checkLocked();
606 
607         if (_state != State.VALID)
608             throw new IllegalStateException("Not valid for write: id="+_sessionData.getId()+" created="+_sessionData.getCreated()+" accessed="+_sessionData.getAccessed()+" lastaccessed="+_sessionData.getLastAccessed()+" maxInactiveMs="+_sessionData.getMaxInactiveMs()+" expiry="+_sessionData.getExpiry());
609         
610         if (!isResident())
611             throw new IllegalStateException("Not valid for write: id="+_sessionData.getId()+" not resident");
612     }
613     
614     
615     /* ------------------------------------------------------------- */
616     /**
617      * Chech that the session data can be read.
618      * 
619      * @throws IllegalStateException if the session is invalid
620      */
621     protected void checkValidForRead () throws IllegalStateException
622     {
623         checkLocked();
624         
625         if (_state == State.INVALID)
626             throw new IllegalStateException("Invalid for read: id="+_sessionData.getId()+" created="+_sessionData.getCreated()+" accessed="+_sessionData.getAccessed()+" lastaccessed="+_sessionData.getLastAccessed()+" maxInactiveMs="+_sessionData.getMaxInactiveMs()+" expiry="+_sessionData.getExpiry());
627         
628         if (!isResident())
629             throw new IllegalStateException("Invalid for read: id="+_sessionData.getId()+" not resident");
630     }
631     
632     
633     /* ------------------------------------------------------------- */
634     protected void checkLocked ()
635     throws IllegalStateException
636     {
637         if (!_lock.isLocked())
638             throw new IllegalStateException("Session not locked");
639     }
640 
641     /** 
642      * @see javax.servlet.http.HttpSession#getAttribute(java.lang.String)
643      */
644     @Override
645     public Object getAttribute(String name)
646     {
647         try (Lock lock = _lock.lockIfNotHeld())
648         {
649             checkValidForRead();
650             return _sessionData.getAttribute(name);
651         }
652     }
653 
654     /** 
655      * @see javax.servlet.http.HttpSession#getValue(java.lang.String)
656      */
657     @Override
658     @Deprecated
659     public Object getValue(String name)
660     {
661         try (Lock lock = _lock.lockIfNotHeld())
662         { 
663             return _sessionData.getAttribute(name);
664         }
665     }
666 
667     /** 
668      * @see javax.servlet.http.HttpSession#getAttributeNames()
669      */
670     @Override
671     public Enumeration<String> getAttributeNames()
672     {
673         try (Lock lock = _lock.lockIfNotHeld())
674         {
675             checkValidForRead();
676             final Iterator<String> itor = _sessionData.getKeys().iterator();
677             return new Enumeration<String> ()
678             {
679 
680                 @Override
681                 public boolean hasMoreElements()
682                 {
683                     return itor.hasNext();
684                 }
685 
686                 @Override
687                 public String nextElement()
688                 {
689                     return itor.next();
690                 }
691 
692             };
693         }
694     }
695 
696 
697 
698 
699     /* ------------------------------------------------------------ */
700     public int getAttributes()
701     {
702         return _sessionData.getKeys().size();
703     }
704 
705 
706 
707 
708     /* ------------------------------------------------------------ */
709     public Set<String> getNames()
710     {
711         return Collections.unmodifiableSet(_sessionData.getKeys());
712     }
713 
714 
715     /* ------------------------------------------------------------- */
716     /**
717      * @deprecated As of Version 2.2, this method is replaced by
718      *             {@link #getAttributeNames}
719      */
720     @Deprecated
721     @Override
722     public String[] getValueNames() throws IllegalStateException
723     {
724         try (Lock lock = _lock.lockIfNotHeld())
725         {
726             checkValidForRead();
727             Iterator<String> itor = _sessionData.getKeys().iterator();
728             if (!itor.hasNext())
729                 return new String[0];
730             ArrayList<String> names = new ArrayList<String>();
731             while (itor.hasNext())
732                 names.add(itor.next());
733             return names.toArray(new String[names.size()]);
734         }
735     }
736 
737     /* ------------------------------------------------------------- */
738     /** 
739      * @see javax.servlet.http.HttpSession#setAttribute(java.lang.String, java.lang.Object)
740      */
741     @Override
742     public void setAttribute(String name, Object value)
743     {
744         Object old=null;
745         try (Lock lock = _lock.lockIfNotHeld())
746         {
747             //if session is not valid, don't accept the set
748             checkValidForWrite();
749             old=_sessionData.setAttribute(name,value);
750         }
751         if (value == null && old == null)
752             return; //if same as remove attribute but attribute was already removed, no change
753         callSessionAttributeListeners(name, value, old);
754     }
755     
756     
757     
758     /* ------------------------------------------------------------- */
759     /** 
760      * @see javax.servlet.http.HttpSession#putValue(java.lang.String, java.lang.Object)
761      */
762     @Override
763     @Deprecated
764     public void putValue(String name, Object value)
765     {
766         setAttribute(name,value);
767     }
768     
769     
770     
771     /* ------------------------------------------------------------- */
772     /** 
773      * @see javax.servlet.http.HttpSession#removeAttribute(java.lang.String)
774      */
775     @Override
776     public void removeAttribute(String name)
777     {
778        setAttribute(name, null);
779     }
780     
781     
782     
783     /* ------------------------------------------------------------- */
784     /** 
785      * @see javax.servlet.http.HttpSession#removeValue(java.lang.String)
786      */
787     @Override
788     @Deprecated
789     public void removeValue(String name)
790     {
791        setAttribute(name, null);
792     }
793 
794     /* ------------------------------------------------------------ */
795     /** Force a change to the id of a session.
796      * 
797      * @param request the Request associated with the call to change id.
798      */
799     public void renewId(HttpServletRequest request)
800     {
801         if (_handler == null)
802             throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
803         
804         String id = null;
805         String extendedId = null;
806         try (Lock lock = _lock.lockIfNotHeld())
807         {
808             checkValidForWrite(); //don't renew id on a session that is not valid
809             id = _sessionData.getId(); //grab the values as they are now
810             extendedId = getExtendedId();
811         }
812         
813         _handler._sessionIdManager.renewSessionId(id, extendedId, request); 
814         setIdChanged(true);
815     }
816        
817    
818     /* ------------------------------------------------------------- */
819     /** Called by users to invalidate a session, or called by the
820      * access method as a request enters the session if the session
821      * has expired, or called by manager as a result of scavenger
822      * expiring session
823      * 
824      * @see javax.servlet.http.HttpSession#invalidate()
825      */
826     @Override
827     public void invalidate()
828     {
829         if (_handler == null)
830             throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
831 
832         boolean result = false;
833 
834         try (Lock lock = _lock.lockIfNotHeld())
835         {
836             switch (_state)
837             {
838                 case INVALID:
839                 {
840                     throw new IllegalStateException(); //spec does not allow invalidate of already invalid session
841                 }
842                 case VALID:
843                 {
844                     //only first change from valid to invalidating should be actionable
845                     result = true;
846                     _state = State.INVALIDATING;
847                     break;
848                 }
849                 default:
850                 {
851                     LOG.info("Session {} already being invalidated", _sessionData.getId());
852                 }
853             }
854         }
855 
856         try
857         {
858             //if the session was not already invalid, or in process of being invalidated, do invalidate
859             if (result)
860             {
861                 //tell id mgr to remove session from all other contexts
862                 _handler.getSessionIdManager().invalidateAll(_sessionData.getId());
863             }
864         }
865         catch (Exception e)
866         {
867             LOG.warn(e);
868         }
869     }
870 
871     /* ------------------------------------------------------------- */
872     /** Grab the lock on the session
873      * @return the lock
874      */
875     public Lock lock ()
876     {
877         return _lock.lock();
878     }
879 
880     /* ------------------------------------------------------------- */
881     /** Call HttpSessionAttributeListeners as part of invalidating
882      * a Session.
883      * 
884      * @throws IllegalStateException
885      */
886     protected void doInvalidate() throws IllegalStateException
887     {
888         try (Lock lock = _lock.lockIfNotHeld())
889         {
890             try
891             {
892                 if (LOG.isDebugEnabled())
893                     LOG.debug("invalidate {}",_sessionData.getId());
894                 if (isValid())
895                 {
896                     Set<String> keys = null;
897 
898                     do
899                     {
900                         keys = _sessionData.getKeys();
901                         for (String key:keys)
902                         {
903                             Object  old=_sessionData.setAttribute(key,null);
904                             if (old == null)
905                                 return; //if same as remove attribute but attribute was already removed, no change
906                             callSessionAttributeListeners(key, null, old);
907                         }
908 
909                     }
910                     while (!keys.isEmpty());
911                 }
912             }
913             finally
914             {
915                 // mark as invalid
916                 _state = State.INVALID;
917             }
918         }
919     }
920 
921     /* ------------------------------------------------------------- */
922     @Override
923     public boolean isNew() throws IllegalStateException
924     {
925         try (Lock lock = _lock.lockIfNotHeld())
926         {
927             checkValidForRead();
928             return _newSession;
929         }
930     }
931     
932     
933 
934     /* ------------------------------------------------------------- */
935     public void setIdChanged(boolean changed)
936     {
937         try (Lock lock = _lock.lockIfNotHeld())
938         {
939             _idChanged=changed;
940         }
941     }
942     
943     
944     /* ------------------------------------------------------------- */
945     public boolean isIdChanged ()
946     {
947         try (Lock lock = _lock.lockIfNotHeld())
948         {
949             return _idChanged;
950         }
951     }
952     
953     
954     /* ------------------------------------------------------------- */
955     @Override
956     public Session getSession()
957     {
958         // TODO why is this used
959         return this;
960     }
961   
962     /* ------------------------------------------------------------- */
963     protected SessionData getSessionData()
964     {
965         return _sessionData;
966     }
967 
968     /* ------------------------------------------------------------- */
969     public void setResident (boolean resident)
970     {
971         _resident = resident;
972     }
973     
974     /* ------------------------------------------------------------- */
975     public boolean isResident ()
976     {
977         return _resident;
978     }
979     
980 }