Business Rule Functions

Business Rule Functions

Business Rule functions are the functions that can be executed with Business Rule expressions. You can view a list of available Business Rule functions by clicking the "Functions" tab on the expression window:

images/download/attachments/144836500/image-2023-9-25_12-3-9-version-1-modificationdate-1695661391000-api-v2.png


Business Rule functions may be either global or context-specific. Global functions are available to use in all ValidationContexts while context-specific functions are only available for specific ValidationContexts


Creating New Business Rule Functions

In order to create a new Business Rule function, we must:

  • Create a new class that implements PlatformELFunction.

  • Create a JavaScript implementation of the function.

  • Provide a description.

Each step is covered in more detail below. As an example, this guide will demonstrate how to create a new function named "reverseString" that will reverse the characters within a string.

Create a new class that implements PlatformELFunction

PlatformELFunction is the interface for functions that can be executed within a Platform Expression Language expression - aka a Business Rule expression. We'll provide an implementation for this interface by following the steps below:

  1. Create a new class in your module. The example uses PTA (PlatformTestModule), so the class is placed in the "com.onenetwork.platformtestmodule.el.functions" package.

  2. Make your new class implement the PlatformELFunction interface in the "com.onenetwork.platform.tools.el" package.

We have to provide implementations for two abstract methods:

  • eval(List<Object>) - This is the java implementation of our new Business Rule function. The List argument contains the arguments passed into our function.

  • getName() - This should return the name of our new Business Rule function. Note that this name must be globally unique. If some other registered Business Rule function has the same name, an exception will be thrown when we try to register our new function.

The implementation for reversing a string looks like this:

ReverseString.java
package com.onenetwork.platformtestmodule.el.functions;
import java.util.List;
import com.onenetwork.platform.tools.el.PlatformELFunction;
public class ReverseString implements PlatformELFunction {
@Override
public Object eval(List<Object> args) {
if (args.size() != 1) {
throw new IllegalArgumentException("Must supply exactly 1 argument");
}
String str = args.get(0).toString();
String reversedStr = "";
for (int i = str.length() - 1; 0 <= i; --i) {
reversedStr += str.charAt(i);
}
return reversedStr;
}
@Override
public String getName() {
return "reverseString";
}
}


Create a JavaScript implementation

Business Rules functions may be run on the frontend as well as the backend, so we must provide a JavaScript implementation for every Business Rule function that we create.

The PlatformELFunction interface defines a method "getJSFunction()" that is expected to return the JavaScript implementation of our Business Rule function. This method has a default implementation that will attempt to locate and return the source of a JavaScript file with the same name as the class implementing the PlatformELFunction interface. In our example, the implementing class is named "ReverseString", so this method will look for a file named "ReverseString.js", and then return the contents. You can override the "getJSFunction()" method and provide some other implementation if you don't like the default behavior, but this will not be done within this example.

To create a JavaScript implementation, we must:

Create a new ".js" file with the same name as the class that implements PlatformELFunction. That class is named "ReverseString", so a new file named "ReverseString.js" has been created within the same directory:

images/download/attachments/144836500/image-2023-9-25_11-51-27-version-1-modificationdate-1695660689000-api-v2.png


As for the contents of the js file, we provide the JavaScript implementation in an anonymous function that accepts a single "values" argument - which is an array of arguments passed into the function. To make things easier, you can copy + paste this into your js file:

anonymous function
function(values) {
// Provide a javascript implementation within this function. Do not
// write code outside of this function.
}


The JavaScript implementation for "ReverseString.js" looks like this:

ReverseString.js
function(values) {
if (values.length != 1) {
throw new Error('Must supply exactly 1 argument');
}
if ((typeof values[0]) != 'string') {
throw new Error('The argument must be a string.')
}
var str = values[0];
var reversedString = "";
for (var i = str.length - 1; 0 <= i; --i) {
reversedString += str[i];
}
return reversedString;
}


Provide a description

When a Business Rule function is selected on the frontend, we can see a description in a panel below it:

images/download/attachments/144836500/image-2023-9-25_11-54-20-version-1-modificationdate-1695660862000-api-v2.png


Ideally each description will describe what the function does, the arguments that it expects, and provide an example invocation.

The descriptions are defined in the "message.properties" file of the module that you're working in. It's essential that our key matches this format: "platformel.description.<function-name>"

The <function-name> is the name of the function that is returned by "getName()" in your PlatformELFunction implementation. ReverseString.getName() returns "reverseString", so we'll use the key "platformel.description.reverseString".

Note that you can use HTML to format the description.

Our example description within message.properties looks like this:

message.properties
platformel.description.reverseString=Accepts a single string argument, and returns a string value with the same characters in reverse order.<br/><br/>Example: reverseString('testaroo') returns 'ooratset'

On the frontend, that description looks like this:

images/download/attachments/144836500/image-2023-9-25_11-56-32-version-1-modificationdate-1695660994000-api-v2.png


Register the new Business Rule function

All that remains to do is register the new function. ValidationService.java provides a few methods for registering new functions depending on whether we want them to be global (available across all ValidationContexts) or context-specific (available to only a particular ValidationContext).



registerPlatformELFunctions(List<PlatformELFunction>)
void registerPlatformELFunctions(List<PlatformELFunction> functions);

Functions registered with the above method will be available globally - across all ValidationContexts.




registerPlatformELFunctions(List<PlatformELFunction>, String)
void registerPlatformELFunctions(List<PlatformELFunction> functions, String context);

Functions registered with the above method will be available only within the ValidationContext whose name matches the "context" argument.




registerContext(ValidationContext, List<PlatformELFunction>)
void registerContext(ValidationContext validationContext, List<PlatformELFunction> functions);

This is a convenience method for registering both a ValidationContext and PlatformELFunctions simultaneously. Functions registered with this method will be available only within the passed ValidationContext.




We only need to register Business Rule functions once, so it is recommended to do so within the "ModuleContextListener.java" class of your module. Here is an example of what this may look like:

ModuleContextListener.java
public class ModuleContextListener implements com.onenetwork.platform.env.module.ModuleContextListener {
/**
* Initializes the ONE-App environment at web-app startup.
* path and the Taglib environment.
*
* @param app the ONE app.
*
*/
public void moduleInitialized(Module app) throws Exception {
// ...
registerPlatformELFunctions();
// ...
}
// ...
private void registerPlatformELFunctions() {
List<PlatformELFunction> functions = ListUtil.create(new ReverseString());
ValidationService validationService = Services.get(ValidationService.class);
validationService.registerPlatformELFunctions(functions, "TestGrandparent");
}
}


The new "reverseString" method is registered with the "TestGrandparent" ValidationContext, so it will only be available in rules using that context. You can see that's it's available in the image below because the TestGrandparent context is used:

images/download/attachments/144836500/image-2023-9-25_12-1-55-version-1-modificationdate-1695661317000-api-v2.png


At this point, you can see that it's not available in the next image because the TestParent context is used:

images/download/attachments/144836500/image-2023-9-25_12-2-32-version-1-modificationdate-1695661354000-api-v2.png