esper.codehaus.org and espertech.comDocumentation
Esper allows the use scripting languages within EPL. You may use scripts for imperative programming to execute certain code as part of EPL processing by the engine.
The syntax and examples outlined below discuss how to declare a script that is visible to the same EPL statement that listed the script.
For declaring scripts that are visible across multiple EPL statements i.e. globally visible scripts please consult Section 5.19.2, “Declaring a Global Script”
that explains the create expression
clause.
Any scripting language that supports JSR 223 and also the MVEL scripting language can be specified in EPL. This section provides MVEL and JavaScript examples.
For more information on the MVEL scripting language and its syntax, please refer to MVEL At Codehaus. MVEL is an expression language that has a natural syntax for Java-based applications and compiles to provide fast execution times. To use MVEL with Esper, please make sure to add the MVEL jar file to the application classpath.
For more information on JSR 223 scripting languages, please refer to external resources. As JSR 223 defines a standard API for script engines, your application may use any script engine that implements the API. Current JVM versions ship with a JavaScript script engine. Other script engines such as Groovy, Ruby and Python scripts can be used as implementations of JSR 223.
As an alternative to a script consider providing a custom single row function as described in Section 17.3, “Single-Row Function”
The syntax for scripts is:
expression [return_type] [dialect_identifier:] script_name [ (parameters) ] [ script_body ]
Use the expression
keyword to declare a script.
The return_type is optional. If the script declaration provides a return type the engine can perform strong type checking: Any expressions that invoke the script and use the return value are aware of the return type. If no return type is provided the engine assumes the script returns java.lang.Object
.
The dialect_identifier is optional and identifies the scripting language. Use mvel
for MVEL , js
for JavaScript and python
for Python and similar for other JSR 223 scripting languages.
If no dialect identifier is specified, the default dialect that is configured applies, which is js
unless your application changes the default configuration.
It follows the script name. You may use the same script name multiple times and thus overload providing multiple signatures under the same script name. The combination of script name and number of parameters must be unique however.
If you have script parameters, specify the parameter names for the script as a comma-separated list of identifiers in parenthesis. It is not necessary to list parameter types.
The script body is the actual MVEL or JavaScript or other scripting language script and is placed in square brackets: [ ... script body ...]
.
The next example shows an EPL statement that calls a JavaScript script which computes the Fibonacci total for a given number:
expression double js:fib(num) [ fib(num); function fib(n) { if(n <= 1) return n; return fib(n-1) + fib(n-2); } ] select fib(intPrimitive) from SupportBean;
The expression
keyword is followed by the return type (double
), the dialect (js
) and the script name (fib
) that declares a single parameter (num
).
The JavaScript code that computes the Fibonacci total is between square brackets []
.
The following example shows an EPL statement that calls a MVEL script which outputs all the different colors that are listed in the colors
property of each ColorEvent
:
expression mvel:printColors(colors) [ String c = null; for (c : colors) { System.out.println(c); } ] select printColors(colors) from ColorEvent;
This example instead uses JavaScript to print colors and passes the event itself as a script parameter:
expression js:printColors(colorEvent) [ importClass (java.lang.System); importClass (java.util.Arrays); System.out.println(Arrays.toString(colorEvent.getColors())); ] select printColors(colorEvent) from ColorEvent as colorEvent
The engine provides a built-in script object under the variable name epl
to all scripts. Your scripts may use this script object to share and retain state by setting and reading script attributes.
The epl
script object implements the interface com.espertech.esper.client.hook.EPLScriptContext
. The EPLScriptContext
interface has two methods: The void setScriptAttribute(String attribute, Object value)
method to set an attribute value and the Object getScriptAttribute(String attribute)
method to read an attribute value.
The engine maintains a separate script object per context partition, or per statement if not declaring a context. Therefore script attributes are not shared between statements.
The next example demonstrates the use of the epl
script object. It outputs a flag value true
when an RFID event matched because the location is A
,
and outputs a flag value false
when an RFID event matched because the location is B
. The example works the same for either MVEL or JavaScript dialects: You may simple replace the js
dialect with mvel
.
expression boolean js:setFlag(name, value, returnValue) [ if (returnValue) epl.setScriptAttribute(name, value); returnValue; ] expression js:getFlag(name) [ epl.getScriptAttribute(name); ] select getFlag('locA') as flag from RFIDEvent(zone = 'Z1' and (setFlag('locA', true, location = 'A') or setFlag('locA', false, location = 'B')) )
The example above utilizes two scripts: The setFlag
script receives an attribute name, attribute value and a return value. The script sets the script attribute only when the return value is true. The getFlag
script simply returns the script attribute value.
Upon EPL statement compilation, the engine resolves script parameter types and performs script compilation. At runtime the engine evaluates the script in its compiled form.
As the engine cannot inspect scripts if is not possible for the engine to perform query planning or many optimizations based on the information in scripts. It is thus recommended to structure EPL such that basic filter and join expressions are EPL expressions and not script expressions.
Your EPL may declare a return type for the script. If no return type is declared and when using the MVEL dialect, the engine will infer the return type from the MVEL expression analysis result. If the return type is not provided and cannot be inferred or the dialect is not MVEL, the return type is Object
.
If the EPL declares a numeric return type then engine performs coercion of the numeric result to the return type that is specified.
In the case that the EPL declares a return type that does not match the type of the actual script return value, the engine does not check return value type.