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