View Javadoc

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