View Javadoc

1   /*
2   Wotonomy: OpenStep design patterns for pure Java applications.
3   Copyright (C) 2003 Intersect Software Corp.
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  Lesser General Public License for more details.
14  
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, see http://www.gnu.org
17  */
18  
19  package net.wotonomy.web;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.ObjectInputStream;
26  import java.io.ObjectOutputStream;
27  import java.io.ObjectStreamClass;
28  
29  import javax.servlet.http.HttpSession;
30  
31  
32  /***
33  * An implementation of WOSessionStore that stores WOSessions
34  * inside of HttpSessions, to take advantage of the servlet 
35  * containers built-in distribution capabilities.
36  *
37  * @author michael@mpowers.net
38  * @author $Author: cgruber $
39  * @version $Revision: 905 $
40  */
41  public class WOServletSessionStore extends WOSessionStore
42  {
43      private static final String ServletSessionKey = "WOServletSessionStoreKey";
44  
45      /***
46      * This implementation currently does nothing and returns null, as we rely on the 
47      * servlet container to dispose of the HttpSession which contains our WOSession.
48      */                                              
49      public WOSession removeSessionWithID(String sessionID)
50      {
51          return null;
52      }
53      
54      /***
55      * Returns the WOSession for the specified ID from the store.
56      * The sessionID parameter is ignored, and the session is removed from
57      * the store until saveSessionForContext is called.
58      */
59      public WOSession restoreSessionWithID(String sessionID, WORequest aRequest)
60      {
61          WOSession result = null;
62          HttpSession servletSession = aRequest.servletRequest().getSession();
63          if ( servletSession != null )
64          {
65              try
66              {
67                  result = (WOSession) servletSession.getAttribute( ServletSessionKey );
68                  if ( result != null )
69                  {
70                      // if the servlet's class loader has changed, we need to reload
71                      if ( result.getClass().getClassLoader() != 
72                          WOApplication.application().getClass().getClassLoader() )
73                      {
74                          throw new ClassCastException( result.getClass().toString() );
75                      }
76                  }
77              } 
78              catch ( ClassCastException exc )
79              {
80                  // we're having an issue with the container's class loader:
81                  // try serializing and deserializing to see if it is reloaded correctly
82                  try
83                  {
84                      
85                      ByteArrayOutputStream bytes = new ByteArrayOutputStream();
86                      ObjectOutputStream output = new ObjectOutputStream( bytes );
87                      Object o = servletSession.getAttribute( ServletSessionKey );
88                      output.writeObject( o );
89                      output.flush();
90                      output.close();
91                      
92                      System.out.println( 
93                          "WOServletSessionStore: reloaded session with size: " +
94                          bytes.toByteArray().length );                
95      
96                      ObjectInputStream input = new CustomObjectInputStream( 
97                          new ByteArrayInputStream( bytes.toByteArray() ),
98                          WOApplication.application().getClass().getClassLoader() );
99                      
100                     o = input.readObject();
101                     input.close();
102                     
103                     // try it again
104                     result = (WOSession) o;
105                 }
106                 catch ( Exception e )
107                 {
108                     e.printStackTrace();
109                     // give up: remove the attribute and allow a new session
110                     servletSession.removeAttribute( ServletSessionKey );
111                 }
112             }
113             
114             if ( result != null ) 
115             {
116                 servletSession.removeAttribute( ServletSessionKey );
117             }
118         }
119         //System.out.println( "restoreSessionWithID: " + sessionID + " : " + result );        
120         return result;
121     }
122                                                    
123     /***
124     * Places the context's session into the store.
125     */
126     public void saveSessionForContext(WOContext context)
127     {
128         //System.out.println( "saveSessionForContext: " + context + " : " + context.session() );        
129         context.request().servletRequest().getSession( true ).setAttribute(
130             ServletSessionKey, context.session() );
131     }
132     
133     /***
134     * Needed to specify a class loader which may be different that the
135     * one used to load the ObjectInputStream class.
136     */ 
137     private static class CustomObjectInputStream extends ObjectInputStream
138     {
139         ClassLoader loader;
140         
141         public CustomObjectInputStream( 
142             InputStream anInputStream, ClassLoader aClassLoader )
143         throws java.io.IOException, java.io.StreamCorruptedException
144         {
145             super( anInputStream );
146             loader = aClassLoader;
147         }
148         
149         protected Class resolveClass(ObjectStreamClass v)
150              throws IOException, ClassNotFoundException 
151         {
152             return loader.loadClass( v.getName() );
153         }
154     }
155 }
156 
157 /*
158  * $Log$
159  * Revision 1.2  2006/02/19 01:44:02  cgruber
160  * Add xmlrpc files
161  * Remove jclark and replace with dom4j and javax.xml.sax stuff
162  * Re-work dependencies and imports so it all compiles.
163  *
164  * Revision 1.1  2006/02/16 13:22:22  cgruber
165  * Check in all sources in eclipse-friendly maven-enabled packages.
166  *
167  * Revision 1.7  2003/01/22 23:00:32  mpowers
168  * Now keeping the most recent page around.
169  *
170  * Revision 1.6  2003/01/21 17:53:16  mpowers
171  * Now handling reloading when wotonomy is on the system class path.
172  *
173  * Revision 1.5  2003/01/15 19:50:49  mpowers
174  * Fixed issues with WOSession and Serializable.
175  * Can now persist sessions between classloaders (hot swap of class impls).
176  *
177  * Revision 1.3  2003/01/14 16:05:19  mpowers
178  * Removed extraneous printlns.
179  *
180  * Revision 1.2  2003/01/13 22:25:07  mpowers
181  * Request-response cycle is working with session and page persistence.
182  *
183  * Revision 1.1  2003/01/07 20:48:24  mpowers
184  * Implemented WOSessionStore and WOServletSessionStore.
185  *
186  *
187  */
188