public class TestDriver
extends java.lang.Object
This class is accessible both from the command line (see main(java.lang.String[])
for
required arguments) and programatically (see the following methods:
initialize
computeResults
(of an arithmetic expression)compute
(an arithmetic expression)evaluateResults
(of a logical expression)evaluate
(a logical expression)
Where this class must interface to the expression compiler, the data type
constants from SymbolResolver
are used. However, this class
supports the concept of application-defined user types. This abstraction
of data typing permits application code to do its own interpretation of
expression tokens at compile time (for instance when the compiler calls
resolveConstant
), or when initializing variables from
the properties file. Ultimately, however, any expression token which will
be resolved at expression compile time or runtime must be mapped to a
SymbolResolver
type constant.
As an example, this test driver supports the notion of an application
defined date
data type. This permits the implementation of
more advanced parsing of formated date strings during initialization,
or during expression compilation, when a string constant formated as a
date is encountered. The application defined date
data type
is mapped to a long internally. When a formated date
string or a variable of type date
must be resolved, it is
converted to a Long
value representing the number of
milliseconds since 1970.01.01.
A sample set of properties follows:
# # Data for a sample variable resolver. Sets up a simple database of employee # records. # # # Acceptable formats for date/time constants in expressions. These determine # how date and time information are parsed by the application. # date.format.0 = yyyy.MM.dd date.format.1 = MM/dd/yyyy date.format.2 = MMM dd, yyyy date.format.3 = HH:mm:ss date.format.4 = yyyy/MM/dd HH:mm:ss # # Boolean constants. These will be reserved keywords in the application. # 'true' and 'false' are directly supported by the compiler. # boolean.constant.yes = true boolean.constant.no = false boolean.constant.T = true boolean.constant.F = false boolean.constant.yup = true boolean.constant.nope = false # # Variable data types. The meanings of these data types are specific to the # testcase application, which uses them as clues for parsing. # # employee name type.name = string # employee date of birth type.dob = date # number of overtime hours (fractional) type.overtime = double # employee's city type.city = string # employee's union affiliation status type.union = boolean # time shift begins (millis since midnight) type.begin = date # time shift ends (millis since midnight) type.end = date # # "Employee" records. Groups of variables which have the same index number # in their property key name comprise the same record. # emp.1.name = Larry emp.1.dob = 1950.01.14 emp.1.overtime = 0. emp.1.city = Boston emp.1.union = true emp.1.begin = 09:00:00 emp.1.end = 17:30:00 emp.2.name = Moe emp.2.dob = 1960.05.21 emp.2.overtime = 5.5 emp.2.city = St. Louis emp.2.union = true emp.2.begin = 06:00:00 emp.2.end = 15:00:00 emp.3.name = Curly emp.3.dob = 1945.11.13 emp.3.overtime = 24.25 emp.3.city = New York emp.3.union = false emp.3.begin = 07:30:00 emp.3.end = 17:15:00
Modifier and Type | Class and Description |
---|---|
private class |
TestDriver.SymbolLibrary
This class illustrates a sample library of user functions available to
the
TestDriver user. |
Modifier and Type | Field and Description |
---|---|
private static java.lang.String |
APPTYPE_BOOLEAN
Application defined boolean data type
|
private static java.lang.String |
APPTYPE_DATE
Application defined date data type
|
private static java.lang.String |
APPTYPE_DOUBLE
Application defined double data type
|
private static java.lang.String |
APPTYPE_LONG
Application defined long data type
|
private static java.lang.String |
APPTYPE_STRING
Application defined string data type
|
private java.util.Map |
currentRecord
Data record currently being used in an expression evaluation
|
private java.util.List |
dateFormats
List of acceptable date formats, in order of use when parsing
|
private static boolean |
debug
Expression class files are dumped to current directory when true
|
private static java.lang.String |
PFX_BOOL_CONSTANT
Boolean constant keyword prefix in initialization properties
|
private static java.lang.String |
PFX_DATE_FORMAT
Date format keyword prefix in initialization properties
|
private static java.lang.String |
PFX_TYPE
Variable data type keyword prefix in initialization properties
|
private static java.lang.String |
PFX_VAR_EMP
Employee variable keyword prefix in initialization properties
|
private java.util.List |
records
List of data records, in index order
|
private java.util.Map |
reservedMap
Map of reserved keywords to constant values
|
private java.util.Map |
symbolAppTypeMap
Map of symbol names to app-defined data type names
|
private static java.util.Map |
TYPE_CONSTANTS
Map of app-defined type names to SymbolResolver type constants
|
Constructor and Description |
---|
TestDriver()
Default constructor.
|
Modifier and Type | Method and Description |
---|---|
private void |
checkRange(int first,
int last)
Validate that the range specified by
first and
last corresponds with the number of data records loaded
into the current instance of the test driver. |
private static void |
endWithHelp(int rc)
Abort the program and display help text.
|
int |
getRecordCount()
Get the number of data records managed by the current instance of the
test driver.
|
private void |
initialize(java.util.Properties props)
Initialize the driver by storing all acceptable date format strings,
boolean constants, application-defined data type to variable mappings,
and variable values.
|
static void |
main(java.lang.String[] args)
Command line entry point into program.
|
private java.util.Date |
parseDate(java.lang.String source)
Try to parse
source as a date string using each of the
acceptable date format strings provided by the configuration. |
private java.lang.Object |
parseDatum(java.lang.String key,
java.lang.String value)
Parse
value into an object of the correct type, using
key as a cue to its data type. |
private int |
parseIndex(java.lang.String key,
int start)
Extract a numeric value from the string
key . |
private java.lang.String |
parseToken(java.lang.String key,
int start)
Extract a token substring of
key which begins at character
index start and ends either at the next dot separator
character encountered or at the end of key . |
private void |
readBooleanConstant(java.lang.String key,
java.lang.String value)
Read and parse a boolean constant string configuration property.
|
private void |
readDataRecordVariable(java.lang.String key,
java.lang.String value,
java.util.Map map)
Read and parse a data variable configuration property.
|
private void |
readDataType(java.lang.String key,
java.lang.String value)
Read and parse a data type configuration property.
|
private void |
readDateFormat(java.lang.String key,
java.lang.String value,
java.util.Map map)
Read and parse a date format string configuration property.
|
private java.lang.String |
stripEnclosing(java.lang.String text,
char c)
Strip specified enclosing character, if any, from the beginning and end
of a string.
|
private static final boolean debug
private static final java.lang.String PFX_DATE_FORMAT
private static final java.lang.String PFX_BOOL_CONSTANT
private static final java.lang.String PFX_TYPE
private static final java.lang.String PFX_VAR_EMP
private static final java.lang.String APPTYPE_BOOLEAN
private static final java.lang.String APPTYPE_LONG
private static final java.lang.String APPTYPE_DATE
private static final java.lang.String APPTYPE_DOUBLE
private static final java.lang.String APPTYPE_STRING
private static final java.util.Map TYPE_CONSTANTS
private java.util.List dateFormats
private java.util.Map symbolAppTypeMap
private java.util.Map reservedMap
private java.util.List records
private java.util.Map currentRecord
public TestDriver() throws java.lang.NoSuchMethodException
java.lang.NoSuchMethodException
private void initialize(java.util.Properties props)
Properties
. Two passes are necessary because
we iterate through the keys in props
in an indeterminate
order. It is necessary to know about constant values, date format
strings, and the variables' data type mappings (all collected during
the first pass) in order to parse their values correctly in the second
pass.
Important: in order for this test driver to do anything useful at expression runtime, this method must be called beforehand to populate the driver with data. Otherwise, no variables or constants used in expressions will be resolvable.
See the class description
for a sample of the
properties format which is expected by this method.
props
- Configuration propertiesprivate void readDateFormat(java.lang.String key, java.lang.String value, java.util.Map map) throws java.lang.IllegalArgumentException, java.lang.NumberFormatException
SimpleDateFormat
object for later parsing of date strings,
and store this in map
. The object's key in map
is the numeric index extracted from the end of the property's key name.key
- Configuration property key name.value
- Configuration property value as a string.map
- Map into which SimpleDateFormat
object will be
stored.java.lang.IllegalArgumentException
- if key
represents an unexpected key name.java.lang.NumberFormatException
- if a valid numeric index cannot be extracted from
key
.private void readBooleanConstant(java.lang.String key, java.lang.String value) throws java.lang.IllegalArgumentException
0
for
false
and non-zero (1
, conventionally) for
true
. The last portion of the property key name represents
the name of the symbolic constant, which is stored as a reserved key
word.key
- Configuration property key name.value
- Configuration property value as a string.java.lang.IllegalArgumentException
- if key
represents an unexpected key name.private void readDataType(java.lang.String key, java.lang.String value) throws java.lang.IllegalArgumentException
key
- Configuration property key name.value
- Configuration property value as a string.java.lang.IllegalArgumentException
- if key
represents an unexpected key name.private void readDataRecordVariable(java.lang.String key, java.lang.String value, java.util.Map map) throws java.lang.IllegalArgumentException, java.lang.NumberFormatException
Map
object)
is constructed and stored by index within map
.key
- Configuration property key name.value
- Configuration property value as a string.map
- Map which holds data records.java.lang.IllegalArgumentException
- if key
represents an unexpected key name or the
variable name extracted from key
collides with
the name of a reserved keyword.java.lang.NumberFormatException
- if a valid numeric index cannot be extracted from
key
.private int parseIndex(java.lang.String key, int start) throws java.lang.IllegalArgumentException, java.lang.NumberFormatException
key
. The portion
of key
which contains the numeric value is expected to
begin at character index start
. It is expected to end
either at the next '.
' (dot) character encountered or at
the end of key
.key
- String from which numeric value is to be extracted.start
- Starting character of numeric value within key
.key
.java.lang.IllegalArgumentException
- if start
is an out of bounds index for
key
.java.lang.NumberFormatException
- if a valid numeric index cannot be extracted from
key
.private java.lang.String parseToken(java.lang.String key, int start) throws java.lang.IllegalArgumentException
key
which begins at character
index start
and ends either at the next dot separator
character encountered or at the end of key
.key
- String from which token is to be extracted.start
- Starting character of token within key
.key
.java.lang.IllegalArgumentException
- if start
is an out of bounds index for
key
.private java.lang.Object parseDatum(java.lang.String key, java.lang.String value)
value
into an object of the correct type, using
key
as a cue to its data type. First check if
value
represents a reserved keyword and if so, return
its constant value. Next, parse the value based on key
's
data type. If key
is null
, or its data type
cannot be determined, try parsing value
as a date, then
default to treating it as a string literal.key
- The key associated with the value to be parsed.value
- String to be looked up as a reserved keyword or to be parsed
into an object of the correct type.value
, or null
if it could not be parsed propertly.private java.util.Date parseDate(java.lang.String source)
source
as a date string using each of the
acceptable date format strings provided by the configuration. The
order in which format patterns are attempted is that specified in the
configuration.source
- Text to be recognized as a formated date.source
, or
null
if no format pattern could be applied
successfully.private java.lang.String stripEnclosing(java.lang.String text, char c)
text
.text
- Text from which to remove character.c
- Character to be removed.public int getRecordCount()
private void checkRange(int first, int last) throws java.lang.IllegalArgumentException
first
and
last
corresponds with the number of data records loaded
into the current instance of the test driver. Also make sure that
first
is not greater than last
.first
- One-based index of first record to be used.last
- One-based index of last record to be used.java.lang.IllegalArgumentException
- if specified range of records is invalid.private static void endWithHelp(int rc)
rc
- Process return code to be passed to the operating system.public static void main(java.lang.String[] args)
properties
(required) - configuration properties
filetype
(required)
A
- specifies arithmetic (numeric) expressionL
- specifies logical (boolean) expressionexpression
(required) - an arithmetic or logical
expression in double quotes (type must match type
argument and variable and constant references must be those which
have been configured in properties
)first
(optional) - 1-based index of the first data
record to apply to expression
last
(optional) - 1-based index of the last data
record to apply to expression
; can only be specified
if preceded by first