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.nosql;
20  
21  
22  import java.util.HashSet;
23  import java.util.Set;
24  import java.util.concurrent.atomic.AtomicInteger;
25  
26  import javax.servlet.http.HttpServletRequest;
27  
28  import org.eclipse.jetty.server.session.MemSession;
29  import org.eclipse.jetty.util.log.Log;
30  import org.eclipse.jetty.util.log.Logger;
31  
32  
33  /* ------------------------------------------------------------ */
34  public class NoSqlSession extends MemSession
35  {
36      private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
37      
38      private enum IdleState {NOT_IDLE, IDLE, IDLING, DEIDLING};
39  
40      private final NoSqlSessionManager _manager;
41      private Set<String> _dirty;
42      private final AtomicInteger _active = new AtomicInteger();
43      private Object _version;
44      private long _lastSync;
45  
46      private IdleState _idle = IdleState.NOT_IDLE;
47      
48      private boolean _deIdleFailed;
49  
50      /* ------------------------------------------------------------ */
51      public NoSqlSession(NoSqlSessionManager manager, HttpServletRequest request)
52      {
53          super(manager, request);
54          _manager=manager;
55          _active.incrementAndGet();
56      }
57      
58      /* ------------------------------------------------------------ */
59      public NoSqlSession(NoSqlSessionManager manager, long created, long accessed, String clusterId, Object version)
60      {
61          super(manager, created,accessed,clusterId);
62          _manager=manager;
63          _version=version;
64      }
65      
66      /* ------------------------------------------------------------ */
67      @Override
68      public Object doPutOrRemove(String name, Object value)
69      {
70          synchronized (this)
71          {
72              Object old = super.doPutOrRemove(name,value);
73              
74              if (_manager.getSavePeriod()==-2)
75              {
76                  save(true);
77              }
78              return old;
79          }
80      }
81      
82      
83      /* ------------------------------------------------------------ */
84      @Override
85      public void setAttribute(String name, Object value)
86      {
87          Object old = changeAttribute(name,value);
88          if (value == null && old == null)
89              return; //not dirty, no change
90          
91          if (value==null || !value.equals(old))
92          {
93              if (_dirty==null)
94              {
95                  _dirty=new HashSet<String>();
96              }
97              
98              _dirty.add(name);
99          }
100     }
101     
102     
103     /* ------------------------------------------------------------ */
104     @Override
105     protected void timeout() throws IllegalStateException
106     {
107         super.timeout();
108     }
109 
110 
111     
112     /* ------------------------------------------------------------ */
113     @Override
114     protected void checkValid() throws IllegalStateException
115     {
116         //whenever a method is called on the session, check that it was not idled and
117         //reinflate it if necessary
118         if (!isDeIdleFailed() && _manager.getIdlePeriod() > 0 && isIdle())
119             deIdle();
120         try
121         {
122             super.checkValid();
123         }
124         catch (IllegalStateException e)
125         {
126             throw new IllegalStateException (e.getMessage()+" idle="+_idle+" deidleFailed="+_deIdleFailed+" version="+_version, e);
127         }
128     }
129     
130     
131 
132     /* ------------------------------------------------------------ */
133     @Override
134     protected boolean access(long time)
135     {
136         if (LOG.isDebugEnabled())
137             LOG.debug("NoSqlSession:access:active {} time {}", _active, time);
138         if (_active.incrementAndGet()==1)
139         {
140             long period=_manager.getStalePeriod()*1000L;
141             if (period==0)
142                 refresh();
143             else if (period>0)
144             {
145                 long stale=time-_lastSync;
146                 if (LOG.isDebugEnabled())
147                     LOG.debug("NoSqlSession:access:stale "+stale);
148                 if (stale>period)
149                     refresh();
150             }
151         }
152 
153         return super.access(time);
154     }
155 
156     /* ------------------------------------------------------------ */
157     @Override
158     protected void complete()
159     {
160         super.complete();
161         if(_active.decrementAndGet()==0)
162         {
163             switch(_manager.getSavePeriod())
164             {
165                 case 0: 
166                     save(isValid());
167                     break;
168                 case 1:
169                     if (isDirty())
170                         save(isValid());
171                     break;
172 
173             }
174         }
175     }
176 
177     /* ------------------------------------------------------------ */
178     @Override
179     protected void doInvalidate() throws IllegalStateException
180     {
181         super.doInvalidate();
182         //jb why save here? if the session is invalidated it should be removed
183         save(false);
184     }
185     
186     /* ------------------------------------------------------------ */
187     protected void save(boolean activateAfterSave)
188     {
189         synchronized (this)
190         {
191             _version=_manager.save(this,_version,activateAfterSave);
192             _lastSync=getAccessed();
193         }
194     }
195     
196     
197     /* ------------------------------------------------------------ */
198     public void idle ()
199     {
200         synchronized (this)
201         {
202             if (!isIdle() && !isIdling()) //don't re-idle an idle session as the attribute map will be empty
203             {
204                 if (LOG.isDebugEnabled())
205                     LOG.debug("Idling {}", super.getId());
206                 setIdling();
207                 save(false);
208                 willPassivate();
209                 clearAttributes();
210                 setIdle(true);
211             }
212         }
213     }
214     
215     
216     /* ------------------------------------------------------------ */
217     public synchronized void deIdle()
218     {
219         if (LOG.isDebugEnabled())
220             LOG.debug("Checking before de-idling {}, isidle:{}, isDeidleFailed:", super.getId(), isIdle(), isDeIdleFailed());
221         
222         if (isIdle() && !isDeIdleFailed())
223         {
224 
225             setDeIdling();
226             if (LOG.isDebugEnabled())
227                 LOG.debug("De-idling " + super.getId());
228 
229             // Update access time to prevent race with idling period
230             super.access(System.currentTimeMillis());
231 
232             //access may have expired and invalidated the session, so only deidle if it is still valid
233             if (isValid())
234             {
235                 try
236                 {    
237                     setIdle(false);
238                     _version=_manager.refresh(this, new Long(0)); //ensure version should not match to force refresh
239                     if (_version == null)
240                         setDeIdleFailed(true);
241                 }
242                 catch (Exception e)
243                 {
244                     setDeIdleFailed(true);
245                     LOG.warn("Problem de-idling session " + super.getId(), e);
246                     invalidate();
247                 }
248             }
249         }
250     }
251     
252     /* ------------------------------------------------------------ */
253     public synchronized boolean isIdle ()
254     {
255         return _idle == IdleState.IDLE;
256     }
257     
258     
259     /* ------------------------------------------------------------ */
260     public synchronized boolean isIdling ()
261     {
262         return _idle == IdleState.IDLING;
263     }
264     
265     /* ------------------------------------------------------------ */
266     public synchronized boolean isDeIdling()
267     {
268         return _idle == IdleState.DEIDLING;
269     }
270     
271     
272     public synchronized void setIdling ()
273     {
274         _idle = IdleState.IDLING;
275     }
276     
277     public synchronized void setDeIdling ()
278     {
279         _idle = IdleState.DEIDLING;
280     }
281     
282     /* ------------------------------------------------------------ */
283     public synchronized void setIdle (boolean idle)
284     {
285         if (idle)
286             _idle = IdleState.IDLE;
287         else
288             _idle = IdleState.NOT_IDLE;
289     }
290     
291 
292     public boolean isDeIdleFailed()
293     {
294         return _deIdleFailed;
295     }
296 
297     public void setDeIdleFailed(boolean _deIdleFailed)
298     {
299         this._deIdleFailed = _deIdleFailed;
300     }
301 
302     /* ------------------------------------------------------------ */
303     protected void refresh()
304     {
305         synchronized (this)
306         {
307             _version=_manager.refresh(this,_version);
308         }
309     }
310 
311     /* ------------------------------------------------------------ */
312     public boolean isDirty()
313     {
314         synchronized (this)
315         {
316             return _dirty!=null && !_dirty.isEmpty();
317         }
318     }
319     
320     /* ------------------------------------------------------------ */
321     public Set<String> takeDirty()
322     {
323         synchronized (this)
324         {
325             Set<String> dirty=_dirty;
326             if (dirty==null)
327                 dirty= new HashSet<String>();
328             else
329                 _dirty=null;
330             return dirty;
331         }
332     }
333 
334     /* ------------------------------------------------------------ */
335     public Object getVersion()
336     {
337         return _version;
338     }
339     
340     
341     /* ------------------------------------------------------------ */
342     @Override
343     public void setClusterId(String clusterId)
344     {
345         super.setClusterId(clusterId);
346     }
347 
348     
349     /* ------------------------------------------------------------ */
350     @Override
351     public void setNodeId(String nodeId)
352     {
353         super.setNodeId(nodeId);
354     }
355 }