View Javadoc

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