View Javadoc

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