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