sunlabs.brazil.handler.DynamicConfigHandler Maven / Gradle / Ivy
Show all versions of sunlabs.brazil Show documentation
/*
* DynamicConfigHandler.java
*
* Brazil project web application toolkit,
* export version: 2.3
* Copyright (c) 2000-2002 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: cstevens.
* Portions created by cstevens are Copyright (C) Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): cstevens, suhler.
*
* Version: 2.1
* Created by cstevens on 00/03/02
* Last modified by suhler on 02/10/01 16:36:37
*
* Version Histories:
*
* 2.1 02/10/01-16:36:37 (suhler)
* version change
*
* 1.6 01/01/22-19:02:52 (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.5 00/12/11-13:28:41 (suhler)
* add class=props for automatic property extraction
*
* 1.4 00/04/12-15:54:25 (cstevens)
* imports
*
* 1.3 00/03/29-16:09:02 (cstevens)
* Eliminated dummy server from DynamicConfigHandler.
*
* 1.2 00/03/10-17:09:14 (cstevens)
* Uses rechainable Properties object to insert new Server properties behind
* the Request properties before dispatching to the wrapped handler's respond
* method.
*
* 1.2 00/03/02-17:43:41 (Codemgr)
* SunPro Code Manager data about conflicts, renames, etc...
* Name history : 1 0 handlers/DynamicConfigHandler.java
*
* 1.1 00/03/02-17:43:40 (cstevens)
* date and time created 00/03/02 17:43:40 by cstevens
*
*/
package sunlabs.brazil.handler;
import sunlabs.brazil.server.ChainHandler;
import sunlabs.brazil.server.Handler;
import sunlabs.brazil.server.Request;
import sunlabs.brazil.server.Server;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Properties;
/**
* The DynamicConfigHandler
allows the user to change the
* configuration of the server and its handlers on the fly. This handler
* can therefore be used to swap in and out functionality, for example,
* by dynamically adding a new AuthHandler
to add a new
* form of authentication to a running server.
*
* This handler uses a special set of URLs to allow a new set of
* configuration properties to be uploaded. The new configuration
* replaces the old configuration.
*
* The name of another Handler
is supplied when this
* DynamicConfigHandler
is initialized. This Handler
* is the helper or sub-handler for the DynamicConfigHandler
.
* When the DynamicConfigHandler
receives a regular HTTP
* request (that matches the URL prefix described below), it redirects
* that request to the respond
method of the sub-handler.
*
* The uploaded configuration properties are kept in a separate properties
* object from the server's properties. The server's properties
* are in fact not accessible from the sub-handler; the sub-handler can
* only access and/or change the properties owned by the
* DynamicConfigHandler
.
*
* This handler uses the following configuration properties:
*
* - handler
*
- The name of the initial sub-handler that this
*
DynamicConfigHandler
will use to process requests. When
* new properties are uploaded, the sub-handler will be replaced with
* whatever is specified in the newly uploaded handler
* property.
*
* - prefix
*
- Only URLs beginning with this string will be redirected to the
* sub-handler. This property belongs to the
*
DynamicConfigHandler
and is not changed when
* new properties are uploaded. The default is "/".
*
* - config
*
- URLs beginning with this prefix can be used to upload or download
* new configuration properties to this handler, which will also
* dynamically change which sub-handler is installed. This property
* belongs to the
DynamicConfigHandler
and is not
* changed when new properties are uploaded. The default
* is "/config/".
*
* Properties may be uploaded by sending them as "name=value" pairs in
* the body of a POST or in the "?" query parameters. The URL for
* uploading properties is "config/set".
*
* The current set of properties may be retrieved from this handler by
* sending the URL "config/get"
*
*
* A sample set of configuration parameters illustrating how to use this
* handler follows:
*
* handler=sunlabs.brazil.server.ChainHandler
* port=8081
* log=5
*
* handlers=dyn cgi
*
* dyn.class=sunlabs.brazil.server.DynamicConfigHandler
* dyn.prefix=/sparky/
* dyn.config=/config-sparky/
* dyn.handler=chain
*
* chain.class=sunlabs.brazil.server.ChainHandler
* chain.handlers=foo baz garply
*
* foo.class=sunlabs.brazil.handler.HomeDirHandler
* foo.home=/home/users/
*
* baz.class=sunlabs.brazil.handler.FileHandler
*
* garply.class=sunlabs.brazil.handler.NotFoundHandler
* garply.root="/errors/"
* garply.fileName="nofile.html"
*
* cgi.class = sunlabs.brazil.handler.CgiHandler
* .
* .
* .
*
* These parameters set up a normal Server
on port 8081,
* running a ChainHandler
which dispatches to a
* DynamicConfigHandler
and a CgiHandler
.
*
* The DynamicConfigHandler
will listen for HTTP requests
* beginning with "/sparky/" and dispatch to its dynamically generated
* list of handlers, and listen for requests beginning with "/config-sparky/"
* to dynamically change that set of handlers.
*
* To give this DynamicConfigHandler
something to do, an initial
* set of handlers is provided with the same prefix ("dyn") as the
* DynamicConfigHandler
itself. The prefix is stripped off
* those properties and the revised set of properties is passed to the
* DynamicConfigHandler
to initialize its dynamically
* configurable world.
*
*
* @author Colin Stevens ([email protected])
* @version 2.1, 02/10/01
*/
public class DynamicConfigHandler
implements Handler
{
private static final String URL_PREFIX = "prefix";
private static final String CONFIG_PREFIX = "config";
private static final String HANDLER = "handler";
private static final String CONFIG_SET = "/set";
private static final String CONFIG_GET = "/get";
String urlPrefix = "/";
String configPrefix = "/config";
Server server;
String prefix;
Properties props;
String name;
Handler handler;
/**
* Initializes this DynamicConfigHandler
by loading the
* initial handler. An initial handler does not need to be defined,
* however, since the handler configuration can be downloaded later.
*
* @param server
* The HTTP server that created this handler.
*
* @param prefix
* A prefix to prepend to all of the keys that this
* handler uses to extract configuration information.
*
* @return false
if the initial handler was specified but
* could not be initialized, true
otherwise.
*/
public boolean
init(Server server, String prefix)
{
this.server = server;
this.prefix = prefix;
this.props = server.props;
urlPrefix = props.getProperty(prefix + URL_PREFIX, urlPrefix);
configPrefix = props.getProperty(prefix + CONFIG_PREFIX, configPrefix);
name = props.getProperty(prefix + HANDLER);
if (name == null) {
return true;
}
handler = ChainHandler.initHandler(server, prefix + HANDLER + ".",
name);
return (handler != null);
}
/**
* Responds to an HTTP request by examining the "Host:" request header
* and dispatching to the main handler of the server that handles
* that virtual host. If the "Host:" request header was not specified,
* or named a virtual host that was not initialized in init
* from the list of virtual hosts, this method returns without
* handling the request.
*
* @param request
* The HTTP request to be forwarded to one of the sub-servers.
*
* @return true
if the sub-server handled the message,
* false
if it did not. false
is
* also returned if the "Host:" was unspecified or unknown.
*/
public boolean
respond(Request request)
throws IOException
{
if (request.url.startsWith(configPrefix)) {
if (request.url.endsWith(CONFIG_GET)) {
request.keepAlive = false;
request.sendHeaders(200, "text/plain", -1);
props.save(request.out, null);
return true;
} else if (request.url.endsWith(CONFIG_SET)) {
Properties local = new Properties(server.props);
request.getQueryData(local);
String name = local.getProperty(HANDLER, "");
Handler h = ChainHandler.initHandler(server, "", name);
String result = "result=properties uploaded";
if (h == null) {
result = "error=properties malformed";
} else {
handler = h;
props = local;
}
request.sendResponse(result, "text/plain");
return true;
}
} else if (request.url.startsWith(urlPrefix)) {
request.log(Server.LOG_DIAGNOSTIC, prefix,
"invoking handler: " + name);
/*
* XXX Defaults for my props are the original server props.
* Defaults for request's props are ????
*
* 1. Should my defaults be null instead?
* 2. Should make my defaults be the ???? from the request.
* (Threading issue: concurrent requests w/ differing
* defaults for their properties).
*/
try {
if (props != server.props) {
request.addSharedProps(props);
}
return handler.respond(request);
} finally {
request.removeSharedProps(props);
}
}
return false;
}
}