Basic code examples

These basic examples are given using the scripted Java Rhino scripting engine syntax for usage within business object scripts, workflow scripts, external object scripts, ... In such scripts the explicit this variable correspond to the contextual item (the business object, the workflow, the external object, ...). In such contexts, user rights are available as this.getGrant().

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

Naming conventions

Recommended naming conventions are:

Pakages inclusion

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

java.lang
java.util
org.json
com.simplicite.util.exceptions
com.simplicite.util.tools
com.simplicite.util
com.simplicite.bpm
com.simplicite.webapp
com.simplicite.webapp.tools

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)>);

Example:

importClass(Packages.org.apache.commons.lang3.StringUtils);
console.log(StringUtils.isNumeric("hello world")); // false
console.log(StringUtils.isNumeric("123")); // true

Logging

Console logging

It is possible to log messages using:

console.debug("Hello world !");   // Debug level message
console.info("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
console.traceObject(true);

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.

Examples:

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

Comparisions

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

Example:

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, ...

Examples:

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

or

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:

Example:

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).

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 object manipulation

Searching

Search with filters and no pagination:

var o = this.getGrant().getTmpObject("myObject");
o.resetFilters();
o.getField("myField1").setFilter("ABC");
o.getField("myField2").setFilter("is not null"); // or is null
o.getField("myField3").setFilter("in (1,5,8)"); // or not in
o.getField("myDate1").setFilterDateMin(Tool.getCurrentDate());
o.getField("myDatetime1").setFilterDateMax("2013-06-26 23:45:23");
o.getField("myBool1").setFilter(true); // or false
o.getField("myInteger1").setFilter(">100 and <200");
o.getField("myString1").setFilter("='abc' or ='def'");

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

Paginated search:

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

Others

Sending emails

try {
    var mailer = new Mail(this.getGrant());
    mailer.send(
            "from@mydomain.com",
            "to@mydomain.com",
            "Subject",
            "<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.

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 zipData = Tool.readUrlAsByteArray(url, true);
var destDir = new File(this.getGrant().getTmpDir() + "/mydata." + System.currentTimeMillis());
try {
    ZIPTool.extract(zipData, destDir);
    // Do something with files of file contents located in destDir, e.g. using FileTool methods
} catch (e) {
    console.log(e.message);
} finally {
    FileTool.deleteFileOrDir(destDir);
}

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