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         super.checkValid();
121     }
122 
123     /* ------------------------------------------------------------ */
124     @Override
125     protected boolean access(long time)
126     {
127         if (LOG.isDebugEnabled())
128             LOG.debug("NoSqlSession:access:active {} time {}", _active, time);
129         if (_active.incrementAndGet()==1)
130         {
131             long period=_manager.getStalePeriod()*1000L;
132             if (period==0)
133                 refresh();
134             else if (period>0)
135             {
136                 long stale=time-_lastSync;
137                 if (LOG.isDebugEnabled())
138                     LOG.debug("NoSqlSession:access:stale "+stale);
139                 if (stale>period)
140                     refresh();
141             }
142         }
143 
144         return super.access(time);
145     }
146 
147     /* ------------------------------------------------------------ */
148     @Override
149     protected void complete()
150     {
151         super.complete();
152         if(_active.decrementAndGet()==0)
153         {
154             switch(_manager.getSavePeriod())
155             {
156                 case 0: 
157                     save(isValid());
158                     break;
159                 case 1:
160                     if (isDirty())
161                         save(isValid());
162                     break;
163 
164             }
165         }
166     }
167 
168     /* ------------------------------------------------------------ */
169     @Override
170     protected void doInvalidate() throws IllegalStateException
171     {
172         super.doInvalidate();
173         //jb why save here? if the session is invalidated it should be removed
174         save(false);
175     }
176     
177     /* ------------------------------------------------------------ */
178     protected void save(boolean activateAfterSave)
179     {
180         synchronized (this)
181         {
182             _version=_manager.save(this,_version,activateAfterSave);
183             _lastSync=getAccessed();
184         }
185     }
186     
187     
188     /* ------------------------------------------------------------ */
189     public void idle ()
190     {
191         synchronized (this)
192         {
193             if (!isIdle() && !isIdling()) //don't re-idle an idle session as the attribute map will be empty
194             {
195                 if (LOG.isDebugEnabled())
196                     LOG.debug("Idling {}", super.getId());
197                 setIdling();
198                 save(false);
199                 willPassivate();
200                 clearAttributes();
201                 setIdle(true);
202             }
203         }
204     }
205     
206     
207     /* ------------------------------------------------------------ */
208     public synchronized void deIdle()
209     {
210         if (LOG.isDebugEnabled())
211             LOG.debug("Checking before de-idling {}, isidle:{}, isDeidleFailed:", super.getId(), isIdle(), isDeIdleFailed());
212         
213         if (isIdle() && !isDeIdleFailed())
214         {
215 
216             setDeIdling();
217             if (LOG.isDebugEnabled())
218                 LOG.debug("De-idling " + super.getId());
219 
220             // Update access time to prevent race with idling period
221             super.access(System.currentTimeMillis());
222 
223             //access may have expired and invalidated the session, so only deidle if it is still valid
224             if (isValid())
225             {
226                 try
227                 {    
228                     setIdle(false);
229                     _version=_manager.refresh(this, new Long(0)); //ensure version should not match to force refresh
230                     if (_version == null)
231                         setDeIdleFailed(true);
232                 }
233                 catch (Exception e)
234                 {
235                     setDeIdleFailed(true);
236                     LOG.warn("Problem de-idling session " + super.getId(), e);
237                     invalidate();
238                 }
239             }
240         }
241     }
242     
243     /* ------------------------------------------------------------ */
244     public synchronized boolean isIdle ()
245     {
246         return _idle == IdleState.IDLE;
247     }
248     
249     
250     /* ------------------------------------------------------------ */
251     public synchronized boolean isIdling ()
252     {
253         return _idle == IdleState.IDLING;
254     }
255     
256     /* ------------------------------------------------------------ */
257     public synchronized boolean isDeIdling()
258     {
259         return _idle == IdleState.DEIDLING;
260     }
261     
262     
263     public synchronized void setIdling ()
264     {
265         _idle = IdleState.IDLING;
266     }
267     
268     public synchronized void setDeIdling ()
269     {
270         _idle = IdleState.DEIDLING;
271     }
272     
273     /* ------------------------------------------------------------ */
274     public synchronized void setIdle (boolean idle)
275     {
276         if (idle)
277             _idle = IdleState.IDLE;
278         else
279             _idle = IdleState.NOT_IDLE;
280     }
281     
282 
283     public boolean isDeIdleFailed()
284     {
285         return _deIdleFailed;
286     }
287 
288     public void setDeIdleFailed(boolean _deIdleFailed)
289     {
290         this._deIdleFailed = _deIdleFailed;
291     }
292 
293     /* ------------------------------------------------------------ */
294     protected void refresh()
295     {
296         synchronized (this)
297         {
298             _version=_manager.refresh(this,_version);
299         }
300     }
301 
302     /* ------------------------------------------------------------ */
303     public boolean isDirty()
304     {
305         synchronized (this)
306         {
307             return _dirty!=null && !_dirty.isEmpty();
308         }
309     }
310     
311     /* ------------------------------------------------------------ */
312     public Set<String> takeDirty()
313     {
314         synchronized (this)
315         {
316             Set<String> dirty=_dirty;
317             if (dirty==null)
318                 dirty= new HashSet<String>();
319             else
320                 _dirty=null;
321             return dirty;
322         }
323     }
324 
325     /* ------------------------------------------------------------ */
326     public Object getVersion()
327     {
328         return _version;
329     }
330     
331     
332     /* ------------------------------------------------------------ */
333     @Override
334     public void setClusterId(String clusterId)
335     {
336         super.setClusterId(clusterId);
337     }
338 
339     
340     /* ------------------------------------------------------------ */
341     @Override
342     public void setNodeId(String nodeId)
343     {
344         super.setNodeId(nodeId);
345     }
346 }