sunlabs.brazil.properties.SubstPropsHandler Maven / Gradle / Ivy
Show all versions of sunlabs.brazil Show documentation
/*
* SubstPropsHandler.java
*
* Brazil project web application toolkit,
* export version: 2.3
* Copyright (c) 2004-2006 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): suhler.
*
* Version: 1.5
* Created by suhler on 04/04/27
* Last modified by suhler on 06/11/13 14:57:53
*
* Version Histories:
*
* 1.5 06/11/13-14:57:53 (suhler)
* Move MatchString from handler -> util
*
* 1.4 04/11/30-15:19:44 (suhler)
* fixed sccs version string
*
* 1.3 04/10/26-11:27:31 (suhler)
* add docs
*
* 1.2 04/04/28-14:53:05 (suhler)
* doc bug fixes
*
* 1.2 04/04/27-14:54:59 (Codemgr)
* SunPro Code Manager data about conflicts, renames, etc...
* Name history : 1 0 sunlabs/SubstPropsHandler.java
*
* 1.1 04/04/27-14:54:58 (suhler)
* date and time created 04/04/27 14:54:58 by suhler
*
*/
package sunlabs.brazil.properties;
import java.util.Hashtable;
import java.util.StringTokenizer;
import sunlabs.brazil.util.MatchString;
import sunlabs.brazil.server.Handler;
import sunlabs.brazil.server.Request;
import sunlabs.brazil.server.Server;
import sunlabs.brazil.util.regexp.Regexp;
import sunlabs.brazil.util.http.HttpUtil;
import java.io.IOException;
import java.util.Properties;
/**
* Handler that performs value conversions on ${...} substitutions.
* For any property whose name matches the supplied regular expression,
* The source value is "converted" based on a token in the regular expression.
*
* This Handler is a generalization of the convert
attribute
* of the get
tag of the SetTemplate
. Unlike
* the implementation in the SetTemplate
that implements a
* small, fixed set of conversions of property values in the context of
* get
, this handler allows plug-able conversion filters, and
* performs the conversions any time ${...} substitutions are resolved, not
* just in the context of the get
tag.
*
* This requires the addition of new syntax in ${...}
* substitutions to specify the both the
* conversion (or filter) to apply, and the value to apply it to.
* This new syntax is configurable using the match
,
* key
, and token
attributes, but defaults to:
* ${filter(value)} where filter
represents the conversion
* filter, and value
represents the property name whose contents
* is filtered.
*
* Any class that implements the Convert
interface can be
* loaded and called to perform filtering. Filters that implement all the
* options of the <get ... convert=xxx>
conversion options
* are included.
*
* See the examples, below for the details.
*
* - match
*
- A regular expression that matches a property name that is a candidate
* for filtering. This expression should have at least 2 sets of ()'s
* in order to gather values for "key" and "token" below. The
* default value is
^([a-z]+)\([^)]+\)$
* - key
*
- The regular expression substitution string used to represent the
* actual property name to filter. The default is
\\2
* - token
*
- The regular expression substitution string used to represent the
* filter name or "token". The default is
\\1
*
* Using the defaults for "match", "key", and "token", a property named
* "foo" would be represented as ${xxx(foo)}
where
* "xxx" is the name of the conversion filter.
*
- tokens
*
-
* A witespace separated list of filter names or "token"s that map the
* conversion filters to conversion classes. For each token (e.g. foo), there
* should be a property of the form "foo.class" which specifies the name
* of the class that implements the filter, (and implements the Convert
* interface described below).
* Any additional properties (e.g. x, y, z) needed to initialize a filter
* should be present in the properties file as "foo.x, foo.y...".
*
- [token].code
*
- The name to match the "token" in the property name. The default
* is "[token]".
*
*
* This class contains sample implementations of the convert
* interface. See below for their functions.
*
* @author Stephen Uhler
* @version 1.5
*
* @see java.util.Properties
*/
public class SubstPropsHandler implements Handler {
MatchString isMine; // check for matching url
Regexp matchRe; // expr that matches a property
String keySub; // Substitution string that gets the real key
String tokenSub; // Substitution string that matches conversion token
Hashtable map = new Hashtable(); // map from token to mapping function
static Class[] types = new Class[] {String.class, Properties.class};
public boolean
init(Server server, String prefix) {
isMine = new MatchString(prefix, server.props);
matchRe = new Regexp(server.props.getProperty(prefix + "match",
"(^[a-z]+)\\(([^)]+)\\)$"));
keySub = server.props.getProperty(prefix + "key", "\\2");
tokenSub=server.props.getProperty(prefix + "token", "\\1");
StringTokenizer st = new StringTokenizer(
server.props.getProperty(prefix + "tokens"));
// build table of conversions
while(st.hasMoreTokens()) {
String token = st.nextToken();
String className = server.props.getProperty(token + ".class");
String match=server.props.getProperty(token + ".code", token);
String name = prefix;
if (className == null) {
className = token; // use token as prefix;
} else {
name = token;
}
try {
Class type = Class.forName(className);
Object obj = type.newInstance();
String pre;
if (name.endsWith(".")) {
pre=name;
} else {
pre= name + ".";
}
Object[] args = new Object[] {pre, server.props};
Object result = type.getMethod("init", types).invoke(obj, args);
if (Boolean.FALSE.equals(result)) {
continue;
}
if (! (obj instanceof Convert)) {
server.log(Server.LOG_WARNING,className, "wrong interface");
continue;
}
map.put(name, obj);
server.log(Server.LOG_DIAGNOSTIC, token,
"instantiating class: " + obj);
} catch (Exception e) {
server.log(Server.LOG_WARNING, prefix, "Oops: " + e);
e.printStackTrace();
}
}
return true;
}
public boolean
respond(Request request) throws IOException {
if (isMine.match(request.url)) {
SubstProps p = new SubstProps(request);
PropertiesList pl = new PropertiesList(p);
pl.addBefore(request.serverProps);
}
return false;
}
public String toString() {
return matchRe + "-" + keySub + "-" + tokenSub + "=" + map;
}
/**
* This class implements a properties object that knows how
* to extract the "name" and "filter" from a properly constructed
* name, and to invoke the filter on the value of the encoded
* name.
*/
public class SubstProps extends Properties {
Request r;
public SubstProps(Request r) {
super();
this.r = r;
}
/**
* If the key doesn't exist, but the "derived" key and value
* do exist, then return the substituted value
*/
public Object get(Object key) {
Object val = super.get(key);
String newKey;
if (val == null && key instanceof String &&
null != matchRe.match((String) key)) {
newKey = matchRe.sub((String) key, keySub);
val = r.props.get(newKey);
if (val != null) {
String t = matchRe.sub((String) key, tokenSub);
val = convert((String)val, t);
}
}
return val;
}
public String getProperty(String key) {
String val = super.getProperty(key);
if (val == null && null != matchRe.match(key)) {
String newKey = matchRe.sub(key, keySub);
val = r.props.getProperty(newKey);
if (val != null) {
String t = matchRe.sub((String) key, tokenSub);
val = convert(val, t);
}
}
return val;
}
/**
* Given a value, compute the converted value.
*/
String convert(String value, String token) {
String result=value;
if (token != null) {
Convert cnvt = (Convert) map.get(token);
if (cnvt != null) {
result = cnvt.map(value);
}
}
return result;
}
}
/**
* Class that maps strings to strings.
*/
public interface Convert {
/**
* This is called once at creation time to provide this
* class with configuration information. Any configuration
* parameters required in "p" are prefixed with [prefix].
*/
public boolean init(String prefix, Properties p);
/**
* Map the value.
*/
public String map(String value);
}
// Sample mapping classes
/**
* Convert a value to lowercase.
*/
public static class LowerCase implements Convert {
public boolean init(String prefix, Properties p) {
return true;
}
public String map(String value) {
return value.toLowerCase();
}
}
/**
* HTML escape a value.
*/
public static class Html implements Convert {
public boolean init(String prefix, Properties p) {
return true;
}
public String map(String value) {
return HttpUtil.htmlEncode(value);
}
}
/**
* URL encode a String.
*/
public static class Url implements Convert {
public boolean init(String prefix, Properties p) {
return true;
}
public String map(String value) {
return HttpUtil.urlEncode(value);
}
}
/**
* Do a regexp substitution on a value.
* This takes the following initialization parameters:
*
* - match
*
- A Regular expression that matches the string value.
*
- sub
*
- The regular expression substitution to perform.
* All occurances of "match" are substututed.
*
*/
public static class Resub implements Convert {
Regexp match = null;
String sub = null;
public boolean init(String prefix, Properties p) {
String matchStr=p.getProperty(prefix + "match");
sub = p.getProperty(prefix + "sub");
match = new Regexp(matchStr);
if (match==null || sub == null) {
System.out.println("Missing 'match' and 'sub'");
return false;
}
return true;
}
public String map(String value) {
return match.subAll(value, sub);
}
}
}