Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/tripi/asp/AspSessionHandler.java


1   /**
2    * ArrowHead ASP Server 
3    * This is a source file for the ArrowHead ASP Server - an 100% Java
4    * VBScript interpreter and ASP server.
5    *
6    * For more information, see http://www.tripi.com/arrowhead
7    *
8    * Copyright (C) 2002  Terence Haddock
9    *
10   * This program is free software; you can redistribute it and/or modify
11   * it under the terms of the GNU General Public License as published by
12   * the Free Software Foundation; either version 2 of the License, or
13   * (at your option) any later version.
14   *
15   * This program is distributed in the hope that it will be useful,
16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   * GNU General Public License for more details.
19   *
20   * You should have received a copy of the GNU General Public License
21   * along with this program; if not, write to the Free Software
22   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23   *
24   */
25  package com.tripi.asp;
26  
27  import org.apache.log4j.Category;
28  
29  import javax.servlet.http.HttpSession;
30  import javax.servlet.http.HttpSessionListener;
31  import javax.servlet.http.HttpSessionEvent;
32  import javax.servlet.http.HttpSessionBindingEvent;
33  
34  import java.util.Enumeration;
35  import java.util.HashMap;
36  import java.util.Iterator;
37  import java.util.Map;
38  import java.util.Set;
39  
40  import java.io.IOException;
41  import java.io.Serializable;
42  
43  /**
44   * This class handles synchronization between ASP Sessions and Servlet
45   * sessions for ASP to JSP interaction.
46   *
47   * @author Terence Haddock
48   */
49  public class AspSessionHandler implements HttpSessionListener
50  {
51      /**
52       * Debugging class
53       */
54      private Category DBG = Category.getInstance(AspSessionHandler.class);
55  
56  
57      /**
58       * Constructor.
59       */
60      public AspSessionHandler() {};
61  
62      /**
63       * Global Session to AspCollection mapping.
64       */
65      private static HashMap sessionToAspCollection = new HashMap();
66  
67      /**
68       * Session initialized.
69       * Note: I am assuming that this function is called in a thread-safe
70       * manner within a single session.
71       * @param e Event describing the initiazing of the session.
72       */
73      public void sessionCreated(HttpSessionEvent e)
74      {
75          HttpSession session = e.getSession();
76          if (DBG.isDebugEnabled())
77          {
78              DBG.debug("sessionCreated: " + e);
79              DBG.debug("Session: " + session.getId());
80          }
81          
82          /* Create a hashtable to store the mappings to handle case changes */
83          HashMap caseMapping = new HashMap();
84  
85          /* Store the case mappings into the session to handle passivation/activation */
86          session.setAttribute("ArrowHeadASP_CaseMappings", caseMapping);
87  
88          /* Create the ArrowHead_Contents variable which will contain
89             an ASP-accessible mirror of the session contents */
90          AspCollection contents = new AspSynchronizedCollection(session, caseMapping);
91  
92          /* Store this mapping to the hash map */
93          synchronized(sessionToAspCollection) {
94              sessionToAspCollection.put(session.getId(), contents);
95          }
96              
97  
98          if (DBG.isDebugEnabled()) DBG.debug("Before SESSION_ONSTART");
99  
100         try {
101             GlobalScope.callSessionOnStart(session, contents);
102         } catch (Exception ex) {
103             DBG.error("Error calling SESSION_ONSTART", ex);
104         }
105 
106         if (DBG.isDebugEnabled()) DBG.debug("After SESSION_ONSTART");
107     }
108 
109     /**
110      * Session destroyed.
111      * @param e Event describing the destruction of the session.
112      */
113     public void sessionDestroyed(HttpSessionEvent e)
114     {
115         HttpSession session = e.getSession();
116         if (DBG.isDebugEnabled())
117         {
118             DBG.debug("sessionDestroyed: " + e);
119             DBG.debug("Session: " + session.getId());
120         }
121 
122         if (DBG.isDebugEnabled()) DBG.debug("Before SESSION_ONEND");
123 
124         AspSynchronizedCollection contents;
125         synchronized(sessionToAspCollection)
126         {
127             contents = (AspSynchronizedCollection)sessionToAspCollection.get(session.getId());
128         }
129         if (contents != null) {
130             contents.disconnectFromSession();
131 
132             try {
133                 GlobalScope.callSessionOnEnd(session, contents);
134             } catch (Exception ex) {
135                 DBG.error("Error calling SESSION_ONEND", ex);
136             }
137         }
138 
139         if (DBG.isDebugEnabled()) DBG.debug("After SESSION_ONEND");
140         synchronized(sessionToAspCollection)
141         {
142             sessionToAspCollection.remove(session.getId());
143         }
144     }
145 
146     /**
147      * This function obtains the case mappings for the specified session.
148      */
149     static Map getCaseMappings(HttpSession session)
150     {
151         Map caseMapping;
152         synchronized(sessionToAspCollection) {
153             caseMapping = (Map)sessionToAspCollection.get("ArrowHeadASP_CaseMappings");
154             if (caseMapping == null) {
155                 caseMapping = new HashMap();
156                 sessionToAspCollection.put("ArrowHeadASP_CaseMappings", caseMapping);
157             }
158         }
159         return caseMapping;
160     }
161 
162     /**
163      * This function obtains the ASP Contents for the specified session.
164      */
165     static AspCollection getContents(HttpSession session)
166     {
167         AspCollection collection;
168         synchronized(sessionToAspCollection) {
169             collection = (AspCollection)sessionToAspCollection.get(session.getId());
170             if (collection == null)
171             {
172                 Map caseMapping = getCaseMappings(session);
173                 collection = new AspSynchronizedCollection(session, caseMapping);
174                 sessionToAspCollection.put(session.getId(), collection);
175             }
176         }
177         return collection;
178     }
179 
180     /** This class helps synchronize Asp Session data with Servlet Session
181      * data.
182      */
183     public static class AspSynchronizedCollection extends AspCollection
184         implements SimpleMap
185     {
186         /**
187          * Debugging class
188          */
189         private static Category DBG = Category.getInstance(AspSynchronizedCollection.class);
190 
191         /* The session this collection is attached to */
192         HttpSession session;
193 
194         /* This variable is used to override the session synchronization */
195         boolean connected = true;
196 
197         /* This hashtable is used to keep track of variable case */
198         Map caseMapping = null;
199 
200         /**
201          * Constructor.
202          * @param session Session we are synchronized with.
203          */
204         AspSynchronizedCollection(HttpSession session, Map caseMapping)
205         {
206             this.session = session;
207             this.caseMapping = caseMapping;
208             /* Load all of the stored session data */
209             Set keySet = caseMapping.keySet();
210             for (Iterator i = keySet.iterator(); i.hasNext();)
211             {
212                 String keyLower = (String)i.next();
213                 String key = (String)caseMapping.get(keyLower);
214                 Object value = session.getAttribute(key);
215                 try {
216                     if (value != null) {
217                         internalPut(key, Types.coerceToNode(value));
218                     }
219                 } catch (AspException ex) {
220                     DBG.error("Error during session synchronization", ex);
221                 }
222             }
223         }
224 
225         /**
226          * Obtains the value of data contained within the application
227          * object.
228          * @param obj Value to obtain.
229          * @return value of key obtained
230          * @throws AspException if an error occurs, most likely 
231          *  could not coerce value to string.
232          * @see SimpleMap#get(Object)
233          */
234         public synchronized Object get(Object key)
235             throws AspException
236         {
237             /* If we are not connected, get it from the collection */
238             if (!connected) {
239                 return super.get(key);
240             }
241             /* If we are connected, first try the mapping */
242             String strKey = Types.coerceToString(key);
243             String strAspKey = (String)caseMapping.get(strKey.toLowerCase());
244             /* If we know the key, try the session */
245             if (strAspKey != null)
246             {
247                 Object sessionValue = session.getAttribute(strAspKey);
248                 if (sessionValue != null)
249                 {
250                     /* Found the value from the session */
251                     return Types.coerceToNode(sessionValue);
252                 } else {
253                     return super.get(key);
254                 }
255             } 
256             /* We do not know about this key, let's look for it
257                in the session. First come, first serve. */
258             for (Enumeration e = session.getAttributeNames();e.hasMoreElements();)
259             {
260                 String name = (String)e.nextElement();
261                 if (name.equalsIgnoreCase(strKey)) {
262                     /* Found it */
263                     caseMapping.put(name.toLowerCase(), name);
264                     return Types.coerceToNode(session.getAttribute(name));
265                 }
266             }
267             /* This value is totally unknown. */
268             return Constants.undefinedValueNode;
269         }
270 
271         /**
272          * Internal function to store a value without touching the HttpSession
273          * objects.
274          * @param key Key under which to store this item
275          * @param obj Object to store
276          * @throws AspException if an error occurs
277          */
278         public synchronized void internalPut(Object key, Object obj)
279             throws AspException
280         {
281             String strKey = Types.coerceToString(key);
282             caseMapping.put(strKey.toLowerCase(), strKey);
283             super.put(strKey, obj);
284         }
285 
286         /**
287          * The put method adds an item to this collection
288          * @param key Key under which to store this item
289          * @param obj Object to store
290          * @throws AspException if an error occurs
291          */
292         public synchronized void put(Object key, Object obj) throws AspException
293         {
294             /* Store the value internally */
295             internalPut(key, obj);
296             if (connected)
297             {
298                 /* Place the object into the session */
299                 String str = Types.coerceToString(key);
300                 /* De-reference wrapped Java objects */
301                 Object value = obj;
302                 while (value instanceof JavaObjectNode)
303                     value = ((JavaObjectNode)value).getSubObject();
304                 /* Only store the value if its serializable */
305                 /* Map and List objects are not stored, because they can
306                    contain non-serializable items */
307                 if (value instanceof Serializable &&
308                     !(value instanceof java.util.Map) &&
309                     !(value instanceof java.util.List))
310                 {
311                     if (DBG.isDebugEnabled())
312                         DBG.debug("Storing value " + str + " to session");
313                     /* Store the value into the session */
314                     session.setAttribute(str, value);
315                 } else {
316                     if (DBG.isDebugEnabled())
317                         DBG.debug("Removing value " + str + " from session");
318                     session.removeAttribute(str);
319                 }
320             }
321         }
322 
323         /**
324          * Internal function to remove the element without touching the
325          * HTTPSession.
326          * @param key Key to remove
327          * @throws AspException on error
328          */
329         public synchronized void internalRemove(Object key) throws AspException
330         {
331             String strKey = Types.coerceToString(key);
332             caseMapping.remove(strKey.toLowerCase());
333             super.remove(strKey);
334         }
335     
336         /**
337          * Removes the element from this collection.
338          * @param key Key to remove
339          * @throws AspException on error
340          */
341         public synchronized void remove(Object key) throws AspException
342         {
343             internalRemove(key);
344             if (connected)
345             {
346                 /* Get the key value */
347                 String str = Types.coerceToString(key);
348                 /* Remove all of the matching values from the session. */
349                 for (Enumeration e = session.getAttributeNames();e.hasMoreElements();)
350                 {
351                     String name = (String)e.nextElement();
352                     if (name.equalsIgnoreCase(str)) {
353                         session.removeAttribute(name);
354                     }
355                 }
356             }
357         }
358     
359         /**
360          * Removes all of the elements from this collection.
361          * @throws AspException on error
362          */
363         public synchronized void removeAll() throws AspException
364         {
365             super.removeAll();
366             if (connected)
367             {
368                 /* Remove all values from the session. */
369                 for (Enumeration e = session.getAttributeNames();e.hasMoreElements();)
370                 {
371                     String name = (String)e.nextElement();
372                     session.removeAttribute(name);
373                 }
374             }
375         }
376 
377         /**
378          * Disconnect from the session. Used when sessions are closed so
379          * that setting/removing values to the session does not cause an
380          * invalidated session error.
381          */
382         public void disconnectFromSession()
383         {
384             connected = false;
385         }
386     }
387 }