- Introduction
- Limitations
- Requirements
- Approach
4.1. Formal Syntax
4.2. Expression Types
4.2.1. Constant
4.2.2. Synchronous
4.2.3. Asynchronous
4.3. Initial Value
4.4. Built-in Functions
4.4.1. Random Path
4.5. Built-in Values
4.5.1. Self Reference - Configuration
5.1. Item Naming
5.2. Variable Items Output Path
5.3. HTTP request headers and queries - Future Enhancements
Mongoose is extensible with storage driver and load step plugins. It also supports scenarios scripting with any JSR-223 compatible language. Moreover, any Mongoose plugin may introduce its own configuration options which are being dynamically embedded into the runtime configuration (the modular configuration feature). It is also very useful to parameterize some configuration options, i.e. the given option should supply some dynamically evaluated value which may be different on each value read. The new Mongoose version provides a general mechanism to describe the dynamic configuration options based on Java Unified Expression Language (JSR-341).
- JUEL standard doesn't allow to mix the synchronous and asynchronous evaluation in the same expression
- The initial value should be set if the self referencing is used
- Support both synchronous and asynchronous expression evaluation
- The expression result should be refreshing in background constantly in case of asynchronous evaluation
- The JUEL syntax should be extended to support the initial/seed value setting
- The expression should be able to use the result of the previous evaluation (self referencing)
- The expression should be able to invoke custom functions and access custom variables
- The expression should be able to consist of parts: prefixes/suffixes and multiple independent expressions
The requirements 2-5 are implemented as the JUEL extension in the java-commons library.
Too meet the requirement #6 the whole input string should be a sequence of segments. Any segment may be a constant string or an expression. The segment evaluation result is a constant string or an expression evaluation result. To evaluate the value of the whole input the segments evaluation results are being concatenated sequentially.
In the EBNF notation:
SEGMENTS = SEGMENT*
SEGMENT = CONST_STRING | EXPRESSION
EXPRESSION = (ASYNC_EXPR | SYNC_EXPR) \[ INIT_EXPR ]
ASYNC_EXPR = "#" EXPR_BODY_WITH_BOUNDARIES
SYNC_EXPR = "$" EXPR_BODY_WITH_BOUNDARIES
CONST_EXPR = "%" EXPR_BODY_WITH_BOUNDARIES
EXPR_BODY_WITH_BOUNDARIES = "{" EXPR_BODY "}"
Token | Description |
---|---|
CONST_STRING |
Any sequence of any symbols except #{ /${ /%{ |
EXPR_BODY |
The expression body which shouldn't contain } symbols neither any nested expressions |
For example the input string:
prefix%{42}${this.last() + 1}%{pi * e}_#{date:formatNowIso8601}suffix
will be split into the following sequence of segments:
prefix
: constant string%{42}
: constant value expression${this.last() + 1}%{pi * e}
: synchronous expression with an initial value supplied by the constant value expression_
: constant string#{date:formatNowIso8601}
: asynchronous expressionsuffix
: constant string
The given input string will yield the result like:
prefix428.539734_2019-03-07T15:23:46,461suffix
The expression is being evaluated only once upon instantiation. It's specified by the marker %
.
Expression | Yields |
---|---|
%{42} |
42 |
%{rnd.nextInt(42)} |
A random integer in the range of [0; 42) |
The constant expression is useful also to supply a constant initial value for any other types of expressions.
The expression is being evaluated on every access. The synchronous evaluation is useful if:
- The evaluation complexity is low enough
- The evaluation is non-blocking
- The different value on each invocation is strictly required
The synchronous expression is specified by the marker $
:
${time:millisSinceEpoch()}
The expression above will yield different timestamp every time.
The expression is being evaluated constantly in the background fiber. Requesting the expression value frequently is expected to yield a sequence of the same value. The asynchronous evaluation is most useful when:
- The recalculation cost is too high
- The values consumer doesn't require different value each time
The synchronous expression is specified by the marker #
:
#{date:formatNowRfc1123()}
The expression above will yield the date formatted using RFC1123 standard. The value will change sometimes irrespective to the access.
Warning:
The expression above may return
null
initially (before its 1st evaluation). To avoid this, set the initial value too:#{date:formatNowRfc1123()}%{date:formatNowRfc1123()}
The JUEL standard doesn't allow the initial value setting. However, this is required for the self-referencing functionality. The constant value expression
%{<INIT_EXPRESSION>}
should be used right after an expression to set the initial value.
For example, the expression:
${this.last() + 1}%{-1}
will produce the following sequence of values: 0, 1, 2, ...
Note:
The self reference is used in the example above to access the previous expression evaluation value
The expression may be used to supply an initial value:
#{this.last() + 1}%{rnd.nextInt(42)}
There are some useful static Java methods mapped into the expression language:
- date:formatNowIso8601() e.g. 2001-07-04T12:08:56.235-0700
- date:formatNowRfc1123() e.g. Sun, 06 Nov 1994 08:49:37 GMT
- date:formatNowAmazonStyle() e.g. 20210901T182320Z
- env:get(String name)
- int64:toString(long x, int radix)
- int64:toUnsignedString(long x, int radix)
- int64:reverse(long x)
- int64:reverseBytes(long x)
- int64:rotateLeft(long x, int distance)
- int64:rotateRight(long x, int distance)
- int64:xor(long x1, long x2)
- int64:xorShift(long x)
- math:absInt32(int x)
- math:absInt64(long x)
- math:absFloat32(float x)
- math:absFloat64(double x)
- math:acos(double x)
- math:asin(double x)
- math:atan(double x)
- math:ceil(double x)
- math:cos(double x)
- math:exp(double x)
- math:floor(double x)
- math:log(double x)
- math:log10(double x)
- math:maxInt32(int x1, int x2)
- math:maxInt64((long x1, long x2)
- math:maxFloat32(float x1, float x2)
- math:maxFloat64(double x1, double x2)
- math:minInt32(int x1, int x2)
- math:minInt64((long x1, long x2)
- math:minFloat32(float x1, float x2)
- math:minFloat64(double x1, double x2)
- math:pow(double a, double b)
- math:sin(double x)
- math:sqrt(double x)
- math:tan(double x)
- path:random(int width, int depth)
- string:format(string pattern, args...)
- string:join(string delimeter, string elements...)
- time:millisSinceEpoch()
- time:nanos()
The random path function yields a random path specified by width and depth parameters, where the width specifies the maximum count of the directories per one level and depth specifies the maximum count of such levels.
Name | Type | Description |
---|---|---|
e |
double | The base of natural logarithms |
lineSep |
string | The system-dependent line separator string |
pathSep |
string | The system-dependent path-separator |
pi |
double | The ratio of the circumference of a circle to its diameter |
rnd |
Random | The random number generator |
this |
ExpressionInput | The expression input instance (self referencing) |
There are this
among the built-in values. This is designed for the self referencing purposes. This allows to make an
expression evaluating the next value using the previous evaluation result. For example, the expression:
${this.last() + 1}
supplies the incremented value on each evaluation. The another example:
${int64:xorShift(this.last())}
supplies the new 64-bit random integer on each evaluation.
Note:
- The only useful method for the
this
is last. Please don't use any other methods.
There are two options responsible for the new items naming which support the expression values:
item-naming-prefix
item-naming-seed
Note:
The
item-naming-seed
value may be an integer either a non-composite expression evaluating an integer value.
The item-output-path
configuration option value may be an expression to generate the new path value for each new item
operation.
See the specific HTTP storage driver documentation for the details.
Use the expressions to define the following configuration options:
item-data-size
item-data-ranges-bytes