View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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 unique within cluster
55      private  String _nodeId;    // ID unique within node
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         return _created;
189     }
190 
191     /* ------------------------------------------------------------ */
192     @Override
193     public String getId() throws IllegalStateException
194     {
195         return _manager._nodeIdInSessionId?_nodeId:_clusterId;
196     }
197 
198     /* ------------------------------------------------------------- */
199     public String getNodeId()
200     {
201         return _nodeId;
202     }
203 
204     /* ------------------------------------------------------------- */
205     public String getClusterId()
206     {
207         return _clusterId;
208     }
209 
210     /* ------------------------------------------------------------- */
211     @Override
212     public long getLastAccessedTime() throws IllegalStateException
213     {
214         checkValid();
215         return _lastAccessed;
216     }
217 
218     /* ------------------------------------------------------------- */
219     @Override
220     public int getMaxInactiveInterval()
221     {
222         checkValid();
223         return (int)(_maxIdleMs/1000);
224     }
225 
226     /* ------------------------------------------------------------ */
227     /*
228      * @see javax.servlet.http.HttpSession#getServletContext()
229      */
230     @Override
231     public ServletContext getServletContext()
232     {
233         return _manager._context;
234     }
235 
236     /* ------------------------------------------------------------- */
237     @Deprecated
238     @Override
239     public HttpSessionContext getSessionContext() throws IllegalStateException
240     {
241         checkValid();
242         return AbstractSessionManager.__nullSessionContext;
243     }
244 
245     /* ------------------------------------------------------------- */
246     /**
247      * @deprecated As of Version 2.2, this method is replaced by
248      *             {@link #getAttribute}
249      */
250     @Deprecated
251     @Override
252     public Object getValue(String name) throws IllegalStateException
253     {
254         return getAttribute(name);
255     }
256 
257     /* ------------------------------------------------------------- */
258     /**
259      * @deprecated As of Version 2.2, this method is replaced by
260      *             {@link #getAttributeNames}
261      */
262     @Deprecated
263     @Override
264     public String[] getValueNames() throws IllegalStateException
265     {
266         synchronized(this)
267         {
268             checkValid();
269             if (_attributes==null)
270                 return new String[0];
271             String[] a=new String[_attributes.size()];
272             return (String[])_attributes.keySet().toArray(a);
273         }
274     }
275 
276 
277     /* ------------------------------------------------------------ */
278     public void renewId(HttpServletRequest request)
279     {
280         _manager._sessionIdManager.renewSessionId(getClusterId(), getNodeId(), request); 
281         setIdChanged(true);
282     }
283        
284     /* ------------------------------------------------------------- */
285     public SessionManager getSessionManager()
286     {
287         return _manager;
288     }
289 
290     /* ------------------------------------------------------------ */
291     protected void setClusterId (String clusterId)
292     {
293         _clusterId = clusterId;
294     }
295     
296     /* ------------------------------------------------------------ */
297     protected void setNodeId (String nodeId)
298     {
299         _nodeId = nodeId;
300     }
301     
302 
303     /* ------------------------------------------------------------ */
304     protected boolean access(long time)
305     {
306         synchronized(this)
307         {
308             if (_invalid)
309                 return false;
310             _newSession=false;
311             _lastAccessed=_accessed;
312             _accessed=time;
313 
314             if (_maxIdleMs>0 && _lastAccessed>0 && _lastAccessed + _maxIdleMs < time)
315             {
316                 invalidate();
317                 return false;
318             }
319             _requests++;
320             return true;
321         }
322     }
323 
324     /* ------------------------------------------------------------ */
325     protected void complete()
326     {
327         synchronized(this)
328         {
329             _requests--;
330             if (_doInvalidate && _requests<=0  )
331                 doInvalidate();
332         }
333     }
334 
335 
336     /* ------------------------------------------------------------- */
337     protected void timeout() throws IllegalStateException
338     {
339         // remove session from context and invalidate other sessions with same ID.
340         _manager.removeSession(this,true);
341 
342         // Notify listeners and unbind values
343         synchronized (this)
344         {
345             if (!_invalid)
346             {
347                 if (_requests<=0)
348                     doInvalidate();
349                 else
350                     _doInvalidate=true;
351             }
352         }
353     }
354 
355     /* ------------------------------------------------------------- */
356     @Override
357     public void invalidate() throws IllegalStateException
358     {
359         // remove session from context and invalidate other sessions with same ID.
360         _manager.removeSession(this,true);
361         doInvalidate();
362     }
363 
364     /* ------------------------------------------------------------- */
365     protected void doInvalidate() throws IllegalStateException
366     {
367         try
368         {
369             LOG.debug("invalidate {}",_clusterId);
370             if (isValid())
371                 clearAttributes();
372         }
373         finally
374         {
375             synchronized (this)
376             {
377                 // mark as invalid
378                 _invalid=true;
379             }
380         }
381     }
382 
383     /* ------------------------------------------------------------- */
384     public void clearAttributes()
385     {
386         while (_attributes!=null && _attributes.size()>0)
387         {
388             ArrayList<String> keys;
389             synchronized(this)
390             {
391                 keys=new ArrayList<String>(_attributes.keySet());
392             }
393 
394             Iterator<String> iter=keys.iterator();
395             while (iter.hasNext())
396             {
397                 String key=(String)iter.next();
398 
399                 Object value;
400                 synchronized(this)
401                 {
402                     value=doPutOrRemove(key,null);
403                 }
404                 unbindValue(key,value);
405 
406                 _manager.doSessionAttributeListeners(this,key,value,null);
407             }
408         }
409         if (_attributes!=null)
410             _attributes.clear();
411     }
412 
413     /* ------------------------------------------------------------- */
414     public boolean isIdChanged()
415     {
416         return _idChanged;
417     }
418 
419     /* ------------------------------------------------------------- */
420     @Override
421     public boolean isNew() throws IllegalStateException
422     {
423         checkValid();
424         return _newSession;
425     }
426 
427     /* ------------------------------------------------------------- */
428     /**
429      * @deprecated As of Version 2.2, this method is replaced by
430      *             {@link #setAttribute}
431      */
432     @Deprecated
433     @Override
434     public void putValue(java.lang.String name, java.lang.Object value) throws IllegalStateException
435     {
436         setAttribute(name,value);
437     }
438 
439     /* ------------------------------------------------------------ */
440     @Override
441     public void removeAttribute(String name)
442     {
443         setAttribute(name,null);
444     }
445 
446     /* ------------------------------------------------------------- */
447     /**
448      * @deprecated As of Version 2.2, this method is replaced by
449      *             {@link #removeAttribute}
450      */
451     @Deprecated
452     @Override
453     public void removeValue(java.lang.String name) throws IllegalStateException
454     {
455         removeAttribute(name);
456     }
457 
458     /* ------------------------------------------------------------ */
459     protected Object doPutOrRemove(String name, Object value)
460     {
461         return value==null?_attributes.remove(name):_attributes.put(name,value);
462     }
463 
464     /* ------------------------------------------------------------ */
465     protected Object doGet(String name)
466     {
467         return _attributes.get(name);
468     }
469 
470     /* ------------------------------------------------------------ */
471     @Override
472     public void setAttribute(String name, Object value)
473     {
474         Object old=null;
475         synchronized (this)
476         {
477             checkValid();
478             old=doPutOrRemove(name,value);
479         }
480 
481         if (value==null || !value.equals(old))
482         {
483             if (old!=null)
484                 unbindValue(name,old);
485             if (value!=null)
486                 bindValue(name,value);
487 
488             _manager.doSessionAttributeListeners(this,name,old,value);
489 
490         }
491     }
492 
493     /* ------------------------------------------------------------ */
494     protected void addAttributes(Map<String,Object> map)
495     {
496         _attributes.putAll(map);
497     }
498 
499     /* ------------------------------------------------------------- */
500     public void setIdChanged(boolean changed)
501     {
502         _idChanged=changed;
503     }
504 
505     /* ------------------------------------------------------------- */
506     @Override
507     public void setMaxInactiveInterval(int secs)
508     {
509         _maxIdleMs=(long)secs*1000L;
510     }
511 
512     /* ------------------------------------------------------------- */
513     @Override
514     public String toString()
515     {
516         return this.getClass().getName()+":"+getId()+"@"+hashCode();
517     }
518 
519     /* ------------------------------------------------------------- */
520     /** If value implements HttpSessionBindingListener, call valueBound() */
521     public void bindValue(java.lang.String name, Object value)
522     {
523         if (value!=null&&value instanceof HttpSessionBindingListener)
524             ((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this,name));
525     }
526 
527     /* ------------------------------------------------------------ */
528     public boolean isValid()
529     {
530         return !_invalid;
531     }
532 
533     /* ------------------------------------------------------------- */
534     protected void cookieSet()
535     {
536         synchronized (this)
537         {
538             _cookieSet=_accessed;
539         }
540     }
541 
542     /* ------------------------------------------------------------ */
543     public int getRequests()
544     {
545         synchronized (this)
546         {
547             return _requests;
548         }
549     }
550 
551     /* ------------------------------------------------------------ */
552     public void setRequests(int requests)
553     {
554         synchronized (this)
555         {
556             _requests=requests;
557         }
558     }
559 
560     /* ------------------------------------------------------------- */
561     /** If value implements HttpSessionBindingListener, call valueUnbound() */
562     public void unbindValue(java.lang.String name, Object value)
563     {
564         if (value!=null&&value instanceof HttpSessionBindingListener)
565             ((HttpSessionBindingListener)value).valueUnbound(new HttpSessionBindingEvent(this,name));
566     }
567 
568     /* ------------------------------------------------------------- */
569     public void willPassivate()
570     {
571         synchronized(this)
572         {
573             HttpSessionEvent event = new HttpSessionEvent(this);
574             for (Iterator<Object> iter = _attributes.values().iterator(); iter.hasNext();)
575             {
576                 Object value = iter.next();
577                 if (value instanceof HttpSessionActivationListener)
578                 {
579                     HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
580                     listener.sessionWillPassivate(event);
581                 }
582             }
583         }
584     }
585 
586     /* ------------------------------------------------------------- */
587     public void didActivate()
588     {
589         synchronized(this)
590         {
591             HttpSessionEvent event = new HttpSessionEvent(this);
592             for (Iterator<Object> iter = _attributes.values().iterator(); iter.hasNext();)
593             {
594                 Object value = iter.next();
595                 if (value instanceof HttpSessionActivationListener)
596                 {
597                     HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
598                     listener.sessionDidActivate(event);
599                 }
600             }
601         }
602     }
603 
604 
605 }