All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sunlabs.brazil.handler.ConfigFileHandler Maven / Gradle / Ivy

The newest version!
/*
 * ConfigFileHandler.java
 *
 * Brazil project web application toolkit,
 * export version: 2.3 
 * Copyright (c) 1999-2004 Sun Microsystems, Inc.
 *
 * Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License Version 
 * 1.0 (the "License"). You may not use this file except in compliance with 
 * the License. A copy of the License is included as the file "license.terms",
 * and also available at http://www.sun.com/
 * 
 * The Original Code is from:
 *    Brazil project web application toolkit release 2.3.
 * The Initial Developer of the Original Code is: suhler.
 * Portions created by suhler are Copyright (C) Sun Microsystems, Inc.
 * All Rights Reserved.
 * 
 * Contributor(s): cstevens, rinaldo, suhler.
 *
 * Version:  2.2
 * Created by suhler on 99/06/28
 * Last modified by suhler on 04/08/30 09:02:07
 *
 * Version Histories:
 *
 * 2.2 04/08/30-09:02:07 (suhler)
 *   "enum" became a reserved word, change to "enumer".
 *
 * 2.1 02/10/01-16:36:34 (suhler)
 *   version change
 *
 * 1.35 02/07/24-10:45:56 (suhler)
 *   doc updates
 *
 * 1.34 01/12/10-16:11:12 (suhler)
 *   doc lint
 *
 * 1.33 01/05/18-09:11:40 (suhler)
 *   work with either CookieSessionHAndler -or- SessionFilter
 *
 * 1.32 01/01/22-19:02:30 (cstevens)
 *   Remove RechainableProperties from Request.  In order to insert shared
 *   Properties objects, use request.addSharedProps() instead of manually
 *   rechaining the properties using props.setDefaults().
 *
 * 1.31 00/12/11-13:28:21 (suhler)
 *   add class=props for automatic property extraction
 *
 * 1.30 00/11/20-13:28:06 (suhler)
 *   lint
 *   D
 *
 * 1.29 00/11/20-13:21:35 (suhler)
 *   doc fixes
 *
 * 1.28 00/10/05-11:06:46 (suhler)
 *   The property "glob" can be used to match a patterns of request.props
 *   that may be set by the user that are NOT in the default config file.  If
 *   "glob" is specified, no default file is required.
 *
 * 1.27 00/05/31-13:47:26 (suhler)
 *   doc cleanup
 *
 * 1.26 00/05/24-11:35:36 (suhler)
 *   added a "copy" property to implement old behavior for backward compatibility
 *
 * 1.25 00/05/22-14:03:48 (suhler)
 *   doc updates
 *
 * 1.24 00/05/15-12:04:29 (suhler)
 *   added chaining back in, removing (impossible) behind option
 *   added more diags
 *
 * 1.23 00/05/12-15:25:10 (suhler)
 *   temporarily back out properties chaining
 *
 * 1.22 00/05/10-10:54:06 (suhler)
 *   No longer add config properties directly to request.props.
 *   Instead, use the ChainedProperties.
 *   added "noOverride" option to prevent properties from ovverriding
 *   values that already exist
 *
 * 1.21 00/04/20-11:50:15 (cstevens)
 *   copyright.
 *
 * 1.20 00/04/12-15:53:16 (cstevens)
 *   imports
 *
 * 1.19 00/03/29-14:35:55 (cstevens)
 *   pedantic use of Request.getQueryData()
 *
 * 1.18 00/02/11-12:42:44 (suhler)
 *   arguments to Match wrong
 *
 * 1.17 00/02/03-14:24:40 (suhler)
 *   added "no content" option
 *
 * 1.16 99/12/15-12:02:39 (suhler)
 *   Properties we not being passed on if a "set" was atempted, and no
 *   values were changed
 *
 * 1.15 99/12/07-10:55:17 (suhler)
 *   set request properties *after* processing SET query parameters
 *
 * 1.14 99/11/30-09:47:38 (suhler)
 *   Redo.  Only generate session based files when really needed
 *
 * 1.12.1.1 99/11/14-10:34:55 (rinaldo)
 *   Fix Error with Mime Type
 *
 * 1.13 99/11/01-11:56:37 (suhler)
 *   ConfigFile handler gets root property at each request
 *
 * 1.12 99/10/26-17:11:10 (cstevens)
 *   Get rid of public variables Request.server and Request.sock:
 *   A. In all cases, Request.server was not necessary; it was mainly used for
 *   constructing the absolute URL for a redirect, so Request.redirect() was
 *   rewritten to take an absolute or relative URL and do the right thing.
 *   B. Request.sock was changed to Request.getSock(); it is still rarely used
 *   for diagnostics and logging (e.g., ChainSawHandler).
 *
 * 1.10.1.1 99/10/23-19:47:18 (rinaldo)
 *
 * 1.11 99/10/11-12:30:44 (suhler)
 *   change POST to GET when done processing.
 *
 * 1.10 99/10/06-12:28:41 (suhler)
 *   fix log
 *
 * 1.9 99/10/06-12:20:32 (suhler)
 *   Merged changes between child workspace "/home/suhler/brazil/naws" and
 *   parent workspace "/net/mack.eng/export/ws/brazil/naws".
 *
 * 1.8 99/10/01-11:26:36 (cstevens)
 *   Change logging to show prefix of Handler generating the log message.
 *
 * 1.7.1.2 99/09/27-17:47:30 (suhler)
 *   Entirely new semantics.  This will break all existing uses:
 *   - the "config" file is always merged into the request properties
 *   - a separate url is used to set the properties
 *   - a default properties file is required, and the existing properties limit
 *   what is allowed to be set.
 *
 * 1.7.1.1 99/09/10-11:02:53 (suhler)
 *   ???
 *
 * 1.7 99/08/06-12:11:06 (suhler)
 *   Merged changes between child workspace "/home/suhler/brazil/naws" and
 *   parent workspace "/net/mack.eng/export/ws/brazil/naws".
 *
 * 1.5.1.2 99/08/06-12:05:18 (suhler)
 *   use glob in util directory
 *   ,
 *   .
 *   D
 *
 * 1.5.1.1 99/08/04-18:44:31 (suhler)
 *   Changes to allow session specific file names
 *
 * 1.6 99/07/27-22:02:32 (rinaldo)
 *   Stephen, you will probably not like what I did but it is late and I have to
 *   have the properties I just set be available to all sunsequent url requests tak
 *   a look at XXX.
 *
 * 1.5 99/07/14-11:37:20 (rinaldo)
 *   Allow absolute URLS.
 *
 * 1.4 99/07/13-09:37:41 (suhler)
 *   look up the redirect property in the form/query data
 *
 * 1.3 99/06/29-14:38:20 (suhler)
 *   use new redirector
 *
 * 1.2 99/06/29-09:37:12 (suhler)
 *   re-wrote config handler to be more useful.
 *   It now works in conjuction with the form template handler
 *   see config.config for an example
 *   .
 *
 * 1.2 99/06/28-10:46:26 (Codemgr)
 *   SunPro Code Manager data about conflicts, renames, etc...
 *   Name history : 1 0 handlers/ConfigFileHandler.java
 *
 * 1.1 99/06/28-10:46:25 (suhler)
 *   date and time created 99/06/28 10:46:25 by suhler
 *
 */

