View Javadoc

1   /*
2    * Copyright 2000-2002,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  // package
18  package org.apache.jetspeed.services.statemanager;
19  
20  // imports
21  import java.util.Iterator;
22  import java.util.HashMap;
23  import java.util.Map;
24  import java.util.Set;
25  import java.util.Collections;
26  import javax.servlet.ServletConfig;
27  import javax.servlet.http.HttpSession;
28  
29  import org.apache.turbine.services.TurbineBaseService;
30  import org.apache.turbine.services.InitializationException;
31  import org.apache.turbine.util.RunData;
32  
33  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
34  import org.apache.jetspeed.services.logging.JetspeedLogger;
35  import org.apache.jetspeed.services.statemanager.StateManagerService;
36  import org.apache.jetspeed.services.statemanager.SessionStateBindingListener;
37  
38  /***
39  * <p>BaseStateManagerService is a Turbine Service implementation of the
40  * StateManagerService.</p>
41  * <p>Each SessionState is stored in a Map, storing the names and values
42  * of the state attributes.</p>
43  * <p>The set of states managed is stored in some specific way by extension classes.</p>
44  * <p>See the proposal: jakarta-jetspeed/proposals/StateManager.txt for more details.</p>
45  * @version $Revision: 1.5 $
46  * @see org.apache.jetspeed.services.statemanager.StateManagerService
47  * @see org.apache.jetspeed.services.statemanager.SessionState
48  * @author <a href="mailto:ggolden@apache.org">Glenn R. Golden</a>
49  */
50  public abstract class BaseStateManagerService
51      extends TurbineBaseService
52      implements StateManagerService
53  {
54      /***
55       * Static initialization of the logger for this class
56       */    
57      private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(BaseStateManagerService.class.getName());
58      
59      /*** map of thread to http session for that thread. */
60      protected Map m_httpSessions = null;
61  
62      /********************************************************************************
63      * Abstract methods
64      *******************************************************************************/
65  
66      /***
67      * Initialize the states storage.
68      */
69      protected abstract void initStates();
70  
71      /***
72      * Cleanup the states storage.
73      */
74      protected abstract void shutdownStates();
75  
76      /***
77      * Access the Map which is the set of attributes for a state.
78      * @param key The state key.
79      * @return The Map which is the set of attributes for a state.
80      */
81      protected abstract Map getState( String key );
82  
83      /***
84      * Add a new state to the states we are managing.
85      * @param key The state key.
86      * @param state The Map which is the set of attributes for the state.
87      */
88      protected abstract void addState( String key, Map state );
89  
90      /***
91      * Remove a state from the states we are managing.
92      * @param key The state key.
93      */
94      protected abstract void removeState( String key );
95  
96      /***
97      * Access an array of the keys of all states managed, those that start with the parameter.
98      * @param start The starting string used to select the keys.
99      * @return an array of the keys of all states managed.
100     */
101     protected abstract String[] getStateKeys( String start );
102 
103     /***
104     * retire the attributes of the state.
105     * @param key The state key.
106     * @param state The Map of attributes to retire.
107     */
108     protected void retireAttributes( String key, Map state )
109     {
110         if (state == null) return;
111 
112         Set attributes = state.entrySet();
113         synchronized (state)
114         {
115             Iterator i = attributes.iterator();
116             while (i.hasNext())
117             {
118                 Map.Entry attribute = (Map.Entry) i.next();
119                 unBindAttributeValue(key, (String)attribute.getKey(), attribute.getValue());
120             }
121         }
122 
123         // remove all attributes
124         state.clear();
125 
126     }   // retireAttributes
127 
128     /***
129     * If the object is a SessionStateBindingListener, unbind it
130     * @param stateKey The state key.
131     * @param attributeName The attribute name.
132     * @param attribute The attribute object
133     */
134     protected void unBindAttributeValue( String stateKey, String attributeName, Object attribute )
135     {
136         // if this object wants session binding notification
137         if ((attribute != null) && (attribute instanceof SessionStateBindingListener))
138         {
139             try
140             {
141                 ((SessionStateBindingListener)attribute)
142                     .valueUnbound(stateKey, attributeName);
143             }
144             catch (Throwable e) 
145             {
146                 logger.warn("JetspeedStateManagerService.unBindAttributeValue: unbinding exception: ", e);
147             }
148         }
149 
150     }   // unBindAttributeValue
151 
152     /***
153     * If the object is a SessionStateBindingListener, bind it
154     * @param stateKey The state key.
155     * @param attributeName The attribute name.
156     * @param attribute The attribute object
157     */
158     protected void bindAttributeValue( String stateKey, String attributeName, Object attribute )
159     {
160         // if this object wants session binding notification
161         if ((attribute != null) && (attribute instanceof SessionStateBindingListener))
162         {
163             try
164             {
165                 ((SessionStateBindingListener)attribute)
166                     .valueBound(stateKey, attributeName);
167             }
168             catch (Throwable e) 
169             {
170                 logger.warn("JetspeedStateManagerService.bindAttributeValue: unbinding exception: ", e);
171             }
172         }
173 
174     }   // bindAttributeValue
175 
176     /********************************************************************************
177     * Service implementation
178     *******************************************************************************/
179 
180     /***
181     * Performs early initialization.
182     *
183     * @param config A ServletConfing to use for initialization
184     * activities.
185     * @exception InitializationException, if initialization of this
186     * class was not successful.
187     */
188     public void init( ServletConfig config )
189         throws InitializationException
190     {
191         super.init(config);
192 
193     }   // init
194 
195     /***
196     * Performs early initialization.
197     *
198     * @param data An RunData to use for initialization activities.
199     * @exception InitializationException, if initialization of this
200     * class was not successful.
201     */
202     public void init( RunData data )
203         throws InitializationException
204     {
205         super.init(data);
206 
207     }   // init
208 
209     /***
210     * Performs late initialization.
211     *
212     * If your class relies on early initialization, and the object it
213     * expects was not received, you can use late initialization to
214     * throw an exception and complain.
215     *
216     * @exception InitializationException, if initialization of this
217     * class was not successful.
218     */
219     public void init()
220         throws InitializationException
221     {
222         super.init();
223 
224         // allocate a thread-safe map to store the "current" http session for each thread
225         m_httpSessions = Collections.synchronizedMap(new HashMap());
226 
227         // create our states storage
228         initStates();
229 
230     }   // init
231 
232     /***
233     * Returns to uninitialized state.
234     *
235     * You can use this method to release resources thet your Service
236     * allocated when Turbine shuts down.
237     */
238     public void shutdown()
239     {
240         m_httpSessions.clear();
241         m_httpSessions = null;
242         shutdownStates();
243         super.shutdown();
244 
245     }   // shutdown
246 
247     /********************************************************************************
248     * StateManagerService implementation
249     *******************************************************************************/
250 
251     /***
252     * Access the named attribute of the keyed state.
253     * @param key The state key.
254     * @param name The attribute name.
255     * @return The named attribute value of the keyed state.
256     */
257     public Object getAttribute ( String key, String name )
258     {
259         Map state = getState(key);
260         if (state == null) return null;
261         return state.get(name);
262 
263     }   // getAttribute
264 
265     /***
266     * Set the named state attribute of the keyed state with the provided object.
267     * @param key The state key.
268     * @param name The attribute name.
269     * @param value The new value of the attribute (any object type).
270     */
271     public void setAttribute( String key, String name, Object value )
272     {
273         Map state = getState(key);
274         if (state == null)
275         {
276             // create a synchronized map to store the state attributes
277             state = Collections.synchronizedMap(new HashMap());
278             addState(key, state);
279         }
280 
281         // get the old, if any
282         Object old = getAttribute(key, name);
283         
284         // store the new
285         state.put(name, value);
286 
287         // if there was an old value, unbind it
288         if (old != null)
289         {
290             unBindAttributeValue(key, name, old);
291         }
292 
293         // bind the new
294         bindAttributeValue(key, name, value);
295 
296     }   // setAttribute
297 
298     /***
299     * Remove the named state attribute of the keyed state, if it exists.
300     * @param key The state key.
301     * @param name The attribute name.
302     */
303     public void removeAttribute( String key, String name )
304     {
305         Map state = getState(key);
306         if (state == null) return;
307 
308         // get the old, if any
309         Object old = getAttribute(key, name);
310 
311         // remove
312         state.remove(name);
313         
314         // if the state is now empty, remove it
315         if (state.isEmpty())
316         {
317             removeState(key);
318         }
319 
320         // if there was an old value, unbind it
321         if (old != null)
322         {
323             unBindAttributeValue(key, name, old);
324         }
325 
326     }   // removeAttribute
327 
328     /***
329     * Remove all state attribute of the keyed state.
330     * @param key The state key.
331     */
332     public void clear( String key )
333     {
334         Map state = getState(key);
335         if (state == null) return;
336 
337         // notify all attribute and clear the state
338         retireAttributes(key, state);
339         
340         // and forget about it
341         removeState(key);
342 
343     }   // clear
344 
345     /***
346     * Access an array of all names of attributes stored in the keyed state.
347     * @param key The state key.
348     * @return An array of all names of attributes stored in the keyed state.
349     */
350     public String[] getAttributeNames( String key )
351     {
352         Map state = (Map) getState(key);
353         if (state == null) return null;
354         if (state.size() == 0) return null;
355 
356         // put the names into an array for return
357         return (String[]) state.keySet().toArray(new String[state.size()]);
358 
359     }   // getAttributeNames
360 
361     /***
362     * Access an SessionState object with the given key.
363     * @param key The SessionState key.
364     * @return an SessionState object with the given key.
365     */
366     public SessionState getSessionState( String key )
367     {
368         return new MySessionState(key, this);
369 
370     }   // getSessionState
371 
372     /***
373     * Access the SessionState object associated with the current request's http session.
374 	* The session id is used as the key.
375     * @return an SessionState object associated with the current request's http session.
376     */
377     public SessionState getCurrentSessionState()
378     {
379         HttpSession session = (HttpSession) m_httpSessions.get(Thread.currentThread());
380         if (session == null) return null;
381 
382         return getSessionState(session.getId());
383 
384     }   // getCurrentSessionState
385 
386     /***
387     * Access the SessionState object associated with the current request's http session with the given key.
388 	* @param key The string to add to the session id to form the SessionState key.
389     * @return an SessionState object associated with the current request's http session with the given key.
390     */
391     public SessionState getCurrentSessionState( String key )
392     {
393         HttpSession session = (HttpSession) m_httpSessions.get(Thread.currentThread());
394         if (session == null) return null;
395 
396         return getSessionState(session.getId() + key);
397 
398     }   // getCurrentSessionState
399 
400     /***
401     * Retire, forget about and clean up all states that start with the given key.
402     * @param keyStart The beginning of the key of the states to clean up.
403     */
404     public synchronized void retireState( String keyStart )
405     {
406         // get the current state keys into an array
407         String keys[] = getStateKeys(keyStart);
408         if (keys == null) return;
409         
410         // clear them
411         for (int i = 0; i < keys.length; i++)
412         {
413             clear(keys[i]);
414         }
415 
416     }   // retireState
417 
418     /***
419     * Set the "current" context for this thread -
420     * Call this at the start of each request, and call %%% at the end.
421     * getCurrentSession() uses this for the session state key.
422     * @param session the HttpSession of the current request.
423     */
424     public void setCurrentContext( HttpSession session )
425     {
426         // store the session associated with this thread
427         m_httpSessions.put(Thread.currentThread(), session);
428 
429     }   // setCurrentContext
430 
431     /***
432     * Clear the "current context for this thread -
433     * Call at the end of each request, balanced with calls to setCurrentContext()
434     */
435     public void clearCurrentContext()
436     {
437         // clear the session associated with this thread
438         m_httpSessions.remove(Thread.currentThread());
439 
440     }    // clearCurrentContext
441 
442     /********************************************************************************
443     * SessionState implementation
444     *******************************************************************************/
445 
446     /***
447     * A SessionState implementation, as covers to this service, storing the key.
448     */
449     private class MySessionState
450         implements SessionState
451     {
452         /*** The state key. */
453         private String m_key = null;
454 
455         /*** The StateManagerService object. */
456         private BaseStateManagerService m_service = null;
457 
458         /***
459         * Construct.
460         * @param key The state key.
461         * @param service The JetspeedStateManagerService instance.
462         */
463         public MySessionState( String key,
464                                 BaseStateManagerService service)
465         {
466             m_key = key;
467             m_service = service;
468 
469         }   // MySessionState
470 
471         /***
472         * Access the named attribute.
473         * @param name The attribute name.
474         * @return The named attribute value.
475         */
476         public Object getAttribute( String name )
477         {
478             return m_service.getAttribute(m_key, name);
479 
480         }   // getAttribute
481 
482         /***
483         * Set the named attribute value to the provided object.
484         * @param name The attribute name.
485         * @param value The value of the attribute (any object type).
486         */
487         public void setAttribute( String name, Object value )
488         {
489             m_service.setAttribute(m_key, name, value);
490 
491         }   // setAttribute
492 
493         /***
494         * Remove the named attribute, if it exists.
495         * @param name The attribute name.
496         */
497         public void removeAttribute( String name )
498         {
499             m_service.removeAttribute(m_key, name);
500 
501         }   // removeAttribute
502 
503         /***
504         * Remove all attributes.
505         */
506         public void clear()
507         {
508             m_service.clear(m_key);
509 
510         }   // clear
511 
512         /***
513         * Access an array of all names of attributes stored in the SessionState.
514         * @return An array of all names of attribute stored in the SessionState.
515         */
516         public String[] getAttributeNames()
517         {
518             return m_service.getAttributeNames(m_key);
519 
520         }   // getAttributeNames
521 
522         /***
523         * Access the full unique StateManager key for the SessionState.
524         * @return the full unique StateManager key for the SessionState.
525         */
526         public String getKey()
527         {
528             return m_key;
529 
530         }   // getKey
531 
532         /***
533         * Retire, forget about and clean up this state.
534         */
535         public void retire()
536         {
537             m_service.retireState(m_key);
538 
539         }   // retire
540 
541     }   // class MySessionState
542 
543 }   // BaseStateManagerService
544 
545 /***********************************************************************************
546 *
547 * $Header: /home/cvs/jakarta-jetspeed/src/java/org/apache/jetspeed/services/statemanager/BaseStateManagerService.java,v 1.5 2004/02/23 03:38:28 jford Exp $
548 *
549 **********************************************************************************/
550