001: /*
002: * PropertiesCacheManager.java
003: *
004: * Brazil project web application Framework,
005: * export version: 1.1
006: * Copyright (c) 2000 Sun Microsystems, Inc.
007: *
008: * Sun Public License Notice
009: *
010: * The contents of this file are subject to the Sun Public License Version
011: * 1.0 (the "License"). You may not use this file except in compliance with
012: * the License. A copy of the License is included as the file "license.terms",
013: * and also available at http://www.sun.com/
014: *
015: * The Original Code is from:
016: * Brazil project web application Framework release 1.1.
017: * The Initial Developer of the Original Code is: suhler.
018: * Portions created by suhler are Copyright (C) Sun Microsystems, Inc.
019: * All Rights Reserved.
020: *
021: * Contributor(s): suhler.
022: *
023: * Version: 1.5
024: * Created by suhler on 00/11/16
025: * Last modified by suhler on 00/12/11 13:32:32
026: */
027:
028: package sunlabs.brazil.session;
029:
030: import java.io.File;
031: import java.io.FileOutputStream;
032: import java.io.FileInputStream;
033: import java.io.IOException;
034: import java.io.Serializable;
035: import java.util.Enumeration;
036: import java.util.Hashtable;
037: import java.util.Properties;
038: import sunlabs.brazil.server.Handler;
039: import sunlabs.brazil.server.Request;
040: import sunlabs.brazil.server.Server;
041: import sunlabs.brazil.util.Glob;
042:
043: /**
044: * Another version of the CacheManager. Saves out any session state
045: * that is a "java properties" into a directory, one file per entry.
046: * Restores them on startup. This is a "poor man's" serialization,
047: * that saves only ascii state represented in properties files.
048: * This permits a wider viriety of changes to be made to the
049: * server code, yet still have the ability to read in the proper
050: * session information.
051: * <p>
052: * This handler/sessionManager can take an ascii-readable "snapshot" of
053: * the server state, for all state that is a java properties object.
054: * It doesn't perturb the existing state.
055: * <p>Properties:
056: * <dl class=props>
057: * <dt>storeDir
058: * <dd>The directory to use to store the state files. It is created as needed
059: * when the state is saved. Defalts to "store".
060: * <dt>match
061: * <dd>A glob pattern that matches the url (or url?query if a query is used.
062: * Defaults to "*\?*save=true".
063: * <dt>filePrefix
064: * <dd>A prefix pattern to use for all session files. Defaults to the
065: * handler prefix.
066: * </dl>
067: *
068: * @author Stephen Uhler (stephen.uhler@sun.com)
069: * @version %V% PropertiesCacheManager.java
070: */
071:
072: public class PropertiesCacheManager extends CacheManager implements
073: Handler, Serializable {
074: private static final String STORE = "storeDir";
075: private static final String MATCH = "match";
076: private static final String PREFIX = "filePrefix";
077:
078: /*
079: * Change VERSION to indicate in-compatibility across code versions
080: */
081:
082: private static final String VERSION = "types.1";
083:
084: String storeDir;
085: String match;
086: String filePrefix;
087:
088: public boolean init(Server server, String prefix) {
089: super .init(server, prefix);
090: storeDir = server.props.getProperty(prefix + STORE, "store");
091: match = server.props.getProperty(prefix + MATCH,
092: "*\\?*save=true");
093: filePrefix = server.props.getProperty(prefix + PREFIX, prefix);
094:
095: /*
096: * Read in the directory of saved state, if any.
097: * Each file name is in the form [prefix][key].
098: * A separate file, [prefix]types contains the names and
099: * types of each session.
100: */
101:
102: File dir = new File(storeDir);
103: Properties types = new Properties();
104: try {
105: FileInputStream in = new FileInputStream(new File(dir,
106: filePrefix + VERSION));
107: types.load(in);
108: in.close();
109: server.log(Server.LOG_WARNING, prefix,
110: "Loading saved state from: " + storeDir);
111: } catch (Exception ex) {
112: server.log(Server.LOG_WARNING, prefix,
113: "Can't find existing state file: " + filePrefix
114: + VERSION + " in: " + dir);
115: }
116: Enumeration el = types.keys();
117: while (el.hasMoreElements()) {
118: String key = (String) el.nextElement();
119: String type = types.getProperty(key);
120: server.log(Server.LOG_DIAGNOSTIC, prefix,
121: "Loading session " + key);
122: Properties data;
123: try {
124: data = (Properties) Class.forName(type).newInstance();
125: FileInputStream in = new FileInputStream(new File(dir,
126: filePrefix + key));
127: data.load(in);
128: put(key, data);
129: in.close();
130: } catch (Exception e) {
131: server.log(Server.LOG_WARNING, prefix,
132: "Error reading state file: " + e.getMessage());
133: }
134: }
135: return true;
136: }
137:
138: public boolean respond(Request request) {
139: String check;
140: if (request.query.equals("")) {
141: check = request.url;
142: } else {
143: check = request.url + "?" + request.query;
144: }
145: if (Glob.match(match, check)) {
146: save(request);
147: }
148: return false;
149: }
150:
151: /**
152: * Save all of the properties files!
153: * We make a TOC file that has type info, so we can reconstitue the
154: * proper subclasses of Properties.
155: */
156:
157: int save(Request request) {
158: File dir = new File(storeDir);
159: dir.mkdirs(); // make sure directories exist
160: int count = 0;
161: Properties types = new Properties();
162:
163: /*
164: * If we read in the existing types file to start with, we can
165: * "augment" the state from a previous save.
166: */
167:
168: request.log(Server.LOG_LOG, prefix, "saving all session state");
169: try {
170: FileInputStream in = new FileInputStream(new File(dir,
171: filePrefix + VERSION));
172: types.load(in);
173: in.close();
174: request.log(Server.LOG_DIAGNOSTIC, prefix,
175: "reading existing session state file");
176: } catch (Exception ex) {
177: request.log(Server.LOG_DIAGNOSTIC, prefix,
178: "No existing state files found");
179: }
180:
181: /*
182: * Iterate through the tables, saving every session that is a
183: * properties file.
184: */
185:
186: synchronized (pool) {
187: for (int i = 0; i < maxTables; i++) {
188: Hashtable h = pool[i];
189: if (h != null) {
190: Enumeration e = h.keys();
191: while (e.hasMoreElements()) {
192: Object key = e.nextElement();
193: Object value = h.get(key);
194: if (value instanceof Properties) {
195: request.log(Server.LOG_DIAGNOSTIC, prefix,
196: "Saving state for session " + key);
197: String type = value.getClass().getName();
198: types.put(key, type);
199: try {
200: FileOutputStream props = new FileOutputStream(
201: new File(dir, filePrefix
202: + key.toString()));
203: ((Properties) value).save(props,
204: "Brazil server state from "
205: + request.serverUrl());
206: count++;
207: props.close();
208: } catch (IOException ex) {
209: request.log(Server.LOG_DIAGNOSTIC,
210: prefix, "Failed: "
211: + ex.getMessage());
212: }
213: } else {
214: // System.out.println("Not a properties: " + key);
215: }
216: }
217: }
218: }
219:
220: /*
221: * Now write out the TOC file
222: */
223:
224: try {
225: FileOutputStream out = new FileOutputStream(new File(
226: dir, filePrefix + VERSION));
227: types.save(out, "Brazil server state from "
228: + request.serverUrl());
229: out.close();
230: } catch (IOException ex) {
231: request.log(Server.LOG_DIAGNOSTIC, prefix,
232: "Saving TOC file");
233: }
234: }
235: return count;
236: }
237: }
|