package sunlabs.brazil.handler;

import sunlabs.brazil.session.SessionManager;
import sunlabs.brazil.server.Handler;
import sunlabs.brazil.server.Request;
import sunlabs.brazil.server.Server;
import sunlabs.brazil.util.Glob;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Properties;

/**
 * Handler for manipulating per-user session state that can be
 * represented as ASCII name/value pairs.  The state for each session
 * is stored in a file, which is expected to be in java properties format.
 *
 * If "prefix" is matched, the contents of the (usually cached) config file
 * for the current session is added to the request properties.
 *
 * If the url matches the "set" property, the contents of the config
 * file are changed based on the supplied query parameters (either GET
 * of POST).  If no config file exists for the session, one is created
 * from a default properties file.  Only properties already in the
 * config file may be changed using the "set" method.
 *
 * If a "%" is specified in the file name, it is replaced by the
 * SessionID property, if any, or "common" if sessions aren't used.
 * This should be replaced with something more general, so we can have
 * more arbitrary mappings between request and the session info.
 * 

* The following request properties are used: *

*
prefix
The URL prefix required for all documents *
set
The url pattern to match setting properties. * Currently, it must also match "prefix". *
noContent
a url, matching the "set" pattern that causes * a "204 no content" to be returned to the client * (experimental). *
name
The name of the config file. the first "%" is replaced * by the current SessionID. *
default
The default properties file to "seed" session properties *
glob
Properties that match this "glob" pattern may be set * using the "set" pattern. If this property is specified, * the "default" property is optional. *
root
The document root (no properties prefix required). If the * "name" or "default" properties don't start with a "/", * this is used as the current directory. * *
* If "%" is specified in the file name, a new session file is * created only if 1) a property is changed from the default, and 2) * A cookie was received by the browser. *

* See also: {@link sunlabs.brazil.template.SetTemplate} * which is preferrable in most cases, providing a templated based * (instead of URL based) * mechanism for maintaining persistent properties. * * @author Stephen Uhler * @version 2.2, 04/08/30 */ public class ConfigFileHandler implements Handler { static final String SET = "set"; // glob matching url setting props static final String PREFIX = "prefix"; // prefix for adding to props static final String NAME = "name"; // name of the config file static final String DEFAULT = "default"; // the default config file static final String ROOT = "root"; // root of config file static final String GLOB = "glob"; String propsPrefix; String name; // name of the config file String urlPrefix; // prefix for any request we handle String set; // glob pattern to match url needed to modify props String nc; // glob pattern to match url needed for no content String match; // glob pattern to match settable props not in deflt file String root; // where to find the root of the config file Properties defaultProperties; // where to find the defaults boolean copy = false; // undocumented backwart compat flag /** * Make sure default properties exist before starting this handler, * or that "match" is specified". */ public boolean init(Server server, String prefix) { propsPrefix = prefix; urlPrefix = server.props.getProperty(prefix + PREFIX, "/"); set = server.props.getProperty(prefix + SET, urlPrefix + prefix); nc = server.props.getProperty(prefix + "noContent", "X"); match = server.props.getProperty(prefix + GLOB); name = server.props.getProperty(prefix + NAME, prefix + ".cfg"); copy = (server.props.getProperty(prefix + "copy") != null); root = server.props.getProperty(ROOT, "."); String defaultName = server.props.getProperty(prefix + DEFAULT); File defaultFile = null; if (defaultName != null) { if (defaultName.startsWith("/")) { defaultFile = new File(defaultName); } else { defaultFile = new File(root, defaultName); } } defaultProperties = new Properties(); try { FileInputStream in = new FileInputStream(defaultFile); defaultProperties.load(in); in.close(); } catch (IOException e) { if (match == null) { server.log(Server.LOG_WARNING, prefix, "No default file: " + defaultFile + " ConfigFileHandler NOT installed!"); return false; } } server.log(Server.LOG_DIAGNOSTIC, prefix, "\n set=" + set + "\n name=" + name + "\n default=" + defaultFile); return true; } /** * Extract the session state into the request object, optionally * modifying the properties. If the properties are modified, * they are stored in a file for safe keeping. */ public boolean respond(Request request) throws IOException { if (!request.url.startsWith(urlPrefix)) { return false; } /* * Get the existing properties. */ root = request.props.getProperty(ROOT, root); String id = request.props.getProperty("SessionID", "common"); Properties p = (Properties) SessionManager.getSession(id, propsPrefix, Properties.class); /* * If no properties exist, read in the session * properties, otherwise use the default properties */ if (p.isEmpty()) { File file = getPropsFile(name, id); request.log(Server.LOG_DIAGNOSTIC, propsPrefix, "No properties, looking in: " + file); try { FileInputStream in = new FileInputStream(file); p.load(in); in.close(); } catch (IOException e) { request.log(Server.LOG_DIAGNOSTIC, propsPrefix, "Can't find config file: " + file + " using default properties"); Enumeration enumer = defaultProperties.propertyNames(); while(enumer.hasMoreElements()) { String key = (String) enumer.nextElement(); p.put(key, defaultProperties.getProperty(key)); } } } /* * If "SET" then update the properties file */ if (Glob.match(set, request.url)) { Dictionary update = request.getQueryData(null); // System.out.println("Setting from: " + update); Enumeration enumer = update.keys(); boolean changed = false; synchronized (p) { while(enumer.hasMoreElements()) { String key = (String) enumer.nextElement(); if (p.containsKey(key) || isMatch(key)) { p.put(key, update.get(key)); changed = true; // XXX not quite } else { request.log(Server.LOG_DIAGNOSTIC, propsPrefix, "Can't set key " + key + ", name doesn't exist in default file" + " or doesn;t match: " + match); } } if (!changed) { request.log(Server.LOG_DIAGNOSTIC, propsPrefix, "Set called, nothing changed!!"); } /* * If the client has cookies enabled, try to save the * properties. This depends upon a side effect of the * "sessionHandler" to let us know if the browser * actually sent us our cookie. */ if (changed && (name.indexOf("%") < 0 || request.props.containsKey("UrlID") || request.props.containsKey("gotCookie"))) { File file = getPropsFile(name, id); try { FileOutputStream out = new FileOutputStream(file); p.save(out, request.serverUrl() + request.url + " (from ConfigFileHandler: " + propsPrefix + ")"); out.close(); request.log(Server.LOG_DIAGNOSTIC, propsPrefix, "Saving configuration properties to " + file); } catch (IOException e) { request.log(Server.LOG_WARNING, propsPrefix, "Can't save properties to: " + file); } } } /* * If this is a post, trash the input and change to a get. * XXX This is probably incorrect. */ if (request.method.equals("POST")) { request.method = "GET"; request.postData = null; request.headers.put("Content-Length", "0"); } } if (copy) { Enumeration enumer = p.keys(); while(enumer.hasMoreElements()) { String key = (String) enumer.nextElement(); request.props.put(key, p.getProperty(key)); } } else { request.addSharedProps(p); // request.log(Server.LOG_DIAGNOSTIC, propsPrefix, "Chaining " + // p + " onto request.props"); } return false; } /** * True if key "s" matches glob pattern in "match". If * match is null, then no match. */ private boolean isMatch(String s) { return (match != null && Glob.match(match, s)); } /** * Find the config file name */ private File getPropsFile(String name, String id) { int index; if ((index = name.indexOf("%")) >= 0) { name = name.substring(0,index) + id + name.substring(index+1); } File file; if (name.startsWith("/")) { file = new File(name); } else { file = new File(root, name); } return file; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy