View Javadoc

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