| /* |
| * Copyright 1999,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 org.apache.catalina.session; |
| |
| import java.beans.PropertyChangeListener; |
| import java.beans.PropertyChangeSupport; |
| import java.io.IOException; |
| |
| import org.apache.catalina.Lifecycle; |
| import org.apache.catalina.LifecycleException; |
| import org.apache.catalina.LifecycleListener; |
| import org.apache.catalina.Manager; |
| import org.apache.catalina.Store; |
| import org.apache.catalina.util.LifecycleSupport; |
| import org.apache.catalina.util.StringManager; |
| |
| /** |
| * Abstract implementation of the Store interface to |
| * support most of the functionality required by a Store. |
| * |
| * @author Bip Thelin |
| * @version $Revision$, $Date$ |
| */ |
| |
| public abstract class StoreBase |
| implements Lifecycle, Store { |
| |
| // ----------------------------------------------------- Instance Variables |
| |
| /** |
| * The descriptive information about this implementation. |
| */ |
| protected static String info = "StoreBase/1.0"; |
| |
| /** |
| * Name to register for this Store, used for logging. |
| */ |
| protected static String storeName = "StoreBase"; |
| |
| /** |
| * Has this component been started yet? |
| */ |
| protected boolean started = false; |
| |
| /** |
| * The lifecycle event support for this component. |
| */ |
| protected LifecycleSupport lifecycle = new LifecycleSupport(this); |
| |
| /** |
| * The property change support for this component. |
| */ |
| protected PropertyChangeSupport support = new PropertyChangeSupport(this); |
| |
| /** |
| * The string manager for this package. |
| */ |
| protected StringManager sm = StringManager.getManager(Constants.Package); |
| |
| /** |
| * The Manager with which this JDBCStore is associated. |
| */ |
| protected Manager manager; |
| |
| // ------------------------------------------------------------- Properties |
| |
| /** |
| * Return the info for this Store. |
| */ |
| public String getInfo() { |
| return(info); |
| } |
| |
| |
| /** |
| * Return the name for this Store, used for logging. |
| */ |
| public String getStoreName() { |
| return(storeName); |
| } |
| |
| |
| /** |
| * Set the Manager with which this Store is associated. |
| * |
| * @param manager The newly associated Manager |
| */ |
| public void setManager(Manager manager) { |
| Manager oldManager = this.manager; |
| this.manager = manager; |
| support.firePropertyChange("manager", oldManager, this.manager); |
| } |
| |
| /** |
| * Return the Manager with which the Store is associated. |
| */ |
| public Manager getManager() { |
| return(this.manager); |
| } |
| |
| |
| // --------------------------------------------------------- Public Methods |
| |
| /** |
| * Add a lifecycle event listener to this component. |
| * |
| * @param listener The listener to add |
| */ |
| public void addLifecycleListener(LifecycleListener listener) { |
| lifecycle.addLifecycleListener(listener); |
| } |
| |
| |
| /** |
| * Get the lifecycle listeners associated with this lifecycle. If this |
| * Lifecycle has no listeners registered, a zero-length array is returned. |
| */ |
| public LifecycleListener[] findLifecycleListeners() { |
| |
| return lifecycle.findLifecycleListeners(); |
| |
| } |
| |
| |
| /** |
| * Remove a lifecycle event listener from this component. |
| * |
| * @param listener The listener to add |
| */ |
| public void removeLifecycleListener(LifecycleListener listener) { |
| lifecycle.removeLifecycleListener(listener); |
| } |
| |
| /** |
| * Add a property change listener to this component. |
| * |
| * @param listener a value of type 'PropertyChangeListener' |
| */ |
| public void addPropertyChangeListener(PropertyChangeListener listener) { |
| support.addPropertyChangeListener(listener); |
| } |
| |
| /** |
| * Remove a property change listener from this component. |
| * |
| * @param listener The listener to remove |
| */ |
| public void removePropertyChangeListener(PropertyChangeListener listener) { |
| support.removePropertyChangeListener(listener); |
| } |
| |
| // --------------------------------------------------------- Protected Methods |
| |
| /** |
| * Called by our background reaper thread to check if Sessions |
| * saved in our store are subject of being expired. If so expire |
| * the Session and remove it from the Store. |
| * |
| */ |
| public void processExpires() { |
| long timeNow = System.currentTimeMillis(); |
| String[] keys = null; |
| |
| if(!started) { |
| return; |
| } |
| |
| try { |
| keys = keys(); |
| } catch (IOException e) { |
| manager.getContainer().getLogger().error("Error getting keys", e); |
| return; |
| } |
| if (manager.getContainer().getLogger().isDebugEnabled()) { |
| manager.getContainer().getLogger().debug(getStoreName()+ ": processExpires check number of " + keys.length + " sessions" ); |
| } |
| |
| for (int i = 0; i < keys.length; i++) { |
| try { |
| StandardSession session = (StandardSession) load(keys[i]); |
| if (session == null) { |
| continue; |
| } |
| if (session.isValid()) { |
| continue; |
| } |
| if (manager.getContainer().getLogger().isDebugEnabled()) { |
| manager.getContainer().getLogger().debug(getStoreName()+ ": processExpires expire store session " + keys[i] ); |
| } |
| if ( ( (PersistentManagerBase) manager).isLoaded( keys[i] )) { |
| // recycle old backup session |
| session.recycle(); |
| } else { |
| // expire swapped out session |
| session.expire(); |
| } |
| remove(session.getId()); |
| } catch (Exception e) { |
| manager.getContainer().getLogger().error("Session: "+keys[i]+"; ", e); |
| try { |
| remove(keys[i]); |
| } catch (IOException e2) { |
| manager.getContainer().getLogger().error("Error removing key", e2); |
| } |
| } |
| } |
| } |
| |
| |
| // --------------------------------------------------------- Thread Methods |
| |
| |
| /** |
| * Prepare for the beginning of active use of the public methods of this |
| * component. This method should be called after <code>configure()</code>, |
| * and before any of the public methods of the component are utilized. |
| * |
| * @exception LifecycleException if this component detects a fatal error |
| * that prevents this component from being used |
| */ |
| public void start() throws LifecycleException { |
| // Validate and update our current component state |
| if (started) |
| throw new LifecycleException |
| (sm.getString(getStoreName()+".alreadyStarted")); |
| lifecycle.fireLifecycleEvent(START_EVENT, null); |
| started = true; |
| |
| } |
| |
| |
| /** |
| * Gracefully terminate the active use of the public methods of this |
| * component. This method should be the last one called on a given |
| * instance of this component. |
| * |
| * @exception LifecycleException if this component detects a fatal error |
| * that needs to be reported |
| */ |
| public void stop() throws LifecycleException { |
| // Validate and update our current component state |
| if (!started) |
| throw new LifecycleException |
| (sm.getString(getStoreName()+".notStarted")); |
| lifecycle.fireLifecycleEvent(STOP_EVENT, null); |
| started = false; |
| |
| } |
| |
| |
| } |