View Javadoc

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  
19  package org.eclipse.jetty.server.session;
20  
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.Enumeration;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import javax.servlet.ServletContext;
32  import javax.servlet.http.HttpServletRequest;
33  import javax.servlet.http.HttpSessionActivationListener;
34  import javax.servlet.http.HttpSessionBindingEvent;
35  import javax.servlet.http.HttpSessionBindingListener;
36  import javax.servlet.http.HttpSessionContext;
37  import javax.servlet.http.HttpSessionEvent;
38  
39  import org.eclipse.jetty.server.SessionManager;
40  import org.eclipse.jetty.util.log.Logger;
41  
42  /**
43   *
44   * <p>
45   * Implements {@link javax.servlet.http.HttpSession} from the <code>javax.servlet</code> package.
46   * </p>
47   *
48   */
49  @SuppressWarnings("deprecation")
50  public abstract class AbstractSession implements AbstractSessionManager.SessionIf
51  {
52      final static Logger LOG = SessionHandler.LOG;
53      public final static String SESSION_KNOWN_ONLY_TO_AUTHENTICATED="org.eclipse.jetty.security.sessionKnownOnlytoAuthenticated";
54      private  String _clusterId; // ID without any node (ie "worker") id appended
55      private  String _nodeId;    // ID of session with node(ie "worker") id appended
56      private final AbstractSessionManager _manager;
57      private final Map<String,Object> _attributes=new HashMap<String, Object>();
58      private boolean _idChanged;
59      private final long _created;
60      private long _cookieSet;
61      private long _accessed;         // the time of the last access
62      private long _lastAccessed;     // the time of the last access excluding this one
63      private boolean _invalid;
64      private boolean _doInvalidate;
65      private long _maxIdleMs;
66      private boolean _newSession;
67      private int _requests;
68  
69  
70  
71      /* ------------------------------------------------------------- */
72      protected AbstractSession(AbstractSessionManager abstractSessionManager, HttpServletRequest request)
73      {
74          _manager = abstractSessionManager;
75  
76          _newSession=true;
77          _created=System.currentTimeMillis();
78          _clusterId=_manager._sessionIdManager.newSessionId(request,_created);
79          _nodeId=_manager._sessionIdManager.getNodeId(_clusterId,request);
80          _accessed=_created;
81          _lastAccessed=_created;
82          _requests=1;
83          _maxIdleMs=_manager._dftMaxIdleSecs>0?_manager._dftMaxIdleSecs*1000L:-1;
84          if (LOG.isDebugEnabled())
85              LOG.debug("new session & id "+_nodeId+" "+_clusterId);
86      }
87  
88      /* ------------------------------------------------------------- */
89      protected AbstractSession(AbstractSessionManager abstractSessionManager, long created, long accessed, String clusterId)
90      {
91          _manager = abstractSessionManager;
92          _created=created;
93          _clusterId=clusterId;
94          _nodeId=_manager._sessionIdManager.getNodeId(_clusterId,null);
95          _accessed=accessed;
96          _lastAccessed=accessed;
97          _requests=1;
98          _maxIdleMs=_manager._dftMaxIdleSecs>0?_manager._dftMaxIdleSecs*1000L:-1;
99          if (LOG.isDebugEnabled())
100             LOG.debug("new session "+_nodeId+" "+_clusterId);
101     }
102 
103     /* ------------------------------------------------------------- */
104     /**
105      * asserts that the session is valid
106      */
107     protected void checkValid() throws IllegalStateException
108     {
109         if (_invalid)
110             throw new IllegalStateException();
111     }
112 
113     /* ------------------------------------------------------------- */
114     @Override
115     public AbstractSession getSession()
116     {
117         return this;
118     }
119 
120     /* ------------------------------------------------------------- */
121     public long getAccessed()
122     {
123         synchronized (this)
124         {
125             return _accessed;
126         }
127     }
128 
129     /* ------------------------------------------------------------- */
130     public Map<String,Object> getAttributeMap()
131     {
132         return _attributes;
133     }
134 
135     /* ------------------------------------------------------------ */
136     @Override
137     public Object getAttribute(String name)
138     {
139         synchronized (this)
140         {
141             checkValid();
142             return _attributes.get(name);
143         }
144     }
145 
146     /* ------------------------------------------------------------ */
147     public int getAttributes()
148     {
149         synchronized (this)
150         {
151             checkValid();
152             return _attributes.size();
153         }
154     }
155 
156     /* ------------------------------------------------------------ */
157     @SuppressWarnings({ "unchecked" })
158     @Override
159     public Enumeration<String> getAttributeNames()
160     {
161         synchronized (this)
162         {
163             checkValid();
164             List<String> names=_attributes==null?Collections.EMPTY_LIST:new ArrayList<String>(_attributes.keySet());
165             return Collections.enumeration(names);
166         }
167     }
168 
169     /* ------------------------------------------------------------ */
170     public Set<String> getNames()
171     {
172         synchronized (this)
173         {
174             return new HashSet<String>(_attributes.keySet());
175         }
176     }
177 
178     /* ------------------------------------------------------------- */
179     public long getCookieSetTime()
180     {
181         return _cookieSet;
182     }
183 
184     /* ------------------------------------------------------------- */
185     @Override
186     public long getCreationTime() throws IllegalStateException
187     {
188         checkValid();
189         return _created;
190     }
191 
192     /* ------------------------------------------------------------ */
193     @Override
194     public String getId() throws IllegalStateException
195     {
196         return _manager._nodeIdInSessionId?_nodeId:_clusterId;
197     }
198 
199     /* ------------------------------------------------------------- */
200     public String getNodeId()
201     {
202         return _nodeId;
203     }
204 
205     /* ------------------------------------------------------------- */
206     public String getClusterId()
207     {
208         return _clusterId;
209     }
210 
211     /* ------------------------------------------------------------- */
212     @Override
213     public long getLastAccessedTime() throws IllegalStateException
214     {
215         checkValid();
216         return _lastAccessed;
217     }
218     
219     /* ------------------------------------------------------------- */
220     public void setLastAccessedTime(long time)
221     {
222         _lastAccessed = time;
223     }
224 
225     /* ------------------------------------------------------------- */
226     @Override
227     public int getMaxInactiveInterval()
228     {
229         return (int)(_maxIdleMs/1000);
230     }
231 
232     /* ------------------------------------------------------------ */
233     /*
234      * @see javax.servlet.http.HttpSession#getServletContext()
235      */
236     @Override
237     public ServletContext getServletContext()
238     {
239         return _manager._context;
240     }
241 
242     /* ------------------------------------------------------------- */
243     @Deprecated
244     @Override
245     public HttpSessionContext getSessionContext() throws IllegalStateException
246     {
247         checkValid();
248         return AbstractSessionManager.__nullSessionContext;
249     }
250 
251     /* ------------------------------------------------------------- */
252     /**
253      * @deprecated As of Version 2.2, this method is replaced by
254      *             {@link #getAttribute}
255      */
256     @Deprecated
257     @Override
258     public Object getValue(String name) throws IllegalStateException
259     {
260         return getAttribute(name);
261     }
262 
263     /* ------------------------------------------------------------- */
264     /**
265      * @deprecated As of Version 2.2, this method is replaced by
266      *             {@link #getAttributeNames}
267      */
268     @Deprecated
269     @Override
270     public String[] getValueNames() throws IllegalStateException
271     {
272         synchronized(this)
273         {
274             checkValid();
275             if (_attributes==null)
276                 return new String[0];
277             String[] a=new String[_attributes.size()];
278             return (String[])_attributes.keySet().toArray(a);
279         }
280     }
281 
282 
283     /* ------------------------------------------------------------ */
284     public void renewId(HttpServletRequest request)
285     {
286         _manager._sessionIdManager.renewSessionId(getClusterId(), getNodeId(), request); 
287         setIdChanged(true);
288     }
289        
290     /* ------------------------------------------------------------- */
291     public SessionManager getSessionManager()
292     {
293         return _manager;
294     }
295 
296     /* ------------------------------------------------------------ */
297     protected void setClusterId (String clusterId)
298     {
299         _clusterId = clusterId;
300     }
301     
302     /* ------------------------------------------------------------ */
303     protected void setNodeId (String nodeId)
304     {
305         _nodeId = nodeId;
306     }
307     
308 
309     /* ------------------------------------------------------------ */
310     protected boolean access(long time)
311     {
312         synchronized(this)
313         {
314             if (_invalid)
315                 return false;
316             _newSession=false;
317             _lastAccessed=_accessed;
318             _accessed=time;
319 
320             if (_maxIdleMs>0 && _lastAccessed>0 && _lastAccessed + _maxIdleMs < time)
321             {
322                 invalidate();
323                 return false;
324             }
325             _requests++;
326             return true;
327         }
328     }
329 
330     /* ------------------------------------------------------------ */
331     protected void complete()
332     {
333         synchronized(this)
334         {
335             _requests--;
336             if (_doInvalidate && _requests<=0  )
337                 doInvalidate();
338         }
339     }
340 
341 
342     /* ------------------------------------------------------------- */
343     protected void timeout() throws IllegalStateException
344     {
345         // remove session from context and invalidate other sessions with same ID.
346         _manager.removeSession(this,true);
347 
348         // Notify listeners and unbind values
349         boolean do_invalidate=false;
350         synchronized (this)
351         {
352             if (!_invalid)
353             {
354                 if (_requests<=0)
355                     do_invalidate=true;
356                 else
357                     _doInvalidate=true;
358             }
359         }
360         if (do_invalidate)
361             doInvalidate();
362     }
363 
364     /* ------------------------------------------------------------- */
365     @Override
366     public void invalidate() throws IllegalStateException
367     {
368         checkValid();
369         // remove session from context and invalidate other sessions with same ID.
370         _manager.removeSession(this,true);
371         doInvalidate();
372     }
373 
374     /* ------------------------------------------------------------- */
375     protected void doInvalidate() throws IllegalStateException
376     {
377         try
378         {
379             LOG.debug("invalidate {}",_clusterId);
380             if (isValid())
381                 clearAttributes();
382         }
383         finally
384         {
385             synchronized (this)
386             {
387                 // mark as invalid
388                 _invalid=true;
389             }
390         }
391     }
392 
393     /* ------------------------------------------------------------- */
394     public void clearAttributes()
395     {
396         while (_attributes!=null && _attributes.size()>0)
397         {
398             ArrayList<String> keys;
399             synchronized(this)
400             {
401                 keys=new ArrayList<String>(_attributes.keySet());
402             }
403 
404             Iterator<String> iter=keys.iterator();
405             while (iter.hasNext())
406             {
407                 String key=(String)iter.next();
408 
409                 Object value;
410                 synchronized(this)
411                 {
412                     value=doPutOrRemove(key,null);
413                 }
414                 unbindValue(key,value);
415 
416                 _manager.doSessionAttributeListeners(this,key,value,null);
417             }
418         }
419         if (_attributes!=null)
420             _attributes.clear();
421     }
422 
423     /* ------------------------------------------------------------- */
424     public boolean isIdChanged()
425     {
426         return _idChanged;
427     }
428 
429     /* ------------------------------------------------------------- */
430     @Override
431     public boolean isNew() throws IllegalStateException
432     {
433         checkValid();
434         return _newSession;
435     }
436 
437     /* ------------------------------------------------------------- */
438     /**
439      * @deprecated As of Version 2.2, this method is replaced by
440      *             {@link #setAttribute}
441      */
442     @Deprecated
443     @Override
444     public void putValue(java.lang.String name, java.lang.Object value) throws IllegalStateException
445     {
446         changeAttribute(name,value);
447     }
448 
449     /* ------------------------------------------------------------ */
450     @Override
451     public void removeAttribute(String name)
452     {
453         setAttribute(name,null);
454     }
455 
456     /* ------------------------------------------------------------- */
457     /**
458      * @deprecated As of Version 2.2, this method is replaced by
459      *             {@link #removeAttribute}
460      */
461     @Deprecated
462     @Override
463     public void removeValue(java.lang.String name) throws IllegalStateException
464     {
465         removeAttribute(name);
466     }
467 
468     /* ------------------------------------------------------------ */
469     protected Object doPutOrRemove(String name, Object value)
470     {
471         return value==null?_attributes.remove(name):_attributes.put(name,value);
472     }
473 
474     /* ------------------------------------------------------------ */
475     protected Object doGet(String name)
476     {
477         return _attributes.get(name);
478     }
479 
480     /* ------------------------------------------------------------ */
481     @Override
482     public void setAttribute(String name, Object value)
483     {
484         changeAttribute(name,value);
485     }
486     
487     /* ------------------------------------------------------------ */
488     /**
489      * @param name
490      * @param value
491      * @deprecated use changeAttribute(String,Object) instead
492      * @return
493      */
494     protected boolean updateAttribute (String name, Object value)
495     {
496         Object old=null;
497         synchronized (this)
498         {
499             checkValid();
500             old=doPutOrRemove(name,value);
501         }
502 
503         if (value==null || !value.equals(old))
504         {
505             if (old!=null)
506                 unbindValue(name,old);
507             if (value!=null)
508                 bindValue(name,value);
509 
510             _manager.doSessionAttributeListeners(this,name,old,value);
511             return true;
512         }
513         return false;
514     }
515     
516     
517     /* ------------------------------------------------------------ */
518     /**
519      * Either set (perhaps replace) or remove the value of the attribute
520      * in the session. The appropriate session attribute listeners are
521      * also called.
522      * 
523      * @param name
524      * @param value
525      * @return
526      */
527     protected Object changeAttribute (String name, Object value)
528     {
529         Object old=null;
530         synchronized (this)
531         {
532             checkValid();
533             old=doPutOrRemove(name,value);
534         }
535 
536         callSessionAttributeListeners(name, value, old);
537 
538         return old;
539     }
540 
541     /* ------------------------------------------------------------ */
542     /**
543      * Call binding and attribute listeners based on the new and old
544      * values of the attribute.
545      * 
546      * @param name name of the attribute
547      * @param newValue  new value of the attribute
548      * @param oldValue previous value of the attribute
549      */
550     protected void callSessionAttributeListeners (String name, Object newValue, Object oldValue)
551     {
552         if (newValue==null || !newValue.equals(oldValue))
553         {
554             if (oldValue!=null)
555                 unbindValue(name,oldValue);
556             if (newValue!=null)
557                 bindValue(name,newValue);
558 
559             _manager.doSessionAttributeListeners(this,name,oldValue,newValue);
560         }
561     }
562 
563     /* ------------------------------------------------------------ */
564     protected void addAttributes(Map<String,Object> map)
565     {
566         _attributes.putAll(map);
567     }
568 
569     /* ------------------------------------------------------------- */
570     public void setIdChanged(boolean changed)
571     {
572         _idChanged=changed;
573     }
574 
575     /* ------------------------------------------------------------- */
576     @Override
577     public void setMaxInactiveInterval(int secs)
578     {
579         _maxIdleMs=(long)secs*1000L;
580     }
581 
582     /* ------------------------------------------------------------- */
583     @Override
584     public String toString()
585     {
586         return this.getClass().getName()+":"+getId()+"@"+hashCode();
587     }
588 
589     /* ------------------------------------------------------------- */
590     /** If value implements HttpSessionBindingListener, call valueBound() */
591     public void bindValue(java.lang.String name, Object value)
592     {
593         if (value!=null&&value instanceof HttpSessionBindingListener)
594             ((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this,name));
595     }
596 
597     /* ------------------------------------------------------------ */
598     public boolean isValid()
599     {
600         return !_invalid;
601     }
602 
603     /* ------------------------------------------------------------- */
604     protected void cookieSet()
605     {
606         synchronized (this)
607         {
608             _cookieSet=_accessed;
609         }
610     }
611 
612     /* ------------------------------------------------------------ */
613     public int getRequests()
614     {
615         synchronized (this)
616         {
617             return _requests;
618         }
619     }
620 
621     /* ------------------------------------------------------------ */
622     public void setRequests(int requests)
623     {
624         synchronized (this)
625         {
626             _requests=requests;
627         }
628     }
629 
630     /* ------------------------------------------------------------- */
631     /** If value implements HttpSessionBindingListener, call valueUnbound() */
632     public void unbindValue(java.lang.String name, Object value)
633     {
634         if (value!=null&&value instanceof HttpSessionBindingListener)
635             ((HttpSessionBindingListener)value).valueUnbound(new HttpSessionBindingEvent(this,name));
636     }
637 
638     /* ------------------------------------------------------------- */
639     public void willPassivate()
640     {
641         synchronized(this)
642         {
643             HttpSessionEvent event = new HttpSessionEvent(this);
644             for (Iterator<Object> iter = _attributes.values().iterator(); iter.hasNext();)
645             {
646                 Object value = iter.next();
647                 if (value instanceof HttpSessionActivationListener)
648                 {
649                     HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
650                     listener.sessionWillPassivate(event);
651                 }
652             }
653         }
654     }
655 
656     /* ------------------------------------------------------------- */
657     public void didActivate()
658     {
659         synchronized(this)
660         {
661             HttpSessionEvent event = new HttpSessionEvent(this);
662             for (Iterator<Object> iter = _attributes.values().iterator(); iter.hasNext();)
663             {
664                 Object value = iter.next();
665                 if (value instanceof HttpSessionActivationListener)
666                 {
667                     HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
668                     listener.sessionDidActivate(event);
669                 }
670             }
671         }
672     }
673 
674 
675 }