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  
18  class HashedSession extends AbstractSession
19  {
20      private final HashSessionManager _hashSessionManager;
21  
22      /** Whether the session has been saved because it has been deemed idle; 
23       * in which case its attribute map will have been saved and cleared. */
24      private transient boolean _idled = false;
25  
26      /** Whether there has already been an attempt to save this session
27       * which has failed.  If there has, there will be no more save attempts
28       * for this session.  This is to stop the logs being flooded with errors
29       * due to serialization failures that are most likely caused by user
30       * data stored in the session that is not serializable. */
31      private transient boolean _saveFailed = false;
32  
33      /* ------------------------------------------------------------- */
34      protected HashedSession(HashSessionManager hashSessionManager, HttpServletRequest request)
35      {
36          super(hashSessionManager,request);
37          _hashSessionManager = hashSessionManager;
38      }
39  
40      /* ------------------------------------------------------------- */
41      protected HashedSession(HashSessionManager hashSessionManager, long created, long accessed, String clusterId)
42      {
43          super(hashSessionManager,created, accessed, clusterId);
44          _hashSessionManager = hashSessionManager;
45      }
46  
47      /* ------------------------------------------------------------- */
48      protected void checkValid()
49      {
50          if (_hashSessionManager._idleSavePeriodMs!=0)
51              deIdle();
52          super.checkValid();
53      }
54      
55      /* ------------------------------------------------------------- */
56      @Override
57      public void setMaxInactiveInterval(int secs)
58      {
59          super.setMaxInactiveInterval(secs);
60          if (getMaxInactiveInterval()>0&&(getMaxInactiveInterval()*1000/10)<_hashSessionManager._scavengePeriodMs)
61              _hashSessionManager.setScavengePeriod((secs+9)/10);
62      }
63  
64      /* ------------------------------------------------------------ */
65      @Override
66      protected void doInvalidate()
67      throws IllegalStateException
68      {
69          super.doInvalidate();
70          
71          // Remove from the disk
72          if (_hashSessionManager._storeDir!=null && getId()!=null)
73          {
74              String id=getId();
75              File f = new File(_hashSessionManager._storeDir, id);
76              f.delete();
77          }
78      }
79  
80      /* ------------------------------------------------------------ */
81      synchronized void save(boolean reactivate)
82      {
83          // Only idle the session if not already idled and no previous save/idle has failed
84          if (!isIdled() && !_saveFailed)
85          {
86              if (Log.isDebugEnabled())
87                  Log.debug("Saving {} {}",super.getId(),reactivate);
88  
89              File file = null;
90              FileOutputStream fos = null;
91              
92              try
93              {
94                  file = new File(_hashSessionManager._storeDir, super.getId());
95  
96                  if (file.exists())
97                      file.delete();
98                  file.createNewFile();
99                  fos = new FileOutputStream(file);
100                 willPassivate();
101                 save(fos);
102                 if (reactivate)
103                     didActivate();
104                 else
105                     clearAttributes();
106             }
107             catch (Exception e)
108             {
109                 saveFailed(); // We won't try again for this session
110 
111                 Log.warn("Problem saving session " + super.getId(), e);
112 
113                 if (fos != null)
114                 {
115                     // Must not leave the file open if the saving failed
116                     IO.close(fos);
117                     // No point keeping the file if we didn't save the whole session
118                     file.delete();
119                     _idled=false; // assume problem was before _values.clear();
120                 }
121             }
122         }
123     }
124     /* ------------------------------------------------------------ */
125     public synchronized void save(OutputStream os)  throws IOException 
126     {
127         DataOutputStream out = new DataOutputStream(os);
128         out.writeUTF(getClusterId());
129         out.writeUTF(getNodeId());
130         out.writeLong(getCreationTime());
131         out.writeLong(getAccessed());
132         
133         /* Don't write these out, as they don't make sense to store because they
134          * either they cannot be true or their value will be restored in the 
135          * Session constructor.
136          */
137         //out.writeBoolean(_invalid);
138         //out.writeBoolean(_doInvalidate);
139         //out.writeLong(_maxIdleMs);
140         //out.writeBoolean( _newSession);
141         out.writeInt(getRequests());
142         out.writeInt(getAttributes());
143         ObjectOutputStream oos = new ObjectOutputStream(out);
144         Enumeration<String> e=getAttributeNames();
145         while(e.hasMoreElements())
146         {
147             String key=e.nextElement();
148             oos.writeUTF(key);
149             oos.writeObject(doGet(key));
150         }
151         oos.close();
152     }
153 
154     /* ------------------------------------------------------------ */
155     public synchronized void deIdle()
156     {
157         if (isIdled())
158         {
159             // Access now to prevent race with idling period
160             access(System.currentTimeMillis());
161 
162             
163             if (Log.isDebugEnabled())
164             {
165                 Log.debug("Deidling " + super.getId());
166             }
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 }