Basic code examples

These basic guidelines and examples are given using the server-side Rhino scripting language syntax for usage within business object scripts, workflow scripts, external object scripts, ...

For more details on Rhino sscripting you can check the Mozilla Rhino documentation


In Rhino scripts the this variable correspond to the contextual item (business object, workflow, external obejct, ...) itself, it must be explicitly used (it can't be implicit like in Java code).

The Rhino-only code examples can easily be transposed to equivalent Java code. Some examples are provided both in Rhino and Java so as you can see the syntax differences.

Apart from the variable and methods declarations syntax, the main point of attention is regarding comparisons syntax for non raw types:

  • Rhino: a == b, Java: a.equals(b)
  • Rhino: a != b, Java: !a.equals(b)

Naming conventions

Recommended naming conventions are:

Pakages inclusion

All scripts are processed with the following packages included by default:


It is possible to include a whole additional packages by:

importPackage(Packages.<java package name (e.g. org.apache.commons.lang3)>);

or a single class by:

importClass(Packages.<java class name (e.g. org.apache.commons.lang3.StringUtils)>);


console.log(StringUtils.isNumeric("hello world")); // false
console.log(StringUtils.isNumeric("123")); // true


Console logging

It is possible to log messages using:

console.debug("Hello world !");   // Debug level message"Hello world !");    // Info level message
console.warning("Hello world !"); // Warning level message
console.error("Hello world !");   // Error level message
console.fatal("Hello world !");   // Fatal level message

It is also possible to link a message to an explicit log code:

console.log("Hello world !", "MYLOGCODE_001");

Note that if the log code is omitted the log method is the equivalent to the default infomethod.

The messages are actually displayed depending on the log appenders configuration and on the log code associated configuration.

It is possible to set custom target log codes for default log methods using:

console.setDebugCode("MYLOGCODE_000");   // Otherwise the default DEBUG code is used 
console.setInfoCode("MYLOGCODE_001");    // Otherwise the default INFO code is used 
console.setWarningCode("MYLOGCODE_002"); // Otherwise the default WARN code is used 
console.setErrorCode("MYLOGCODE_003");   // Otherwise the default ERROR code is used 
console.setFatalCode("MYLOGCODE_004");   // Otherwise the default FATAL code is used 

Debug hook calls & SQL logging (as of version 3.1)

Designers can activate the hooks tracer during the development phase. At the top of the object script add the following code:

// Trace object hooks
// - Tracks the calls hierarchy
// - Tracks the call frequency and the durations
var trace = true;     // to active the hooks tracer
var traceAll = true;  // trace all hooks to display the calls hierarchy or only the implemented ones
var traceArgs = true; // trace all hooks arguments or only simple ones
console.traceHooks(trace, traceAll, traceArgs);

// Trace object CRUD 
// - Tracks object accesses
// - Explains the SQL statements

Rhino usual traps

The Rhino scripting engine has several usual traps that are worth mentionning here:

Native Rhino string vs Java strings

The native Rhino strings that you may create with instructions like var s = ""; are not Java strings. This may cause issues when passing these native Rhino strings as arguments of some Java methods.

Our recommendation is thus not to instanciate native Rhino strings in your server scripts but rather instanciate explicit Java strings using either new java.lang.String() or the ScriptInterpreter.getString() method.

Native Rhino objects/arrays vs Java objects/arrays

The native Rhino arrays that you may create with instructions like var a = []; are not Java arrays. Depending on the Rhino version, some methods of the ECMAScript specification are not well (or not yet) implemented on Rhino native arrays (e.g. the indexOf method) Same for native Rhino objects that you may create with instructions like var o = {};.

The worst thing to do is to use native Rhino object/array containing Java objects. For instance:

JSON.stringify({name:"myname"}); // OK 
JSON.stringify({name:new java.lang.String("myname")+""}); // OK (the +"" turns Java string into a native Rhino string)
// JSON.stringify({name:new java.lang.String("myname")}); => error

Our recommendation is thus not to use the confusing native Rhino objects or arrays in your scripts but rather Java maps or arrays/lists like HashMap or ArrayList or, better, Java JSON objects JSONObject and JSONArray instead.


Note that the methods Tool.concat/append/merge are useful to simplify the manipulation of Java arrays.


If you compare Java strings and native Rhino strings you must pay attention to the compare method:


var a = new java.lang.String("hello"); // a is a Java String object
var b = "hello";                       // b is a native Rhino string object
console.log(a.equals(b)); // true
console.log(b.equals(a)); // true
console.log(a == b);      // true
console.log(a === b);     // false (because objects are not of the same type)

You also need to pay a particular attention to comparisons between raw Java and/or native Rhino type variables and Java wrapper objects such as java.lang.Integer, java.lang.Boolean, ...


var x = new java.lang.Integer(10);
var y = 10;
console.log(x.equals(y)); // false
console.log(x == y);      // true
console.log(x === y);     // false
//console.log(y.equals(x)); => error


var x = new java.lang.Boolean(true);
var y = true;
console.log(x.equals(y)); // true
console.log(x == y);      // true
console.log(x === y);     // false
//console.log(y.equals(x)); => error

And also keep in mind that Rhino is more "tolerant" than Java when comparing strings and raw types:


var x = new java.lang.String("10");
var y = "10";
var z = 10;
console.log(x.equals(y)); // true
console.log(y.equals(x)); // true
console.log(x == y);      // true
console.log(x === y);     // false
console.log(x.equals(z)); // false
console.log(x == z);      // true
console.log(x === z);     // false
console.log(y.equals(z)); // true
console.log(y == z);      // true
console.log(x === z);     // false
//console.log(z.equals(x or y)) => error

In all cases, when comparing variables of different types, you need to be sure of what you are doing. Therefore our recommendation is to use == by default unless you have a very specific comparison to do.

Note: as of version 4.0 constraint expressions are processed both at server and client level if your constraint is marked both "static/back" and "front". In client-side Javascript the equals does not exists, so for such server+client constraint expressions you must use == to avoid issues on client side.

JDK scripting engine considerations

As of JDK 8 the default javax.script scripting engine (Nashorn) is not the same as in previous JDKs (Rhino).

As of JDK 13 Nashorn is scheduled to be removed shortly from the JDK.

To avoid compatibility problems the up-to-date Rhino script engine has been added as third party JSR223 libs and is explicitly used instead of the defaut javax.script.

For more details on Rhino scripting engine you can check the Mozilla Rhino documentation

Business objects manipulation


Search with filters.

Without pagination:

Rhino script

var o = this.getGrant().getTmpObject("myObject");
o.getField("myFkField").setFilter(this.getRowId()); // Foreign key
o.getField("myField1").setFilter("ABC"); // simple text
o.getField("myField2").setFilter("is not null"); // or is null
o.getField("myField3").setFilter("in (1,5,8)"); // or not in
o.getField("myField4").setFilter("like 'AB%')"); // etc.
o.getField("myDatetime1").setFilterDateMax("2013-06-26 23:45:23");
o.getField("myBoolean1").setFilter(true); // or false
o.getField("myInteger1").setFilter(">100 and <200");
o.getField("myString1").setFilter("='abc' or ='def'");

var rows =;
for (var i = 0; i < rows.size(); i++) {
    var row = rows.get(i);
    var val = o.getField("myField1").getValue();
    // Etc.


ObjectDB o = getGrant().getTmpObject("myObject");
// Same as above regarding filters

for (String[] row : {
    String val = o.getField("myField1").getValue();

With pagination:

Rhino script

var totalNbRows = o.getCount();
var maxRowsPerPage = 200;
o.preparePagination(totalNbRows, maxRowsPerPage);
for (var p = 0; p <= o.getMaxPage(); p++) {
    var rows =, maxRowsPerPage);
    for (int i = 0; i < rows.size(); j++) {
        var row = rows.get(i);
        var val = o.getField("myField1").getValue();


long totalNbRows = o.getCount();
int maxRowsPerPage = 200;
o.preparePagination(totalNbRows, maxRowsPerPage);
for (int p = 0; p <= o.getMaxPage(); p++) {
    for (String[] row :, maxRowsPerPage) {
        String val = o.getField("myField1").getValue();

Using enumerations fields' code/values

Enumeration fields are particular because they refer a list of value which consist of a list of code and value.

You should thus never use the values but only the codes in your code.

Example: iterate on the codes of a field's list of values:

Rhino script

var l = o.getField("myField").getList().getList().getAllItems();
for (var i = 0; i < l.size(); i++)) {
    var code = l.get(i).getCode();


for (EnumItem item : o.getField("myField").getList().getAllItems()) {
    String code = item.getCode();


Sending emails

try {
    var mailer = new Mail(this.getGrant());
            "<html><body>Hello World !</body></html>");
} catch (e) {
    console.error("Error sending mail" + e.getMessage());

Note: There are several variants of the Mail.send method offering the possibility to add attachments, etc.

ZIP files

Read ZIP file

This simple example unzips a ZIP file read from a public URL and unzip it to a temporary folder for processing files:

    var destDir = new File(this.getGrant().getTmpDir() + "/mydata." + System.currentTimeMillis());
try {
    var zipData = Tool.readUrlAsByteArray(url, true);
    ZIPTool.extract(zipData, destDir);
    // Do something with files of file contents located in destDir, e.g. using FileTool methods
} catch (e) {
} finally {

Write ZIP file

This simple example zips a list of text files and return the ZIP file as a byte array:

try {
    var files = new HashMap<>();
    var data = "Hello world";
    files.put("test1.txt", (data + " 1").getBytes());
    files.put("test2.txt", (data + " 2").getBytes());
    // ...
    files.put("testN.txt", (data + " N").getBytes());
catch (e)

Note: There are several other methods and variants in Tool, ZIPTool and FileTool that you ca use to manipulate URLs and files