View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 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.Enumeration;
23  import java.util.Iterator;
24  import java.util.Map;
25  import java.util.Set;
26  import javax.servlet.ServletContext;
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpSessionActivationListener;
29  import javax.servlet.http.HttpSessionBindingEvent;
30  import javax.servlet.http.HttpSessionBindingListener;
31  import javax.servlet.http.HttpSessionContext;
32  import javax.servlet.http.HttpSessionEvent;
33  
34  import org.eclipse.jetty.server.SessionManager;
35  import org.eclipse.jetty.util.log.Logger;
36  
37  /**
38   *
39   * <p>
40   * Implements {@link javax.servlet.http.HttpSession} from the <code>javax.servlet</code> package.
41   * </p>
42   *
43   */
44  @SuppressWarnings("deprecation")
45  public abstract class AbstractSession implements AbstractSessionManager.SessionIf
46  {
47      final static Logger LOG = SessionHandler.LOG;
48      public final static String SESSION_KNOWN_ONLY_TO_AUTHENTICATED="org.eclipse.jetty.security.sessionKnownOnlytoAuthenticated";
49      private  String _clusterId; // ID without any node (ie "worker") id appended
50      private  String _nodeId;    // ID of session with node(ie "worker") id appended
51      private final AbstractSessionManager _manager;
52      private boolean _idChanged;
53      private final long _created;
54      private long _cookieSet;
55      private long _accessed;         // the time of the last access
56      private long _lastAccessed;     // the time of the last access excluding this one
57      private boolean _invalid;
58      private boolean _doInvalidate;
59      private long _maxIdleMs;
60      private boolean _newSession;
61      private int _requests;
62  
63  
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     /** Check to see if session has expired as at the time given.
109      * @param time
110      * @return
111      */
112     protected boolean checkExpiry(long time)
113     {
114         if (_maxIdleMs>0 && _lastAccessed>0 && _lastAccessed + _maxIdleMs < time)
115             return true;
116         return false;
117     }
118 
119     /* ------------------------------------------------------------- */
120     @Override
121     public AbstractSession getSession()
122     {
123         return this;
124     }
125 
126     /* ------------------------------------------------------------- */
127     public long getAccessed()
128     {
129         synchronized (this)
130         {
131             return _accessed;
132         }
133     }
134 
135     /* ------------------------------------------------------------- */
136     public abstract Map<String,Object> getAttributeMap();
137 
138 
139  
140     
141 
142     /* ------------------------------------------------------------ */
143     public abstract int getAttributes();
144   
145 
146  
147 
148     /* ------------------------------------------------------------ */
149     public abstract Set<String> getNames();
150   
151 
152     /* ------------------------------------------------------------- */
153     public long getCookieSetTime()
154     {
155         return _cookieSet;
156     }
157 
158     /* ------------------------------------------------------------- */
159     @Override
160     public long getCreationTime() throws IllegalStateException
161     {
162         checkValid();
163         return _created;
164     }
165 
166     /* ------------------------------------------------------------ */
167     @Override
168     public String getId() throws IllegalStateException
169     {
170         return _manager._nodeIdInSessionId?_nodeId:_clusterId;
171     }
172 
173     /* ------------------------------------------------------------- */
174     public String getNodeId()
175     {
176         return _nodeId;
177     }
178 
179     /* ------------------------------------------------------------- */
180     public String getClusterId()
181     {
182         return _clusterId;
183     }
184 
185     /* ------------------------------------------------------------- */
186     @Override
187     public long getLastAccessedTime() throws IllegalStateException
188     {
189         checkValid();
190         return _lastAccessed;
191     }
192     
193     /* ------------------------------------------------------------- */
194     public void setLastAccessedTime(long time)
195     {
196         _lastAccessed = time;
197     }
198 
199     /* ------------------------------------------------------------- */
200     @Override
201     public int getMaxInactiveInterval()
202     {
203         return (int)(_maxIdleMs/1000);
204     }
205 
206     /* ------------------------------------------------------------ */
207     /*
208      * @see javax.servlet.http.HttpSession#getServletContext()
209      */
210     @Override
211     public ServletContext getServletContext()
212     {
213         return _manager._context;
214     }
215 
216     /* ------------------------------------------------------------- */
217     @Deprecated
218     @Override
219     public HttpSessionContext getSessionContext() throws IllegalStateException
220     {
221         checkValid();
222         return AbstractSessionManager.__nullSessionContext;
223     }
224 
225     /* ------------------------------------------------------------- */
226     /**
227      * @deprecated As of Version 2.2, this method is replaced by
228      *             {@link #getAttribute}
229      */
230     @Deprecated
231     @Override
232     public Object getValue(String name) throws IllegalStateException
233     {
234         return getAttribute(name);
235     }
236 
237  
238 
239     /* ------------------------------------------------------------ */
240     public void renewId(HttpServletRequest request)
241     {
242         _manager._sessionIdManager.renewSessionId(getClusterId(), getNodeId(), request); 
243         setIdChanged(true);
244     }
245        
246     /* ------------------------------------------------------------- */
247     public SessionManager getSessionManager()
248     {
249         return _manager;
250     }
251 
252     /* ------------------------------------------------------------ */
253     protected void setClusterId (String clusterId)
254     {
255         _clusterId = clusterId;
256     }
257     
258     /* ------------------------------------------------------------ */
259     protected void setNodeId (String nodeId)
260     {
261         _nodeId = nodeId;
262     }
263     
264 
265     /* ------------------------------------------------------------ */
266     protected boolean access(long time)
267     {
268         synchronized(this)
269         {
270             if (_invalid)
271                 return false;
272             _newSession=false;
273             _lastAccessed=_accessed;
274             _accessed=time;
275 
276             if (checkExpiry(time))
277             {
278                 invalidate();
279                 return false;
280             }
281             _requests++;
282             return true;
283         }
284     }
285 
286     /* ------------------------------------------------------------ */
287     protected void complete()
288     {
289         synchronized(this)
290         {
291             _requests--;
292             if (_doInvalidate && _requests<=0  )
293                 doInvalidate();
294         }
295     }
296 
297 
298     /* ------------------------------------------------------------- */
299     protected void timeout() throws IllegalStateException
300     {
301         // remove session from context and invalidate other sessions with same ID.
302         _manager.removeSession(this,true);
303 
304         // Notify listeners and unbind values
305         boolean do_invalidate=false;
306         synchronized (this)
307         {
308             if (!_invalid)
309             {
310                 if (_requests<=0)
311                     do_invalidate=true;
312                 else
313                     _doInvalidate=true;
314             }
315         }
316         if (do_invalidate)
317             doInvalidate();
318     }
319 
320     /* ------------------------------------------------------------- */
321     @Override
322     public void invalidate() throws IllegalStateException
323     {
324         checkValid();
325         // remove session from context and invalidate other sessions with same ID.
326         _manager.removeSession(this,true);
327         doInvalidate();
328     }
329 
330     /* ------------------------------------------------------------- */
331     protected void doInvalidate() throws IllegalStateException
332     {
333         try
334         {
335             if (LOG.isDebugEnabled())
336                 LOG.debug("invalidate {}",_clusterId);
337             if (isValid())
338                 clearAttributes();
339         }
340         finally
341         {
342             synchronized (this)
343             {
344                 // mark as invalid
345                 _invalid=true;
346             }
347         }
348     }
349 
350     /* ------------------------------------------------------------- */
351     public abstract void clearAttributes();
352    
353 
354     /* ------------------------------------------------------------- */
355     public boolean isIdChanged()
356     {
357         return _idChanged;
358     }
359 
360     /* ------------------------------------------------------------- */
361     @Override
362     public boolean isNew() throws IllegalStateException
363     {
364         checkValid();
365         return _newSession;
366     }
367 
368     /* ------------------------------------------------------------- */
369     /**
370      * @deprecated As of Version 2.2, this method is replaced by
371      *             {@link #setAttribute}
372      */
373     @Deprecated
374     @Override
375     public void putValue(java.lang.String name, java.lang.Object value) throws IllegalStateException
376     {
377         changeAttribute(name,value);
378     }
379 
380     /* ------------------------------------------------------------ */
381     @Override
382     public void removeAttribute(String name)
383     {
384         setAttribute(name,null);
385     }
386 
387     /* ------------------------------------------------------------- */
388     /**
389      * @deprecated As of Version 2.2, this method is replaced by
390      *             {@link #removeAttribute}
391      */
392     @Deprecated
393     @Override
394     public void removeValue(java.lang.String name) throws IllegalStateException
395     {
396         removeAttribute(name);
397     }
398     
399     /* ------------------------------------------------------------ */
400     @Override
401     public Enumeration<String> getAttributeNames()
402     {
403         synchronized (this)
404         {
405             checkValid();
406             return doGetAttributeNames();
407         }
408     }
409     
410     /* ------------------------------------------------------------- */
411     /**
412      * @deprecated As of Version 2.2, this method is replaced by
413      *             {@link #getAttributeNames}
414      */
415     @Deprecated
416     @Override
417     public String[] getValueNames() throws IllegalStateException
418     {
419         synchronized(this)
420         {
421             checkValid();
422             Enumeration<String> anames = doGetAttributeNames();
423             if (anames == null)
424                 return new String[0];
425             ArrayList<String> names = new ArrayList<String>();
426             while (anames.hasMoreElements())
427                 names.add(anames.nextElement());
428             return names.toArray(new String[names.size()]);
429         }
430     }
431     
432 
433     /* ------------------------------------------------------------ */
434     public abstract Object doPutOrRemove(String name, Object value);
435  
436 
437     /* ------------------------------------------------------------ */
438     public abstract Object doGet(String name);
439     
440     
441     /* ------------------------------------------------------------ */
442     public abstract Enumeration<String> doGetAttributeNames();
443     
444     
445     /* ------------------------------------------------------------ */
446     @Override
447     public Object getAttribute(String name)
448     {
449         synchronized (this)
450         {
451             checkValid();
452             return doGet(name);
453         }
454     }
455    
456 
457     /* ------------------------------------------------------------ */
458     @Override
459     public void setAttribute(String name, Object value)
460     {
461         changeAttribute(name,value);
462     }
463     
464     /* ------------------------------------------------------------ */
465     /**
466      * @param name
467      * @param value
468      * @deprecated use changeAttribute(String,Object) instead
469      * @return
470      */
471     protected boolean updateAttribute (String name, Object value)
472     {
473         Object old=null;
474         synchronized (this)
475         {
476             checkValid();
477             old=doPutOrRemove(name,value);
478         }
479 
480         if (value==null || !value.equals(old))
481         {
482             if (old!=null)
483                 unbindValue(name,old);
484             if (value!=null)
485                 bindValue(name,value);
486 
487             _manager.doSessionAttributeListeners(this,name,old,value);
488             return true;
489         }
490         return false;
491     }
492     
493     
494     /* ------------------------------------------------------------ */
495     /**
496      * Either set (perhaps replace) or remove the value of the attribute
497      * in the session. The appropriate session attribute listeners are
498      * also called.
499      * 
500      * @param name
501      * @param value
502      * @return
503      */
504     protected Object changeAttribute (String name, Object value)
505     {
506         Object old=null;
507         synchronized (this)
508         {
509             checkValid();
510             old=doPutOrRemove(name,value);
511         }
512 
513         callSessionAttributeListeners(name, value, old);
514 
515         return old;
516     }
517 
518     /* ------------------------------------------------------------ */
519     /**
520      * Call binding and attribute listeners based on the new and old
521      * values of the attribute.
522      * 
523      * @param name name of the attribute
524      * @param newValue  new value of the attribute
525      * @param oldValue previous value of the attribute
526      */
527     protected void callSessionAttributeListeners (String name, Object newValue, Object oldValue)
528     {
529         if (newValue==null || !newValue.equals(oldValue))
530         {
531             if (oldValue!=null)
532                 unbindValue(name,oldValue);
533             if (newValue!=null)
534                 bindValue(name,newValue);
535 
536             _manager.doSessionAttributeListeners(this,name,oldValue,newValue);
537         }
538     }
539   
540 
541     /* ------------------------------------------------------------- */
542     public void setIdChanged(boolean changed)
543     {
544         _idChanged=changed;
545     }
546 
547     /* ------------------------------------------------------------- */
548     @Override
549     public void setMaxInactiveInterval(int secs)
550     {
551         _maxIdleMs=(long)secs*1000L;
552     }
553 
554     /* ------------------------------------------------------------- */
555     @Override
556     public String toString()
557     {
558         return this.getClass().getName()+":"+getId()+"@"+hashCode();
559     }
560 
561     /* ------------------------------------------------------------- */
562     /** If value implements HttpSessionBindingListener, call valueBound() */
563     public void bindValue(java.lang.String name, Object value)
564     {
565         if (value!=null&&value instanceof HttpSessionBindingListener)
566             ((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this,name));
567     }
568 
569     /* ------------------------------------------------------------ */
570     public boolean isValid()
571     {
572         return !_invalid;
573     }
574 
575     /* ------------------------------------------------------------- */
576     protected void cookieSet()
577     {
578         synchronized (this)
579         {
580             _cookieSet=_accessed;
581         }
582     }
583 
584     /* ------------------------------------------------------------ */
585     public int getRequests()
586     {
587         synchronized (this)
588         {
589             return _requests;
590         }
591     }
592 
593     /* ------------------------------------------------------------ */
594     public void setRequests(int requests)
595     {
596         synchronized (this)
597         {
598             _requests=requests;
599         }
600     }
601 
602     /* ------------------------------------------------------------- */
603     /** If value implements HttpSessionBindingListener, call valueUnbound() */
604     public void unbindValue(java.lang.String name, Object value)
605     {
606         if (value!=null&&value instanceof HttpSessionBindingListener)
607             ((HttpSessionBindingListener)value).valueUnbound(new HttpSessionBindingEvent(this,name));
608     }
609 
610     /* ------------------------------------------------------------- */
611     public void willPassivate()
612     {
613         synchronized(this)
614         {
615             HttpSessionEvent event = new HttpSessionEvent(this);
616             for (Iterator<Object> iter = getAttributeMap().values().iterator(); iter.hasNext();)
617             {
618                 Object value = iter.next();
619                 if (value instanceof HttpSessionActivationListener)
620                 {
621                     HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
622                     listener.sessionWillPassivate(event);
623                 }
624             }
625         }
626     }
627 
628     /* ------------------------------------------------------------- */
629     public void didActivate()
630     {
631         synchronized(this)
632         {
633             HttpSessionEvent event = new HttpSessionEvent(this);
634             for (Iterator<Object> iter = getAttributeMap().values().iterator(); iter.hasNext();)
635             {
636                 Object value = iter.next();
637                 if (value instanceof HttpSessionActivationListener)
638                 {
639                     HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
640                     listener.sessionDidActivate(event);
641                 }
642             }
643         }
644     }
645 
646 
647 }