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.io.DataOutputStream;
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileNotFoundException;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.ObjectOutputStream;
28  import java.io.OutputStream;
29  import java.util.Enumeration;
30  
31  import javax.servlet.http.HttpServletRequest;
32  
33  import org.eclipse.jetty.util.IO;
34  import org.eclipse.jetty.util.log.Log;
35  import org.eclipse.jetty.util.log.Logger;
36  
37  public class HashedSession extends AbstractSession
38  {
39      private static final Logger LOG = Log.getLogger(HashedSession.class);
40  
41      private final HashSessionManager _hashSessionManager;
42  
43      /** Whether the session has been saved because it has been deemed idle;
44       * in which case its attribute map will have been saved and cleared. */
45      private transient boolean _idled = false;
46  
47      /** Whether there has already been an attempt to save this session
48       * which has failed.  If there has, there will be no more save attempts
49       * for this session.  This is to stop the logs being flooded with errors
50       * due to serialization failures that are most likely caused by user
51       * data stored in the session that is not serializable. */
52      private transient boolean _saveFailed = false;
53  
54      /* ------------------------------------------------------------- */
55      protected HashedSession(HashSessionManager hashSessionManager, HttpServletRequest request)
56      {
57          super(hashSessionManager,request);
58          _hashSessionManager = hashSessionManager;
59      }
60  
61      /* ------------------------------------------------------------- */
62      protected HashedSession(HashSessionManager hashSessionManager, long created, long accessed, String clusterId)
63      {
64          super(hashSessionManager,created, accessed, clusterId);
65          _hashSessionManager = hashSessionManager;
66      }
67  
68      /* ------------------------------------------------------------- */
69      protected void checkValid()
70      {
71          if (_hashSessionManager._idleSavePeriodMs!=0)
72              deIdle();
73          super.checkValid();
74      }
75  
76      /* ------------------------------------------------------------- */
77      @Override
78      public void setMaxInactiveInterval(int secs)
79      {
80          super.setMaxInactiveInterval(secs);
81          if (getMaxInactiveInterval()>0&&(getMaxInactiveInterval()*1000L/10)<_hashSessionManager._scavengePeriodMs)
82              _hashSessionManager.setScavengePeriod((secs+9)/10);
83      }
84  
85      /* ------------------------------------------------------------ */
86      @Override
87      protected void doInvalidate()
88      throws IllegalStateException
89      {
90          super.doInvalidate();
91          remove();
92      }
93      
94      
95      /* ------------------------------------------------------------ */
96      /**
97       * Remove from the disk
98       */
99      synchronized void remove ()
100     {
101         if (_hashSessionManager._storeDir!=null && getId()!=null)
102         {
103             String id=getId();
104             File f = new File(_hashSessionManager._storeDir, id);
105             f.delete();
106         }
107     }
108 
109     /* ------------------------------------------------------------ */
110     synchronized void save(boolean reactivate)
111     throws Exception
112     {
113         // Only idle the session if not already idled and no previous save/idle has failed
114         if (!isIdled() && !_saveFailed)
115         {
116             if (LOG.isDebugEnabled())
117                 LOG.debug("Saving {} {}",super.getId(),reactivate);
118 
119             try
120             {
121                 willPassivate();
122                 save();
123                 if (reactivate)
124                     didActivate();
125                 else
126                     clearAttributes();
127             }
128             catch (Exception e)
129             {       
130                 LOG.warn("Problem saving session " + super.getId(), e);
131                 _idled=false; // assume problem was before _values.clear();
132             }
133         }
134     }
135     
136     
137     
138     synchronized void save ()
139     throws Exception
140     {   
141         File file = null;
142         FileOutputStream fos = null;
143         if (!_saveFailed && _hashSessionManager._storeDir != null)
144         {
145             try
146             {
147                 file = new File(_hashSessionManager._storeDir, super.getId());
148                 if (file.exists())
149                     file.delete();
150                 file.createNewFile();
151                 fos = new FileOutputStream(file);
152                 save(fos);
153                 IO.close(fos);
154             }
155             catch (Exception e)
156             {
157                 saveFailed(); // We won't try again for this session
158                 if (fos != null) IO.close(fos);
159                 if (file != null) file.delete(); // No point keeping the file if we didn't save the whole session
160                 throw e;             
161             }
162         }
163     }
164     
165     
166     /* ------------------------------------------------------------ */
167     public synchronized void save(OutputStream os)  throws IOException
168     {
169         DataOutputStream out = new DataOutputStream(os);
170         out.writeUTF(getClusterId());
171         out.writeUTF(getNodeId());
172         out.writeLong(getCreationTime());
173         out.writeLong(getAccessed());
174 
175         /* Don't write these out, as they don't make sense to store because they
176          * either they cannot be true or their value will be restored in the
177          * Session constructor.
178          */
179         //out.writeBoolean(_invalid);
180         //out.writeBoolean(_doInvalidate);
181         //out.writeBoolean( _newSession);
182         out.writeInt(getRequests());
183         out.writeInt(getAttributes());
184         ObjectOutputStream oos = new ObjectOutputStream(out);
185         Enumeration<String> e=getAttributeNames();
186         while(e.hasMoreElements())
187         {
188             String key=e.nextElement();
189             oos.writeUTF(key);
190             oos.writeObject(doGet(key));
191         }
192         
193         out.writeInt(getMaxInactiveInterval());
194     }
195 
196     /* ------------------------------------------------------------ */
197     public synchronized void deIdle()
198     {
199         if (isIdled())
200         {
201             // Access now to prevent race with idling period
202             access(System.currentTimeMillis());
203 
204             if (LOG.isDebugEnabled())
205                 LOG.debug("De-idling " + super.getId());
206 
207             FileInputStream fis = null;
208 
209             try
210             {
211                 File file = new File(_hashSessionManager._storeDir, super.getId());
212                 if (!file.exists() || !file.canRead())
213                     throw new FileNotFoundException(file.getName());
214 
215                 fis = new FileInputStream(file);
216                 _idled = false;
217                 _hashSessionManager.restoreSession(fis, this);
218                 IO.close(fis); 
219                 
220                 didActivate();
221 
222                 // If we are doing period saves, then there is no point deleting at this point 
223                 if (_hashSessionManager._savePeriodMs == 0)
224                     file.delete();
225             }
226             catch (Exception e)
227             {
228                 LOG.warn("Problem de-idling session " + super.getId(), e);
229                 if (fis != null) IO.close(fis);//Must ensure closed before invalidate
230                 invalidate();
231             }
232         }
233     }
234 
235 
236     /* ------------------------------------------------------------ */
237     /**
238      * Idle the session to reduce session memory footprint.
239      *
240      * The session is idled by persisting it, then clearing the session values attribute map and finally setting
241      * it to an idled state.
242      */
243     public synchronized void idle()
244     throws Exception
245     {
246         save(false);
247         _idled = true;
248     }
249 
250     /* ------------------------------------------------------------ */
251     public synchronized boolean isIdled()
252     {
253       return _idled;
254     }
255 
256     /* ------------------------------------------------------------ */
257     public synchronized boolean isSaveFailed()
258     {
259         return _saveFailed;
260     }
261 
262     /* ------------------------------------------------------------ */
263     public synchronized void saveFailed()
264     {
265         _saveFailed = true;
266     }
267 
268 }