sunlabs.brazil.template.SetTemplate Maven / Gradle / Ivy
Show all versions of sunlabs.brazil Show documentation
/*
* SetTemplate.java
*
* Brazil project web application toolkit,
* export version: 2.3
* Copyright (c) 2000-2007 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, suhler.
*
* Version: 2.16
* Created by suhler on 00/10/25
* Last modified by suhler on 07/01/08 15:14:56
*
* Version Histories:
*
* 2.16 07/01/08-15:14:56 (suhler)
* add
*
* 2.15 06/11/13-12:07:33 (suhler)
* - started a general purpose "convert" thing
* - added "lower" and "trim" conversions
* - added "track" attribute to track changes to the console
* - removed "tag_map", which is now in the MiscTemplate
*
* 2.14 06/08/01-14:07:08 (suhler)
* - added doImport() public method to tell us to import remembered namespaces
* - fixed remember bug - a namespace could be chained multiple times
*
* 2.13 06/06/15-12:49:34 (suhler)
* the tag now set a "namespace" request property
* .
*
* 2.12 06/05/04-22:29:08 (suhler)
* bug fix: when an empty namespace is imported, then filled with
* , the namespace wasn't being properly imported
*
* 2.11 05/11/27-18:42:06 (suhler)
* assume url.orig is always defined
*
* 2.10 05/07/13-10:19:19 (suhler)
* add headers.hostname and headers.hostport
*
* 2.9 05/06/08-11:14:40 (suhler)
* change "headers.counter" to use server requestCount instead of acceptCount,
* which is more useful.
*
* 2.8 05/05/11-11:35:20 (suhler)
* Make the default "sessionTable" the template handler/filter prefix, and
* not the SetTemplate prefix by default [*** potential incompatibility ***].
* This allows all templates in the same template handler/filter to share
* namespaces by default
*
* 2.7 04/11/03-08:36:05 (suhler)
* url.request is now set in request
*
* 2.6 04/04/28-14:51:25 (suhler)
* doc format fix
*
* 2.5 04/04/19-14:36:40 (suhler)
* Add convert=lowercase to set
*
* 2.4 02/12/19-11:37:31 (suhler)
* add
*
* 2.3 02/11/04-13:53:34 (suhler)
* don't clear non-existing namespaces
*
* 2.2 02/10/24-11:58:04 (suhler)
* Merged changes between child workspace "/home/suhler/brazil/naws" and
* parent workspace "/net/mack.eng/export/ws/brazil/naws".
*
* 1.37.1.1 02/10/24-11:58:01 (suhler)
* - namespace clear "clears" but does not unking the namespace
* - better error checking for missing attributes
* .
*
* 2.1 02/10/01-16:36:47 (suhler)
* version change
*
* 1.37 02/04/18-11:16:10 (suhler)
* added "set" option to get
*
* 1.36 02/02/04-14:31:45 (suhler)
* remove allowGt stuff; see AllowGtTemplate instead
*
* 1.35 02/01/29-10:03:47 (suhler)
* added ... tags to enable unescaped >'s inside
* of quoted attribute strings. Thus The following should work:
*
* ......
*
* to allow saving and fetching a
* namespace from a java properties file
*
* 1.30 01/09/25-17:35:44 (suhler)
* added "imports" directive to auto-import namespaces on every page
*
* 1.29 01/09/23-17:36:05 (suhler)
* remove debugging code
*
* 1.28 01/08/29-08:57:52 (suhler)
* add max length argument to
*
* 1.27 01/08/28-20:56:29 (suhler)
* added ...
* and
*
* 1.26 01/08/27-18:59:25 (suhler)
* add "clear" option to to zap a namespace
*
* 1.25 01/07/20-10:44:40 (suhler)
* doc fixes
*
* 1.24 01/07/18-16:32:40 (suhler)
* - Added headers.timestamp and headers.counter
* - fixed really stupid bug
*
* 1.23 01/07/16-16:46:54 (suhler)
* add PropsTemplate functionallity as "", add option
*
* 1.22 01/07/11-16:27:31 (suhler)
* added "server" namespace
*
* 1.21 01/05/24-10:44:02 (suhler)
* fixed memory leak
*
* 1.20 01/05/23-09:21:46 (suhler)
* Bug fix. Empty tables were never chaind if they were being created
* during a page. Keep track of imported but not yet created tables, so
* they may be chained if they come into existence during a page
*
* 1.19 01/05/11-14:50:31 (suhler)
* use template.debug()
*
* 1.18 01/05/11-10:37:35 (suhler)
* rewrite:
* "local" is a synonym for namespace=local
* autoImport=false will turn off the implicit import of the session namespace
*
* 1.17 01/05/07-11:23:46 (suhler)
* bug. No namespace was using namespace "".
*
* 1.16 01/04/05-14:49:26 (suhler)
* bug fix
*
* 1.15 01/04/05-10:00:48 (suhler)
* don't create empty session tables
*
* 1.14 01/03/27-14:51:47 (suhler)
* > Added the ability to set and use values from alternate session tables
* > with and
*
* 1.13 01/03/26-08:49:00 (suhler)
* Merged changes between child workspace "/home/suhler/brazil/naws" and
* parent workspace "/net/mack.eng/export/ws/brazil/naws".
*
* 1.11.1.1 01/03/26-08:45:35 (suhler)
* Partial implementation of experimantal "namespaces".
*
* 1.12 01/03/23-14:28:21 (cstevens)
* Add "default" option to set template, based on observed usage.
* has "default" option, but this is only useful if the property is going to
* be substituted into HTML. Adding "default" to allows easier use of a
* possibly-undefined property whose value is going to be passed to another
* template via ${...}.
*
* 1.11 01/02/12-15:56:32 (cstevens)
* less logging - don't stringify the entire hashtable when setting a local var.
*
* 1.10 01/01/22-19:03:38 (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.9 00/12/12-13:04:59 (suhler)
* Changed the default behavior to be persistent.
* use "local" keyword for a local copy only
* .
*
* 1.8 00/12/11-13:30:52 (suhler)
* add class=props for automatic property extraction
*
* 1.7 00/12/05-13:11:35 (suhler)
* remove debugging
*
* 1.6 00/11/20-13:21:53 (suhler)
* doc fixes
*
* 1.5 00/11/16-09:38:54 (suhler)
* added ability to set properties from url queries when running as a handler
*
* 1.4 00/11/15-09:48:51 (suhler)
* make persistent properties shareable
*
* 1.3 00/10/26-16:00:12 (suhler)
* implement serializablew
*
* 1.2 00/10/25-20:32:51 (suhler)
* added mustMatch to restict what may be set
*
* 1.2 00/10/25-20:16:59 (Codemgr)
* SunPro Code Manager data about conflicts, renames, etc...
* Name history : 1 0 handlers/templates/SetTemplate.java
*
* 1.1 00/10/25-20:16:58 (suhler)
* date and time created 00/10/25 20:16:58 by suhler
*
*/
package sunlabs.brazil.template;
import java.io.Serializable;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;
import java.util.StringTokenizer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import sunlabs.brazil.properties.PropertiesList;
import sunlabs.brazil.server.Handler;
import sunlabs.brazil.server.Request;
import sunlabs.brazil.server.Server;
import sunlabs.brazil.session.SessionManager;
import sunlabs.brazil.util.Format;
import sunlabs.brazil.util.Glob;
import sunlabs.brazil.util.http.HttpUtil;
/**
* Template (and handler) class for setting and getting values to
* and from the current (or other) request context.
* This class is used by the TemplateHandler. The following tags
* are processed by this class:
*
* - <set name=.. [value=..] [namespace=..]>
*
- <get name=.. [default=..] [namespace=..] [max=nnn] [convert=html|url|none] [set=..]>
*
- <namespace name=.. [clear] [remove] [store=xxx] [load=xxx]>
*
- <import namespace=.. />
*
- <unimport namespace=.. />
*
- <tag [name=..]>
*
- </tag>
*
*
* The tag<set>
is processed with the following
* attributes:
*
* - name=value
*
- The name of the entry to set in the request properties.
*
*
- value=value
*
- The value to store in the property. If this option is not specified,
* then the existing value for this property will be removed.
*
*
- default=other
*
- If
default
is specified and the specified value
* was the empty string "", then store this other value in the
* property instead. other is only evaluated in this case.
*
* - local
*
- By default, variables are set (or removed from) a namespace that is
* persistent across all requests for the same session. If
*
local
is specified, the values only remain for the
* duration of the current request. [Deprecated - use namespace=local]
*
* - namespace
*
- The namespace to use to set or delete the property. The default
* is
namespace=${SessionID}
, unless set
is
* inside the scope of an enclosing namespace
tag.
* Namespaces are used to define
* variable scopes that may be managed explicitly in template pages.
*
* Two namespaces are treated specially:
*
* - local
* may be used to set (or clear) values
* from request.props
.
* - server
* may be used to set (or clear) values
* from server.props
, unless "noserver" is defined
* in which case hte "Server" namespace is not treated specially.
*
*
*
* The <namespace>
..</namespace>
tag
* pairs are used to specify a default namespace other than the
* SessionId
for the set and import tags
* or manipulate a namespace.
* When a namespace is in effect, the request property [prefix].namespace
* is set to the current namespace, where [prefix] is the
* RewriteContext.templatePrefix. This permits other templates (such as the
* ListTemplate) to use the current namespace setting.
* These tags don't nest.
*
* attributes for namespace
:
*
* - name=value
*
- The default namespace to use for the set and
import
* default namespace name.
* - clear
*
- If set, namespace
name
is cleared.
* - remove
*
- If set, namespace
name
is removed.
* - load=file_name
*
- If specified, and the property
saveOk
is set, then
* the specified namespace will be saved loaded from a file in java
* properties
* format. Relative path names are resolved with respect to the
* document root.
* - store=file_name
*
- If specified, and the property
saveOk
is set, then
* the specified namespace will be stored to a file in java properties
* format. Relative path names are resolved with respect to the
* document root.
*
* When using load
or store
, the namespace
* names "local" and "server" are treated specially, referring to
* "request.props" and "server.props" respectively.
*
* The tag<import>
(and <unimport>
)
* are processed with the following
* attributes:
*
* - namespace=value
*
- The name/value pairs assiciated with the namespace are
* made available for the remainder of the page.
*
*
* The "unimport" taq should probably be replaced by <import>
*
* The "get" (formerly property) tag has the following attributes:
*
* - name
*
- The name of the variable to get
*
- namespace
*
- The namespace to look in. By default, the variable is searched
* for in "request.props"
*
- default
*
- The value to use if no value matches "name".
*
- convert
*
- The conversion to perform on the value of the data before
* substitution: "html", "url", "lower, "trim", or "none" (the default). For
* "html", any special html syntax is escaped.
* For "url", the data will be suitable for transmission as an
* http URL. The "lower" and "trim" options convert to lowercase and
* remove leading and trailing whitespace, respectively.
*
- max
*
- The output is truncated to at most
max
characters.
*
* If a single attribute is specified, with no "=", then is is taken
* to be the "name" parameter. Thus:
* <get foo>
is equivalent to:
* <get name="foo">
.
*
* Request Properties:
*
* - sessionTable
*
- The name of the SessionManager table to use for
* storing values. Defaults to the template handler's prefix.
* When configured
* in one server both as a handler and a template, the sessionTable should
* be set to the same value in both cases to get a useful result.
*
- debug
*
- If set, the original tag is included in a comment,
* otherwise it is removed entirely.
*
- mustMatch
*
- Set to a glob pattern that all names must match
* in order to be set. This may be used to prevent malicious
* html pages (what a concept) from changing inappropriate values.
*
- noserver
*
- The "server" namespace will no longer be mapped to
*
server.props
* - noSet
*
- If set, then the "set" tag will be disabled.
*
- querySet
*
- If set, then properties may be set in query
* parameters, to the "handler" portion, but only
* if they match the glob pattern.
*
- autoImport
*
- If set to "1", the namespace for the session is
* automatically imported. (defaults to "1");
*
- imports
*
- Defines a set of (white space delimited) namespaces that will
* automatically be imported at the beginning of each page.
* Each namespace name will be processed for ${...} substitutions before
* an import is attempted. If the namespace doesn't already exist,
* the import is ignored.
*
- query
- The query parameters are inserted into the request object,
* prefixed by the value assigned to "query".
*
- headers
- The mime headers are inserted into the request object,
* prefixed by the value assigned to "headers".
*
In addition, the following properties (prefixed with
* "headers") are also set:
*
* - address The ip address of the client
*
- counter A monotonically increasing counter
* (# of client requests accepted since the server started).
*
- method The request method (typically GET or POST).
*
- protocol The client HTTP protocol level (for 1.0 or 1.1)
*
- query The current query data, if any.
*
- timestamp A timestamp (in ms since epoch) from when
* this request was first accepted.
*
- url The current url.
*
- hostname, hostport The name and port parts of the
* "host" header, if set.
*
* - url.orig
- If set and "headers" are requested, this value is used as
* the
url
instead of the one in request.url.
*
*
* Normally, any persistent properties held by the SetTemplate are
* chained onto the request.props when the init method is found. If this
* template is installed as an up-stream handler, then the persistent
* properties associated with the session are made available at that time.
*
* When used as a handler, the following property is used:
*
* - session=value
*
- The request property to find the session information in.
* Normally this should be the same as the session property used
* by the container calling this as a template.
*
- saveOk
*
- This must be specified in order for the
* "namespace store" or "namespace load" functions to operate.
*
*
* @author Stephen Uhler
* @version @(#)SetTemplate.java 2.15
*/
public class SetTemplate extends Template implements Serializable, Handler {
String mustMatch; // glob-pattern of permitted names
String prefix = null; // non-null if instance is a handler
String session; // the handler property for the session var
String sessionTable; // the "other" session key
String querySet; // if non-null set values from query
boolean allowServer=true; // allow sets to server properties
boolean noSet = false; // if true, "set" is disabled"
String current; // current namespace
Vector remember = new Vector(); // future chainable namespaces
/**
* Chain the session-id properties into the request chain, if
* there are any. If "query" or "headers" are requested for "get",
* then add in those properties to request.props.
*/
public boolean
init(RewriteContext hr) {
Properties props = hr.request.props;
current = null;
String query = props.getProperty(hr.prefix + "query");
if (query != null) {
Dictionary h = hr.request.getQueryData(null);
Enumeration keys = h.keys();
while(keys.hasMoreElements()) {
String key = (String) keys.nextElement();
props.put(query + key, h.get(key));
}
}
String headers = props.getProperty(hr.prefix + "headers");
if (headers != null) {
Enumeration keys = hr.request.headers.keys();
while(keys.hasMoreElements()) {
String key = (String) keys.nextElement();
props.put(headers + key.toLowerCase(),
hr.request.headers.get(key));
}
props.put(headers + "method", hr.request.method);
props.put(headers + "url", props.getProperty("url.orig"));
props.put(headers + "query", hr.request.query);
String protocol = hr.request.serverProtocol == null ?
hr.request.server.protocol : hr.request.serverProtocol;
props.put(headers + "protocol", protocol);
props.put(headers + "address",
"" + hr.request.getSocket().getInetAddress().getHostAddress());
props.put(headers + "timestamp", "" + hr.request.startMillis);
props.put(headers + "counter", "" + hr.server.requestCount);
String host = props.getProperty(headers + "host");
if (host != null) {
int indx = host.indexOf(":");
if (indx < 0) {
props.put(headers + "hostname", host);
props.put(headers + "hostport", protocol.equals("http")?
"80" : "443");
} else {
props.put(headers + "hostname", host.substring(0,indx));
props.put(headers + "hostport", host.substring(indx+1));
}
}
}
remember.removeAllElements();
mustMatch = hr.request.props.getProperty(hr.prefix + "mustMatch");
allowServer = (null == hr.request.props.getProperty(hr.prefix +
"noserver"));
noSet = (null != hr.request.props.getProperty(hr.prefix +
"noSet"));
sessionTable = hr.request.props.getProperty(hr.prefix +
"sessionTable", hr.templatePrefix);
String autoImport = hr.request.props.getProperty(hr.prefix +
"autoImport", "1");
if (autoImport.equals("1")) {
Properties p = (Properties) SessionManager.getSession(hr.sessionId,
sessionTable, null);
if (p != null) {
hr.request.addSharedProps(p);
} else {
remember.addElement(hr.sessionId);
hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
"Remembering (init) " + sessionTable);
}
}
String imports = hr.request.props.getProperty(hr.prefix + "imports");
if (imports != null) {
StringTokenizer st = new StringTokenizer(imports);
while (st.hasMoreTokens()) {
String token = Format.subst(hr.request.props, st.nextToken());
Properties p = (Properties) SessionManager.getSession(token,
sessionTable, null);
if (p != null) {
hr.request.addSharedProps(p);
hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
"Auto importing: " + token);
}
}
}
return super.init(hr);
}
/**
* Set the value of a variable. Allow variable substitutions in the name
* and value. Don't create property tables needlessly.
*
* Attributes:
*
* - name
*
- The name of the variable to set
*
- value
*
- The value to set if to.
*
- namespace
*
- The namespace to look in. By default, the variable is set in
* the namespace associated with the current "SessionId".
*
- local
*
- A (deprecated) alias for "namespace=local", or the current
* request.props.
*
*/
public void
tag_set(RewriteContext hr) {
boolean shouldTrack = Format.isTrue(hr.request.props.getProperty(hr.prefix + "track"));
if (noSet) {
return;
}
debug(hr);
hr.killToken();
String name = hr.get("name");
if (name == null) {
debug(hr, "missing variable name");
return;
}
if (mustMatch!=null && !Glob.match(mustMatch, name)) {
debug(hr, name + " doesn't match " + mustMatch);
return;
}
String value = convert(hr,hr.get("value"));
String namespace = hr.get("namespace");
boolean local = (hr.isTrue("local") || "local".equals(namespace));
Class create = (value != null) ? Properties.class : null;
if (namespace == null) {
namespace = (current == null) ? hr.sessionId : current;
}
/*
* Find the correct property table. If we are
* clearing an entry, don't make the table if it doesn't exist.
*/
Properties p; // table to set or clear
if (local) {
p = hr.request.props;
namespace="local";
} else if (allowServer && "server".equals(namespace)) {
p = hr.server.props;
} else {
p = (Properties) SessionManager.getSession(namespace,
sessionTable, create);
}
// set or clear the entry
if (value != null) {
if (value.equals("")) {
String dflt = hr.get("default");
if (dflt != null) {
value = dflt;
}
}
if (p.size()==0 && remember.contains(namespace)) {
hr.request.addSharedProps(p);
remember.removeElement(namespace);
hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
"Importing " + namespace);
}
if (shouldTrack) {
System.out.println(": (" + name + "=" + value +
") in namespace: (" + namespace + ")");
}
p.put(name, value);
debug(hr, namespace + "(" + name + ") = " + value);
} else if (p != null) {
p.remove(name);
if (shouldTrack) {
System.out.println(" Clearing the entry (" + name +
") from namespace (" + namespace + ")");
}
}
}
/**
* Convert the html tag "property" in to the request's property
* DEPRECATED - use "get"
*/
public void
tag_property(RewriteContext hr) {
tag_get(hr);
}
/**
* Replace the tag "get" with the value of the
* variable specified by the "name" attribute.
*
* Attributes:
*
* - name
*
- The name of the variable to get
*
- namespace
*
- The namespace to look in. By default, the variable is searched
* for in "request.props". The namespace "server" is used to look in
* the server's namespace. The namespace "local" is a synonym for the
* default namespace.
*
- default
*
- The value to use if no value matches "name".
*
- convert
*
- The conversion to perform on the value of the data before
* substitution: "html", "url", or "none" (the default). For
* "html", any special html syntax is escaped.
* For "url", the data will be suitable for transmission as an
* http URL.
*
- max
*
- Truncate the String to at most
max
characters.
* Max must be at least one, and truncation occurs after
* any conversions.
* - set
*
- The resultant value is placed into the request property named by
* the
set
attribute, and not inserted into the
* HTML stream. If none of "namespace", "convert", or "match"
* is used, then this simply copies the property from one name
* to another.
*
* If a single attribute is specified, with no "=", then is is taken
* to be the "name" parameter. Thus:
* <get foo>
is equivalent to:
* <get name="foo">
.
*/
public void
tag_get(RewriteContext hr) {
String name = hr.getArgs();
String result = null;
if (name.indexOf('=') >= 0) {
name = hr.get("name");
result = hr.get("default");
} else {
name = Format.subst(hr.request.props, name);
}
if (name == null) {
debug(hr, "get: no name");
return;
}
String namespace = hr.get("namespace");
if (namespace != null) {
Properties p;
if (namespace.equals("server")) {
p = hr.server.props;
} else if (namespace.equals("local")) {
p = hr.request.props;
} else {
p = (Properties) SessionManager.getSession(namespace,
sessionTable, null);
}
result = p==null ? result : p.getProperty(name, result);
} else {
result = hr.request.props.getProperty(name, result);
}
if (result != null) {
result = convert(hr, result);
int max = 0;
try {
String str = hr.get("max");
max = Integer.decode(str).intValue();
} catch (Exception e) {}
if (max > 0 && max < result.length()) {
result = result.substring(0,max);
}
String set = hr.get("set"); // set to value only
if (set != null) {
hr.request.props.put(set, result);
} else {
hr.append(result);
}
} else {
debug(hr, "property: no value for " + name);
}
hr.killToken();
}
/**
* This should be a general purpose utility
*/
static String convert(RewriteContext hr, String s) {
String convert = hr.get("convert");
if (convert != null) {
if (convert.indexOf("lower")>=0) {
s = s.toLowerCase();
}
if (convert.indexOf("trim")>=0) {
s = s.trim();
}
if (convert.indexOf("html")>=0) {
s = HttpUtil.htmlEncode(s);
}
if (convert.indexOf("url")>=0) {
s = HttpUtil.urlEncode(s);
}
}
return s;
}
/**
* Import all the data from the named namespace. The namespace
* associated with the session ID is imported automatically
* for backward compatibility. If the namespace doesn't exist,
* don't create it now, but remember it needs to be "Chained"
* if it is created on this page.
*/
public void
tag_import(RewriteContext hr) {
debug(hr);
hr.killToken();
String namespace = hr.get("namespace");
if (namespace == null && current != null) {
namespace = current;
// System.out.println("Importing namespace: " + namespace);
}
if (namespace != null) {
Properties p = (Properties) SessionManager.getSession(namespace,
sessionTable, null);
if (p != null) {
hr.request.addSharedProps(p);
} else if (!remember.contains(namespace)){
remember.addElement(namespace);
hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
"Remembering " + namespace);
}
}
}
/**
* Un-import a previously imported namespace.
*/
public void
tag_unimport(RewriteContext hr) {
debug(hr);
hr.killToken();
String namespace = hr.get("namespace");
if (namespace == null && current != null) {
namespace = current;
}
if (namespace != null) {
Properties p = (Properties) SessionManager.getSession(namespace,
sessionTable, null);
if (p != null) {
PropertiesList pl = hr.request.props.wraps(p);
if (pl != null) {
pl.remove();
hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
"un-Importing: " + namespace);
}
} else if (!remember.contains(namespace)) {
remember.removeElement(namespace);
hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
"unimporting remembered namespace: " + namespace);
}
}
}
/**
* Set the default namespace for "set" and "import".
*/
public void
tag_namespace(RewriteContext hr) {
String name = hr.get("name");
debug(hr);
hr.killToken();
if (name != null) {
if (!hr.isSingleton()) {
current = name;
hr.request.props.put(hr.templatePrefix + "namespace", current);
}
String load = hr.get("load");
String store = hr.get("store");
boolean ok =
(null != hr.request.props.getProperty(hr.prefix + "saveOk"));
// XXX should dis-allow ambiguous options
Properties p; // which property to load or set
boolean isSm = false; // true if session manager table
if (name.equals("local")) {
p = hr.request.props;
} else if (name.equals("server")) {
p = hr.server.props;
} else {
p = (Properties) SessionManager.getSession(name,
sessionTable, null);
isSm = true;
}
if (ok && store != null && p != null) {
store(p, hr, store, name);
} else if (store != null) {
debug(hr, "namespace store failed: (allowed=" + ok + ")");
}
if (ok && load != null) {
if (p == null) {
p = (Properties) SessionManager.getSession(name,
sessionTable, Properties.class);
}
load(p, hr, load);
if (remember.contains(name)) {
hr.request.addSharedProps(p);
remember.removeElement(p);
hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
"load: Importing " + name);
}
} else if (load != null) {
debug(hr, "namespace load failed: (allowed=" + ok + ")");
}
if (isSm && hr.isTrue("clear") && p != null) {
p.clear();
}
if (isSm && hr.isTrue("remove") && p != null) {
SessionManager.remove(name, sessionTable);
p = null;
}
} else {
debug(hr, "No namespace to import");
}
}
/**
* Convert a file name into a file object.
* relative paths use are resolved relative to the document root
* @param p properties file to find the doc root in
* @param prefix the properties prefix for root
* @param name the name of the file
*/
public File
file2path(Properties p, String prefix, String name) {
File file;
if (name.startsWith("/")) {
return new File(name);
} else {
String root = p.getProperty(prefix + "root",
p.getProperty("root", "."));
return new File(root, name);
}
}
/**
* load a namespace from a java properties file
*/
boolean
load(Properties p, RewriteContext hr, String name) {
File file = file2path(hr.request.props, hr.prefix, name);
hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
"loading namespace " + file);
try {
FileInputStream in = new FileInputStream(file);
p.load(in);
in.close();
return true;
} catch (IOException e) {
hr.request.log(Server.LOG_LOG, hr.prefix,
"Can't load namespace " + file);
return false;
}
}
/**
* Store a namespace into a java properties file
*/
boolean
store(Properties p, RewriteContext hr, String name, String title) {
File file = file2path(hr.request.props, hr.prefix, name);
try {
FileOutputStream out = new FileOutputStream(file);
p.save(out, hr.request.serverUrl() + hr.request.url +
" (for namespace " + title + ")");
out.close();
hr. request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
"Saving namespace " + title + " to " + file);
return true;
} catch (IOException e) {
hr. request.log(Server.LOG_WARNING, hr.prefix,
"Can't save namespace " + title + " to " + file);
return false;
}
}
/**
* Clear the default namespace for "set" and "import".
*/
public void
tag_slash_namespace(RewriteContext hr) {
debug(hr);
hr.killToken();
current = null;
hr.request.props.remove(hr.templatePrefix + "namespace");
}
/**
* Map a set of variables from one name to another.
*
* - namespace
*
- The namespace of the destination (defaults to current namespace)
*
- match
*
- The regular expression that matches variable names in the
* current context
*
- replace
*
- The substitution expression used to derice the new names
*
- convert
*
- Which conversions to perform on the data. May be
* "html", "lower", "url", "trim", or "none". The default is "none"
*
- clobber
*
- "true" or "false". If "false" (the default) existing variables
* will not be overridden
*
- clear
*
- "true" or "false". If "true" (the default) the source variable
* will be deleted
*
*/
/**
* Insert a literal "<".
* Using the current scheme, there is no easy way to substitute into
* a tag parameter. So we'll invent a "magic" tag (called tag)
* that will allow us to create entities dynamically. Thus values
* can be substituted into entities by escaping the entity as in:
*
* <tag>a href=<property href></tag>
*
*
* The [optional] attribute "name" may be used to specify the
* name of the tag, which will be emmitted just after the "<".
*/
public void
tag_tag(RewriteContext hr) {
String name = hr.get("name");
hr.append("<");
if ( name != null) {
hr.append(name);
}
}
/**
* Insert a literal ">"
*/
public void
tag_slash_tag(RewriteContext hr) {
hr.append(">");
}
/**
* Get the 2 SessionManager keys, "sessionTable" and "session" (SessionID).
*/
public boolean
init(Server server, String prefix) {
this.prefix = prefix;
querySet = server.props.getProperty(prefix + "querySet");
sessionTable = server.props.getProperty(prefix + "sessionTable",
prefix);
session=server.props.getProperty(prefix + "session", "SessionID");
return true;
}
/**
* Chain a SessionManager entries onto the request properties,
* and optionally allow setting of request props from query parameters.
* Only the session id table can be chained, and
* values (if any) are set in request.props (i.e. namespace=local)
*/
public boolean
respond(Request request) {
String id = request.props.getProperty(session);
if (id != null) {
Properties p = (Properties) SessionManager.getSession(id,
sessionTable, null);
if (p != null) {
request.addSharedProps(p);
request.log(Server.LOG_DIAGNOSTIC, prefix,
"Chaining: " + id + "," + sessionTable);
} else {
request.log(Server.LOG_DIAGNOSTIC, prefix,
"No table: " + id + "," + sessionTable);
}
}
/*
* Set some properties as part of the request.
* Should they be persistent or not?
*/
if (querySet!=null) {
Dictionary h = request.getQueryData(null);
Enumeration keys = h.keys();
while(keys.hasMoreElements()) {
String key = (String) keys.nextElement();
if (Glob.match(querySet, key)) {
request.props.put(key, h.get(key));
}
}
}
return false;
}
/**
* See if a remembered namespace is actually in use, and import it.
* (This is a workaround). If some other template causes a namespace
* that was previously imported but empty to be created, then this
* tells us that it is now populated, and should be added to the
* chain. [a better implementation might have us register interest
* in a namespace, so we would be called automatically upon creation,
* instead of requiring the creator to know about us and make this
* call explicitly.]
*/
public boolean
doImport(RewriteContext hr) {
boolean result = false;
String namespace= hr.get("namespace");
if (namespace != null && remember.contains(namespace)) {
Properties p = (Properties) SessionManager.getSession(namespace,
sessionTable, null);
if (p != null) {
hr.request.addSharedProps(p);
remember.removeElement(namespace);
result=true;
}
}
return result;
}
}