Groovy Scripting
Groovy Scripting
The main scripting language in use in OrderFlow is Groovy.
The advantages of using Groovy are as follows:
- Groovy is a Java Virtual Machine (JVM) based language, and integrates seamlessly with the rest of OrderFlow, which is built using Java.
- Groovy is both immensely powerful but also simple to learn.
Groovy Basics
There are plenty of online tutorials on Groovy. For OrderFlow scripting we tend to rely only on its most basic features, in areas such as variable assignment, logical expressions, conditional expressions, and looping.
Variable Assignment
Done using the def
keywork:
def count = 0; //integer def state = 'ready'; //string def map = ['key1':'value1', 'key2':'value2']; map['key3'] = 'value3'; def list = [1,2]; list.add(3);
Note the format used for map and list literals.
Note that map values can also be retrieved using 'dot' notation, as in the example below.
def map = ['key1':'value1', 'key2':'value2']; map.key3 = 'value3'; print map.key3;
Note that there are restrictions in the names of keys that can be used in dot notation.
Consider the example:
def map = ['two word key':'value']; print map['two word key'];
You cannot use as a substitute for the second line:
print map.two word key;
However, the example below with the single quotes will work:
print map.'two word key';
Logical expression
Logical expressions are usually done using the if statement, followed by a conditional expression.
if (count > 10 || state == 'ready') { //do something } else if (count <= 10 && state == 'ready') { //do another thing } else { //do something else }
The conditional expression can be a compound statement, with elements joined by &&
(and) or ||
(or), operators.
Note that it is also possible to use a switch statement for:
switch (input["storeId"]) { case "1": return "Default Store"; case "2": return "US Store"; case "3": return "European Store"; default: throw new IllegalArgumentException("Unrecognised Store Id"); }
In general, our recommendation is to use if
statements if the number of outcomes is no more than three. The switch
statement is
more intuitive if there are a large number of potential outcomes.
Looping
There are different ways to do looping. The most commonly used looping construct is with the for
keyword, as shown below:
for (line in shipment.orderLines) { println line.product.externalReference; }
Return values
The value returned from a script execution is best controlled using a return
statement, as below:
return 'somevalue';
Note that if no return statement is contained, then the script will return the value of the most recently evaluated expression. As it is not always very easy to identify what this will be, it is best practice to explicitly use return statement when relying on the value returned from a script.
Null Values
Groovy can access information from the OrderFlow data model using compound expressions such as:
shipment.site.externalReference
Note that if the site has not yet been set on the site, the code above will fail with a NullPointerException
(NPE).
Groovy provides a very simple and useful way to write 'NPE safe' expressions, using the ?
operator. In the case above, the following code
will not fail with a NullPointerException
, but will instead will return a null
value.
shipment.site?.externalReference
Formatting and Parseing
Groovy has some useful formatting functionality which can be useful, for example, for formatting dates and numbers:
Date Formatting
Dates can be formatted using code such as the following:
def dateString = new java.text.SimpleDateFormat('yyyy-MM-dd hh:mm:ss').format(shipment.created); println date;
The date format can obviously be set to the required value. There are many tutorials on the internet on how to use SimpleDateFormat
for this purpose.
Date Parseing
The class java.text.SimpleDateFormat
can also parse a date from a text string. This is useful for converting dates from a different format.
def date = new java.text.SimpleDateFormat('dd/MM/yy hh:mm:ss').parse('30/10/15 23:11:15'); def newDateString = new java.text.SimpleDateFormat('yyyy-MM-dd hh:mm:ss').format(date); println newDateString;
Number Formatting
Groovy scripts can be used for number formatting in a number of ways. A simple example is shown below, which formats a decimal with two decimal character.
println String.format('%.2f', 1.345)
which will output the value 1.35
.
Scripting Context
An important concept to understand with scripting is the scripting context.
Sometimes you may see scripts that variables that don't appear to have been 'defined'. An example is shown below:
if (input['key'] == 'testvalue') { ... }
In the above snippet, there is no declaration of the input
variable. Instead, the input
variable has been
added to the scripting context independently of the script itself.
Scripts in OrderFlow almost always rely on some scripting context to achieve a result. For example, for a script that
need to operate on or extract data from a shipment
, the shipment will invariably be present in the scripting context.
The details of the scripting context for the different types of scripts run in OrderFlow are covered in the different sections of this document.
Sandboxing
The Groovy that can be executed within OrderFlow environments is tightly controlled to avoid the risk of undesirable or risky code being added to scripts.
However, by default, the following applies:
- methods or constructors cannot be called in any of the 'system' classes in the
java.lang
package, includingSystem
,ClassLoader
,Thread
,Runtime
orSecurity
. - objects can only be instantiated from the packages
java.lang
,java.util
andjava.text
.
For certain scripting context, these limitations are relaxed slightly to allow for access to methods in specific packages to support functionality likely to be required in that scripting environment.