/* * Copyright 2000-2002,2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // package package org.apache.jetspeed.services.statemanager; // imports import java.util.Iterator; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.Collections; import javax.servlet.ServletConfig; import javax.servlet.http.HttpSession; import org.apache.turbine.services.TurbineBaseService; import org.apache.turbine.services.InitializationException; import org.apache.turbine.util.RunData; import org.apache.jetspeed.services.logging.JetspeedLogFactoryService; import org.apache.jetspeed.services.logging.JetspeedLogger; import org.apache.jetspeed.services.statemanager.StateManagerService; import org.apache.jetspeed.services.statemanager.SessionStateBindingListener; /** * <p>BaseStateManagerService is a Turbine Service implementation of the * StateManagerService.</p> * <p>Each SessionState is stored in a Map, storing the names and values * of the state attributes.</p> * <p>The set of states managed is stored in some specific way by extension classes.</p> * <p>See the proposal: jakarta-jetspeed/proposals/StateManager.txt for more details.</p> * @version $Revision: 1.5 $ * @see org.apache.jetspeed.services.statemanager.StateManagerService * @see org.apache.jetspeed.services.statemanager.SessionState * @author <a href="mailto:ggolden@apache.org">Glenn R. Golden</a> */ public abstract class BaseStateManagerService extends TurbineBaseService implements StateManagerService { /** * Static initialization of the logger for this class */ private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(BaseStateManagerService.class.getName()); /** map of thread to http session for that thread. */ protected Map m_httpSessions = null; /******************************************************************************* * Abstract methods *******************************************************************************/ /** * Initialize the states storage. */ protected abstract void initStates(); /** * Cleanup the states storage. */ protected abstract void shutdownStates(); /** * Access the Map which is the set of attributes for a state. * @param key The state key. * @return The Map which is the set of attributes for a state. */ protected abstract Map getState( String key ); /** * Add a new state to the states we are managing. * @param key The state key. * @param state The Map which is the set of attributes for the state. */ protected abstract void addState( String key, Map state ); /** * Remove a state from the states we are managing. * @param key The state key. */ protected abstract void removeState( String key ); /** * Access an array of the keys of all states managed, those that start with the parameter. * @param start The starting string used to select the keys. * @return an array of the keys of all states managed. */ protected abstract String[] getStateKeys( String start ); /** * retire the attributes of the state. * @param key The state key. * @param state The Map of attributes to retire. */ protected void retireAttributes( String key, Map state ) { if (state == null) return; Set attributes = state.entrySet(); synchronized (state) { Iterator i = attributes.iterator(); while (i.hasNext()) { Map.Entry attribute = (Map.Entry) i.next(); unBindAttributeValue(key, (String)attribute.getKey(), attribute.getValue()); } } // remove all attributes state.clear(); } // retireAttributes /** * If the object is a SessionStateBindingListener, unbind it * @param stateKey The state key. * @param attributeName The attribute name. * @param attribute The attribute object */ protected void unBindAttributeValue( String stateKey, String attributeName, Object attribute ) { // if this object wants session binding notification if ((attribute != null) && (attribute instanceof SessionStateBindingListener)) { try { ((SessionStateBindingListener)attribute) .valueUnbound(stateKey, attributeName); } catch (Throwable e) { logger.warn("JetspeedStateManagerService.unBindAttributeValue: unbinding exception: ", e); } } } // unBindAttributeValue /** * If the object is a SessionStateBindingListener, bind it * @param stateKey The state key. * @param attributeName The attribute name. * @param attribute The attribute object */ protected void bindAttributeValue( String stateKey, String attributeName, Object attribute ) { // if this object wants session binding notification if ((attribute != null) && (attribute instanceof SessionStateBindingListener)) { try { ((SessionStateBindingListener)attribute) .valueBound(stateKey, attributeName); } catch (Throwable e) { logger.warn("JetspeedStateManagerService.bindAttributeValue: unbinding exception: ", e); } } } // bindAttributeValue /******************************************************************************* * Service implementation *******************************************************************************/ /** * Performs early initialization. * * @param config A ServletConfing to use for initialization * activities. * @exception InitializationException, if initialization of this * class was not successful. */ public void init( ServletConfig config ) throws InitializationException { super.init(config); } // init /** * Performs early initialization. * * @param data An RunData to use for initialization activities. * @exception InitializationException, if initialization of this * class was not successful. */ public void init( RunData data ) throws InitializationException { super.init(data); } // init /** * Performs late initialization. * * If your class relies on early initialization, and the object it * expects was not received, you can use late initialization to * throw an exception and complain. * * @exception InitializationException, if initialization of this * class was not successful. */ public void init() throws InitializationException { super.init(); // allocate a thread-safe map to store the "current" http session for each thread m_httpSessions = Collections.synchronizedMap(new HashMap()); // create our states storage initStates(); } // init /** * Returns to uninitialized state. * * You can use this method to release resources thet your Service * allocated when Turbine shuts down. */ public void shutdown() { m_httpSessions.clear(); m_httpSessions = null; shutdownStates(); super.shutdown(); } // shutdown /******************************************************************************* * StateManagerService implementation *******************************************************************************/ /** * Access the named attribute of the keyed state. * @param key The state key. * @param name The attribute name. * @return The named attribute value of the keyed state. */ public Object getAttribute ( String key, String name ) { Map state = getState(key); if (state == null) return null; return state.get(name); } // getAttribute /** * Set the named state attribute of the keyed state with the provided object. * @param key The state key. * @param name The attribute name. * @param value The new value of the attribute (any object type). */ public void setAttribute( String key, String name, Object value ) { Map state = getState(key); if (state == null) { // create a synchronized map to store the state attributes state = Collections.synchronizedMap(new HashMap()); addState(key, state); } // get the old, if any Object old = getAttribute(key, name); // store the new state.put(name, value); // if there was an old value, unbind it if (old != null) { unBindAttributeValue(key, name, old); } // bind the new bindAttributeValue(key, name, value); } // setAttribute /** * Remove the named state attribute of the keyed state, if it exists. * @param key The state key. * @param name The attribute name. */ public void removeAttribute( String key, String name ) { Map state = getState(key); if (state == null) return; // get the old, if any Object old = getAttribute(key, name); // remove state.remove(name); // if the state is now empty, remove it if (state.isEmpty()) { removeState(key); } // if there was an old value, unbind it if (old != null) { unBindAttributeValue(key, name, old); } } // removeAttribute /** * Remove all state attribute of the keyed state. * @param key The state key. */ public void clear( String key ) { Map state = getState(key); if (state == null) return; // notify all attribute and clear the state retireAttributes(key, state); // and forget about it removeState(key); } // clear /** * Access an array of all names of attributes stored in the keyed state. * @param key The state key. * @return An array of all names of attributes stored in the keyed state. */ public String[] getAttributeNames( String key ) { Map state = (Map) getState(key); if (state == null) return null; if (state.size() == 0) return null; // put the names into an array for return return (String[]) state.keySet().toArray(new String[state.size()]); } // getAttributeNames /** * Access an SessionState object with the given key. * @param key The SessionState key. * @return an SessionState object with the given key. */ public SessionState getSessionState( String key ) { return new MySessionState(key, this); } // getSessionState /** * Access the SessionState object associated with the current request's http session. * The session id is used as the key. * @return an SessionState object associated with the current request's http session. */ public SessionState getCurrentSessionState() { HttpSession session = (HttpSession) m_httpSessions.get(Thread.currentThread()); if (session == null) return null; return getSessionState(session.getId()); } // getCurrentSessionState /** * Access the SessionState object associated with the current request's http session with the given key. * @param key The string to add to the session id to form the SessionState key. * @return an SessionState object associated with the current request's http session with the given key. */ public SessionState getCurrentSessionState( String key ) { HttpSession session = (HttpSession) m_httpSessions.get(Thread.currentThread()); if (session == null) return null; return getSessionState(session.getId() + key); } // getCurrentSessionState /** * Retire, forget about and clean up all states that start with the given key. * @param keyStart The beginning of the key of the states to clean up. */ public synchronized void retireState( String keyStart ) { // get the current state keys into an array String keys[] = getStateKeys(keyStart); if (keys == null) return; // clear them for (int i = 0; i < keys.length; i++) { clear(keys[i]); } } // retireState /** * Set the "current" context for this thread - * Call this at the start of each request, and call %%% at the end. * getCurrentSession() uses this for the session state key. * @param session the HttpSession of the current request. */ public void setCurrentContext( HttpSession session ) { // store the session associated with this thread m_httpSessions.put(Thread.currentThread(), session); } // setCurrentContext /** * Clear the "current context for this thread - * Call at the end of each request, balanced with calls to setCurrentContext() */ public void clearCurrentContext() { // clear the session associated with this thread m_httpSessions.remove(Thread.currentThread()); } // clearCurrentContext /******************************************************************************* * SessionState implementation *******************************************************************************/ /** * A SessionState implementation, as covers to this service, storing the key. */ private class MySessionState implements SessionState { /** The state key. */ private String m_key = null; /** The StateManagerService object. */ private BaseStateManagerService m_service = null; /** * Construct. * @param key The state key. * @param service The JetspeedStateManagerService instance. */ public MySessionState( String key, BaseStateManagerService service) { m_key = key; m_service = service; } // MySessionState /** * Access the named attribute. * @param name The attribute name. * @return The named attribute value. */ public Object getAttribute( String name ) { return m_service.getAttribute(m_key, name); } // getAttribute /** * Set the named attribute value to the provided object. * @param name The attribute name. * @param value The value of the attribute (any object type). */ public void setAttribute( String name, Object value ) { m_service.setAttribute(m_key, name, value); } // setAttribute /** * Remove the named attribute, if it exists. * @param name The attribute name. */ public void removeAttribute( String name ) { m_service.removeAttribute(m_key, name); } // removeAttribute /** * Remove all attributes. */ public void clear() { m_service.clear(m_key); } // clear /** * Access an array of all names of attributes stored in the SessionState. * @return An array of all names of attribute stored in the SessionState. */ public String[] getAttributeNames() { return m_service.getAttributeNames(m_key); } // getAttributeNames /** * Access the full unique StateManager key for the SessionState. * @return the full unique StateManager key for the SessionState. */ public String getKey() { return m_key; } // getKey /** * Retire, forget about and clean up this state. */ public void retire() { m_service.retireState(m_key); } // retire } // class MySessionState } // BaseStateManagerService /********************************************************************************** * * $Header: /home/cvspublic/jakarta-jetspeed/src/java/org/apache/jetspeed/services/statemanager/BaseStateManagerService.java,v 1.5 2004/02/23 03:38:28 jford Exp $ * **********************************************************************************/