View Javadoc

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