001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.session;
018:
019: import java.beans.PropertyChangeListener;
020: import java.beans.PropertyChangeSupport;
021: import java.io.IOException;
022:
023: import org.apache.catalina.Container;
024: import org.apache.catalina.Lifecycle;
025: import org.apache.catalina.LifecycleException;
026: import org.apache.catalina.LifecycleListener;
027: import org.apache.catalina.Logger;
028: import org.apache.catalina.Manager;
029: import org.apache.catalina.Store;
030: import org.apache.catalina.util.LifecycleSupport;
031: import org.apache.catalina.util.StringManager;
032:
033: /**
034: * Abstract implementation of the Store interface to
035: * support most of the functionality required by a Store.
036: *
037: * @author Bip Thelin
038: * @version $Revision: 1.8 $, $Date: 2004/05/22 23:23:23 $
039: */
040:
041: public abstract class StoreBase implements Lifecycle, Store {
042:
043: // ----------------------------------------------------- Instance Variables
044:
045: /**
046: * The descriptive information about this implementation.
047: */
048: protected static String info = "StoreBase/1.0";
049:
050: /**
051: * Name to register for this Store, used for logging.
052: */
053: protected static String storeName = "StoreBase";
054:
055: /**
056: * The debugging detail level for this component.
057: */
058: protected int debug = 0;
059:
060: /**
061: * Has this component been started yet?
062: */
063: protected boolean started = false;
064:
065: /**
066: * The lifecycle event support for this component.
067: */
068: protected LifecycleSupport lifecycle = new LifecycleSupport(this );
069:
070: /**
071: * The property change support for this component.
072: */
073: protected PropertyChangeSupport support = new PropertyChangeSupport(
074: this );
075:
076: /**
077: * The string manager for this package.
078: */
079: protected StringManager sm = StringManager
080: .getManager(Constants.Package);
081:
082: /**
083: * The Manager with which this JDBCStore is associated.
084: */
085: protected Manager manager;
086:
087: // ------------------------------------------------------------- Properties
088:
089: /**
090: * Return the info for this Store.
091: */
092: public String getInfo() {
093: return (info);
094: }
095:
096: /**
097: * Return the name for this Store, used for logging.
098: */
099: public String getStoreName() {
100: return (storeName);
101: }
102:
103: /**
104: * Set the debugging detail level for this Store.
105: *
106: * @param debug The new debugging detail level
107: */
108: public void setDebug(int debug) {
109: this .debug = debug;
110: }
111:
112: /**
113: * Return the debugging detail level for this Store.
114: */
115: public int getDebug() {
116: return (this .debug);
117: }
118:
119: /**
120: * Set the Manager with which this Store is associated.
121: *
122: * @param manager The newly associated Manager
123: */
124: public void setManager(Manager manager) {
125: Manager oldManager = this .manager;
126: this .manager = manager;
127: support.firePropertyChange("manager", oldManager, this .manager);
128: }
129:
130: /**
131: * Return the Manager with which the Store is associated.
132: */
133: public Manager getManager() {
134: return (this .manager);
135: }
136:
137: // --------------------------------------------------------- Public Methods
138:
139: /**
140: * Add a lifecycle event listener to this component.
141: *
142: * @param listener The listener to add
143: */
144: public void addLifecycleListener(LifecycleListener listener) {
145: lifecycle.addLifecycleListener(listener);
146: }
147:
148: /**
149: * Get the lifecycle listeners associated with this lifecycle. If this
150: * Lifecycle has no listeners registered, a zero-length array is returned.
151: */
152: public LifecycleListener[] findLifecycleListeners() {
153:
154: return lifecycle.findLifecycleListeners();
155:
156: }
157:
158: /**
159: * Remove a lifecycle event listener from this component.
160: *
161: * @param listener The listener to add
162: */
163: public void removeLifecycleListener(LifecycleListener listener) {
164: lifecycle.removeLifecycleListener(listener);
165: }
166:
167: /**
168: * Add a property change listener to this component.
169: *
170: * @param listener a value of type 'PropertyChangeListener'
171: */
172: public void addPropertyChangeListener(
173: PropertyChangeListener listener) {
174: support.addPropertyChangeListener(listener);
175: }
176:
177: /**
178: * Remove a property change listener from this component.
179: *
180: * @param listener The listener to remove
181: */
182: public void removePropertyChangeListener(
183: PropertyChangeListener listener) {
184: support.removePropertyChangeListener(listener);
185: }
186:
187: // --------------------------------------------------------- Protected Methods
188:
189: /**
190: * Called by our background reaper thread to check if Sessions
191: * saved in our store are subject of being expired. If so expire
192: * the Session and remove it from the Store.
193: *
194: */
195: public void processExpires() {
196: long timeNow = System.currentTimeMillis();
197: String[] keys = null;
198:
199: if (!started) {
200: return;
201: }
202:
203: try {
204: keys = keys();
205: } catch (IOException e) {
206: log(e.toString());
207: e.printStackTrace();
208: return;
209: }
210:
211: for (int i = 0; i < keys.length; i++) {
212: try {
213: StandardSession session = (StandardSession) load(keys[i]);
214: if (session == null) {
215: continue;
216: }
217: if (session.isValid()) {
218: continue;
219: }
220: if (((PersistentManagerBase) manager).isLoaded(keys[i])) {
221: // recycle old backup session
222: session.recycle();
223: } else {
224: // expire swapped out session
225: session.expire();
226: }
227: remove(session.getId());
228: } catch (Exception e) {
229: log("Session: " + keys[i] + "; " + e.toString());
230: try {
231: remove(keys[i]);
232: } catch (IOException e2) {
233: log(e2.toString());
234: e2.printStackTrace();
235: }
236: }
237: }
238: }
239:
240: /**
241: * Log a message on the Logger associated with our Container (if any).
242: *
243: * @param message Message to be logged
244: */
245: protected void log(String message) {
246: Logger logger = null;
247: Container container = manager.getContainer();
248:
249: if (container != null) {
250: logger = container.getLogger();
251: }
252:
253: if (logger != null) {
254: logger.log(getStoreName() + "[" + container.getName()
255: + "]: " + message);
256: } else {
257: String containerName = null;
258: if (container != null) {
259: containerName = container.getName();
260: }
261: System.out.println(getStoreName() + "[" + containerName
262: + "]: " + message);
263: }
264: }
265:
266: // --------------------------------------------------------- Thread Methods
267:
268: /**
269: * Prepare for the beginning of active use of the public methods of this
270: * component. This method should be called after <code>configure()</code>,
271: * and before any of the public methods of the component are utilized.
272: *
273: * @exception LifecycleException if this component detects a fatal error
274: * that prevents this component from being used
275: */
276: public void start() throws LifecycleException {
277: // Validate and update our current component state
278: if (started)
279: throw new LifecycleException(sm.getString(getStoreName()
280: + ".alreadyStarted"));
281: lifecycle.fireLifecycleEvent(START_EVENT, null);
282: started = true;
283:
284: }
285:
286: /**
287: * Gracefully terminate the active use of the public methods of this
288: * component. This method should be the last one called on a given
289: * instance of this component.
290: *
291: * @exception LifecycleException if this component detects a fatal error
292: * that needs to be reported
293: */
294: public void stop() throws LifecycleException {
295: // Validate and update our current component state
296: if (!started)
297: throw new LifecycleException(sm.getString(getStoreName()
298: + ".notStarted"));
299: lifecycle.fireLifecycleEvent(STOP_EVENT, null);
300: started = false;
301:
302: }
303:
304: }
|