/*
* ExprProps.java
*
* Brazil project web application toolkit,
* export version: 2.3
* Copyright (c) 2001-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: drach.
* Portions created by drach are Copyright (C) Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): drach, suhler.
*
* Version: 2.3
* Created by drach on 01/07/11
* Last modified by suhler on 04/05/24 14:41:51
*
* Version Histories:
*
* 2.3 04/05/24-14:41:51 (suhler)
* doc fixes
*
* 2.2 03/07/07-14:44:01 (suhler)
* Merged changes between child workspace "/home/suhler/brazil/naws" and
* parent workspace "/net/mack.eng/export/ws/brazil/naws".
*
* 2.1 02/10/01-16:36:30 (suhler)
* version change
*
* 1.6.1.1 02/09/20-10:53:46 (suhler)
* removed diagnostics
*
* 1.6 02/06/27-18:36:46 (suhler)
* don't try to calculate anything that doesn't have a valid operator
*
* 1.5 01/11/21-11:43:36 (suhler)
* doc fixes
*
* 1.4 01/08/17-17:23:55 (drach)
* Use most recent request.props instead of cached version
*
* 1.3 01/07/16-16:58:18 (suhler)
* Merged changes between child workspace "/home/suhler/brazil/naws" and
* parent workspace "/net/mack.eng/export/ws/brazil/naws".
*
* 1.1.1.1 01/07/16-16:50:28 (suhler)
* minor doc fixes
*
* 1.2 01/07/16-16:15:55 (drach)
* Add comments to both. Add get method to ExprProps.
*
* 1.2 01/07/11-16:01:58 (Codemgr)
* SunPro Code Manager data about conflicts, renames, etc...
* Name history : 2 1 handlers/ExprProps.java
* Name history : 1 0 properties/ExprProps.java
*
* 1.1 01/07/11-16:01:57 (drach)
* date and time created 01/07/11 16:01:57 by drach
*
*/
package sunlabs.brazil.properties;
import sunlabs.brazil.server.Request;
import sunlabs.brazil.util.Calculator;
import sunlabs.brazil.util.regexp.Regexp;
import java.util.Properties;
/**
*
* ExprProps
is a subclass of Properties
that
* is "smart" in the sense that it wraps a Calculator
* object, passing get
and getProperty
keys to
* the Calculator
for processing.
*
* Keys are first searched for in the Properties
* object. If not found, the key is passed to the getValue
* method of the wrapped Calculator
object. The
* Calculator
will return null
if the key
* consists of only a name or Brazil token and that name/token evaluates
* to 0. In this case, a value associated with the key can not be
* "found" and the get
or getproperty
method returns
* null
also.
*
* Only property names that "look" like expressions (e.g. contain
* at least one of characters in [&|*+/%=!<>-]) are passed to the calculator.
*
* @author Steve Drach <drach@sun.com>
* @version 2.3, 04/05/24
*
* @see java.util.Properties
* @see sunlabs.brazil.util.Calculator
* @see ExprPropsHandler
*/
public class ExprProps extends Properties {
private Calculator c;
private Request request;
// only keys that have at least one of these are considered
private static Regexp exp = new Regexp("[&|+*/%=!<>-]");
/**
* This constructor creates a Calculator
instance with
* this instance of ExprProps
as it's symbol table.
*/
public ExprProps() {
super();
c = new Calculator(this);
}
/**
*
* This constructor creates a Calculator
instance with
* this instance of ExprProps
as it's symbol table and
* with the Properties
instance referenced by the
* parameter defaults
as it's set of default values.
*
* @param defaults the defaults
*/
public ExprProps(Properties defaults) {
super(defaults);
c = new Calculator(this);
}
/**
* This constructor creates a Calculator
instance with
* request.props
as it's symbol table.
*
* @param request the Request
instance
*/
public ExprProps(Request request) {
super();
/*
* Note that request.props may have it's value changed, by BSLTemplate
* for example, after Calculator is initialized. Save request so
* a new request.props can be passed to each call to
* Calculator.getValue().
*/
this.request = request;
c = new Calculator(request.props);
}
/**
* This constructor creates a Calculator
instance with
* request.props
as it's symbol table and with the
* Properties
instance referenced by the parameter
* defaults
as it's set of default values.
*
* @param request the Request
instance
* @param defaults the defaults
*/
public ExprProps(Request request, Properties defaults) {
super(defaults);
this.request = request;
c = new Calculator(request.props);
}
/**
*
* Returns the value to which the specified key is mapped in this
* Hashtable
. If the key is not found, then it's value
* is computed by treating the key as an arithmetic expression or
* statement.
*
* If, during the computation, an ArithmeticException
is
* thrown, the key compute.error
is set in the base
* Properties
. The value associated with the key is
* an error message.
*
* @param key the Hashtable
key
*
* @return the value in this table with the
* specified key or null
*/
public Object get(Object key) {
Object val = super.get(key);
if (val == null && key instanceof String &&
null != exp.match((String) key)) {
try {
remove("compute.error");
if (request != null) {
// request.props may have changed (see BSLTemplate)
val = c.getValue((String)key, request.props);
} else {
val = c.getValue((String)key);
}
} catch (ArithmeticException e) {
put("compute.error", e.getMessage());
val = null; // should be "" perhaps but that breaks things
}
}
return val;
}
private boolean calculating; // prevent infinite recursion
/**
*
* Searches for the property with the specified key in this property list.
* If the key is not found in this property list, then it's value is
* computed by treating the key as an arithmetic expression or statement.
*
* If, during the computation, an ArithmeticException
is
* thrown, the key compute.error
is set in the base
* Properties
. The value associated with the key is
* an error message.
*
* If the result of the computation is null
, the default
* property list, and its defaults, recursively, are then checked. The
* method returns null
if the property is not found.
*
* @param key the property key
*
* @return the value in this property list with the
* specified key or null
*
* @see java.util.Properties#defaults
*/
public String getProperty(String key) {
String val = super.getProperty(key);
if (val == null && !calculating && null != exp.match(key)) {
try {
remove("compute.error");
calculating = true;
/*
* It's critical that keys that contain only a name
* return a value of null rather than 0 so they can
* be found in Property instances further down the
* list.
*/
if (request != null) {
// request.props may have changed (see BSLTemplate)
val = c.getValue(key, request.props);
} else {
val = c.getValue(key);
}
if (val != null) {
// System.err.println("Calculator: " + key + " -> " + val);
}
} catch (ArithmeticException e) {
put("compute.error", e.getMessage());
val = null; // should be "" perhaps but that breaks things
} finally {
calculating = false;
}
}
return ((val == null) && (defaults != null)) ? defaults.getProperty(key) : val;
}
}