Advanced code examples

Please refer to basic code examples document for naming conventions and logging strategies.

Sharing parameters

It can be useful to store parameters (or serializable objects) in the user's session (Grant) or object instances (ObjectDB)

Object-level parameter

Examples:

Share a parameter between objects:

MyObjectA.initUpdate = function() {
    // To store the current RowId of this object
    this.getGrant().setParameter("MYAPP_CONTEXT_ID", this.getRowId());
}

MyObjectB.initList = function(parent) {
    // To use the current Id of A when a list B is displayed
    var id = this.getGrant().getParameter("MYAPP_CONTEXT_ID");
    if (id && id!="") // ...
};

MyExternalObjectC.display = function(param) {
    // To use the current Id of A when the external object is displayed
    var id = this.getGrant().getParameter("MYAPP_CONTEXT_ID");
    if (id && id!="") ...
};

MyObjectB.myAction = function() {
    // To use the current Id of A when a list B is displayed
    var id = this.getGrant().getParameter("MY_CONTEXT_ID");
    if (id && id!="") ...
};

Store a set of data (as org.json.JSONObject between hooks of the same object:

MyObject.postValidate = function() {
    var data = new JSONObject().put("key1", "value").put("key2", 123).put("key3", new JSONArray().put(new JSONObject(...)));
    this.setParameter("MY_DATA", data);
}
MyObject.postSave = function() {
    var data = this.getParameter("MY_DATA");
    console.log(data.toString());
    var k1 = data.getString("key1");
    var k2 = data.getInt("key2");
    var k3 = data.getJSONArray("key3");
    // ...
}

Etc.

Global parameter

To make a global setting, it is necessary to use the system singleton

Grant.getSystemAdmin().setParameter(name, value);
Grant.getSystemAdmin().getParameter(name);
Grant.getSystemAdmin().removeParameter(name);

Session parameter

The best solution is to load the parameter depending on user in the GrantHooks at logon:

Example:

GrantHooks.postLoadGrant = function(grant) {
    var login = grant.getLogin();
    var employeeId = grant.simpleQuery("select ... query depending on login ...");
    grant.setParameter("MYAPP_EMP_ID", employeeId || "unknown");
    var empPhone = Tools.readURL("http://...external REST service...");
    grant.setParameter("MYAPP_EMP_PHONE", empPhone || "");
};

Booby traps:

Advanced validations

Phone number validations

As of version 3.1 MAINTENANCE 07, it is possible to do an advanced validation of phone numbers fields (typically in a preValidate or postValidate hook).

Example:

var f = this.getFieldValue("myPhoneNumber");
f.setValue("myPhoneNumber", new PhoneNumTool("fr").getNationalNumber(f.getValue()));

Note: it is also possible to format as international number using getInternationalNumber instead of getNationalNumber

Data preparation

Dynamic list generation

In order to programmatically generate a list of values, you have to

  1. assign a non-empty list of values to the field, as you would for a normal list, to avoid simplicite-triggered EMPTY LIST errors
  2. build the list in your object's postLoad hook

Example:

MyObject.postLoad = function(){
    var yearsList = emptyAndGetList(this.getField("YourField"));

    for(var i=2010; i<=2100; i++){
        yearsList.putItem(new EnumItem(i.toString(),i.toString()));
    }
};

function emptyAndGetList(field){
  field.setList(new ObjectFieldList(field));
  return field.getList();
}

Data encryption

As of version 3.2 you can use the EncryptionToolclass to encrypt/decrypt a field value.

Example:

MyObject.key = function() {
    // ZZZ set as a system parameter (make sure to configure it as "private") ZZZ
    //return this.getGrant().getParameter("MY_ENCRYPTION_KEY");
    // or
    // ZZZ pass this to the JVM by -Dmy.encryption.key=...
    //return System.getProperty("my.encryption.key");
    // or
    // ZZZ set this in the JVM environent
    return System.getEnv("MY_ENCRYPTION_KEY");
    // etc.
};

MyObject.preSave = function() {
    // Encrypt the value before saving
    var l = this.getField("mySensitiveField");
    l.setValue(EncryptionTool.encrypt(l.getValue(), MyObject.key.call(this)));
};

MyObject.postSelect = function(rowId, copy) {
    // Decrypt the value after selecting it
    var l = this.getField("mySensitiveField");
    l.setValue(EncryptionTool.decrypt(l.getValue(), MyObject.key.call(this)));
};

Note: an encrypted field using this method cannot be searchable except of exact values (by encrypting the search filter in the preSearch hook)

Call remote URL with client certificate

In this example the object is storing the client certificate JKS file as a document field and the certificate password as a password field.

It can be easily transposed with the JKS avialable as a static local file or as a (protected) resource and with the password stored as a system parameter or a environment variable etc.

MyObject.callAPI = function() {
    var url = "https://myremotehost/myservice";
    var cert = this.getField("myClientCertificateField").getDocument();
    var pwd = this.getFieldValue("myClientCertificatePasswordField");
    console.log("Calling " + url + " with client certificate " + cert.getName());
    return Tool.readUrlWithClientCert(url, cert.getBytes(true), pwd);
};

Note: the client certificate must be a JKS file, if you have a PEM certificate you can convert it to JKS format converting it first as PKCS12 using openssl pkcs12 -export -inkey mycert.key -in mycert.pem -out mycert.p12 and then importing it in a JKS file using keytool -importkeystore -destkeystore mycert.jks -srckeystore mycert.p12 -srcstoretype PKCS12 (you will be prompted to enter the passwords for the certficates)