Skip to content

Pipeline Expressions Using JEXL

Richard Tomlinson edited this page Apr 21, 2016 · 9 revisions

Introduction

JEXL is an Apache Commons library intended to facilitate the implementation of dynamic and scripting features in applications. JEXL name stands for Java EXpression Language, a simple expression language originally inspired by Apache Velocity and the Expression Language defined in the JavaServer Pages Standard Tag Library version 1.1 (JSTL) and JavaServer Pages version 2.0 (JSP). JEXL 2.0 added features inspired by Unified EL. The syntax is now close to a mix of ECMAScript and "shell-script" making it easy to master by developers or testers.

In some places within the AOP testing framework it is possible to specify a JEXL expression to test for values in the pipeline.

Expressions

A JEXL expression allows conditions to be defined such that they can influence the behaviour of the mock framework by making a decision based on what has happened in previous flow steps. An expression can reference the pipeline by using a dotted notation for pipeline elements and use the regular operators to test for equality, greater, less than, etc. The sample below shows some idata

<IDataXMLCoder version="1.0">
  <record javaclass="com.wm.util.Values">
    <value name="producerId">2</value>
    <record name="producer" javaclass="com.wm.data.ISMemDataImpl">
      <value name="name">Sumito Namachi</value>
      <value name="contactDuration">36</value>
    </record>
    <record javaclass="com.wm.data.ISMemDataImpl">
      <array name="myArray" type="value" depth="1">
        <value>entry1</value>
        <value>entry2</value>
      </array>
    </record>

Some simple expressions might be:

  • producerId == 2
  • producer.name == "Sumito Namachi"
  • producer.contractDuration > 24

Its possible to use regular expressions and 'in' style checks:

  • producer.contractDuration =~ [24, 36,48] - contact duration exists in array
  • producer.name =~ "Sumito.*" - Regex match
  • producer.name =^ "Sum" - Starts with

Inbuilt Functions

  • size(myArray) == 2 - Checking size of array is expected

The http://commons.apache.org/proper/commons-jexl/reference/syntax.html has more details.

Retrieving array values

In some documents, the data may appear as an array of elements. To access arrays the usual Java like syntax of square brackets with an integer value, starting at 0, to indicate the array position. For example:

<IDataXMLCoder version="1.0">
  <record javaclass="com.wm.util.Values">
      <array name="agents" javaclass="com.wm.data.ISMemDataImpl">
          <value name="agentId">122</value>
          <value name="agentId">134</value>
      </record>
  </record>
</IDataXMLCoder>

In the case an array of agents are available so to check the first id the expression would be agents[0].agentId == 122

Dealing with special characters - namespaces and other cases

JEXL variable processing supports the use of a-z, A-Z, 0-9, underscore(_) and dollar ($) in names. In some cases there may be a need to reference a pipeline variable that uses a restricted character such as space, hyphen, dollar, at sign or colon. Use the backslash character () in front of the restricted character to escape it. Internally within the JEXL processing the backslash is replaced.

  • spaces - such as the Business Rules variable "Project Name" to "Project\ Name"
  • hyphen - "my-variable" would become "my\-variable"
  • colon - colons are used within namespaces, for example, this is a snippet of IData for a document reference:
<IDataXMLCoder version="1.0">
  <record javaclass="com.wm.util.Values">
     <value name="producerId">2</value>
     <record name="producer" javaclass="com.wm.data.ISMemDataImpl">
         <value name="prd:Id">2</value>
     </record>
   </record>
</IDataXMLCoder>

Note that the names have a colon in them as the namespace separator. So a reference to producer.prd:Id would fail. In this case, escape all colons with \ character such that this example would now be producer.prd\:Id.

In order to get around the character reference issue, the restricted characters are transformed internally into a simplified code using valid characters. When things go wrong with your expressions, such as being incorrectly formatted, in error, etc, you may see oddly named variables containing combinations of underscore and three letters. The internal representation is:

  • Colon is replaced as _col (two underscores, 'col' and underscore) so that "foo:bar" is translated to "foo__col_bar"
  • Hyphen is replaced with _hyp so that "foo-bar" is translated to "foo__hyp_bar"
  • Space is replaced with _spc so that "foo bar" is translated to "foo__spc_bar"
  • The @ is replaced with _att
  • Asterisk (*) is replaced with _ast

Using knowledge of the representations above, you should still be able to make out to which variable the error relates and correct the issue. You never need use the encoded representation in your JEXL expression.

You never need to escape the use of an underscore or dollar within a name so that "foo$bar" and "foo_bar" are both valid with no escaping.

Functions

JEXL also offers the ability to define and use custom functions which are an extension to the language. A function allows some complex processing to occur but is represented in the JEXL expression as a simple declaration. Functions are pieces of Java code and for more information on how to define and extend them, see the wm-aop-util project

Current functions available are:

arrays

  • arrays:contains(arr, str) - Searches for str in the array arr

    For some given data int the file data/arrayvalues.xml:

<?xml version="1.0" encoding="UTF-8"?>
<IDataXMLCoder version="1.0">
  <record javaclass="com.wm.data.ISMemDataImpl">
    <array name="files" type="value" depth="1">
      <value>D:\SoftwareAG\IntegrationServer\packages\OrgWmUtilTest\resources\test.xslt</value>
      <value>D:\SoftwareAG\IntegrationServer\packages\OrgWmUtilTest\resources\test2.xslt</value>
    </array>
  </record>
</IDataXMLCoder>

We can check that something does or does not exist

When invoke org.wmaop.test.services:empty with data/arrayvalues.xml
Then pipeline has arrays:contains(files, "test2.xslt") && !arrays:contains(files, "foo")
  • arrays:matches(arr, regex) - Searches for the regex match in the string array arr

    Using the data example above, we can match for an entry within the array using a regular expression

When invoke org.wmaop.test.services:empty with data/arrayvalues.xml
Then pipeline has arrays:matches(files, ".*lt")

Further information on JEXL

Details of the syntax is available at http://commons.apache.org/proper/commons-jexl/reference/syntax.html