AnyLang: A Lightweight, Multi-Script Solution
This article illustrates how a low–cost, lightweight solution helps here with the flexibility to create rules in a programming language of one’s choice.
Join the DZone community and get the full member experience.
Join For FreeThough we recommend going through the previous article by the authors to understand the motivation behind this one, let us brief it here. Business rules and managing them are crucial in enterprise applications. A business rule may be perceived as an action taken by a decision and mostly are IF-ELSE branches that describe how the business must function. While a number of free and solutions, such as JRule, IBM Drools, Blaze (FICO), Oracle Rules SDK etc. already exist with highly sophisticated features, often their licensing and maintenance become a lingering burden, moreover when the product is underutilized. Nowadays, thanks to the growing popularity of microservices, development teams are often small, and a member might wear multiple hats. Writing and maintaining rules and rule engines, therefore, may be carried out by different members and teams.
Business Rule Engines come with their respective learning curve, and it’s difficult to always have a person with the right skill set in the team solely for managing a BRMS. To mitigate this gap, we need the flexibility to use different programming languages, at least the common ones. This article illustrates how a low–cost, lightweight solution helps here with the flexibility to create rules in a programming language of one’s choice (currently, support for Java, JavsScript, and Pyhton is available). It also helps abstract the storage of rules, which can be literally anywhere — from local file systems to cloud storage, databases, CMS, etc.
For open-source contributors, it offers the opportunity to create support for newer programming languages and accommodate newer storage and security strategies. At the point of composing the article, support for Java, JavaScript, and Python are available. So, it can be used by backend, frontend, and Data/ Analytics engineers seamlessly. For storage, support for Local File Storage, Non-Reactive Streams, JDBC/JPA for SQL+ NoSQL databases, cloud services such as AWS S3 bucket, Azure Blob and FS are supported until now.
1. Executing JavaScript Functions From Java
Though ScriptEngines have been there for quite some time, they are relatively less commonplace among developers. This section attempts to provide a short description of how a JavaScript function can be invoked programmatically in Java. While we talk about ScriptEngines, we shall make it abridged; making examples adhere to Java SE 1.8. To explore more on this topic, materials available on the Internet may be consulted. Assume that we have the following JavaScript function, someJSAddFunction
Stored in a file a.js on the local storage, the function needs to be executed via a Java program. The code snippet below illustrates how this may be achieved:
/* A simple function which takes an array of numbers and returns their sum. */
function someJSAddFunction (arr){
var sum=0;
for(var x in arr){
print(x);
sum=sum+arr[x];
}
return sum;
}
public static void main(String[] args) throws FileNotFoundException, ScriptException, NoSuchMethodException {
ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("nashorn"); // Get // an instance of ScriptEngine
Object eval = scriptEngine.eval(
new FileReader( new File("path/subPath/a.js") )
); // read JavaScript from file
Invocable invocable=(Invocable)scriptEngine;
Object r = invocable.invokeFunction("someJSAddFunction", new int[] {1,2,3,4,5}); // Invoke //the method by method name, passing argument
System.out.println("Result of JS execution is "+r);
}
Stored in a file a.js on the local storage, the function needs to be executed via a Java program. The code snippet below illustrates how the above may be achieved.
The below output is obtained:
To learn and explore more, you may refer to this article or any other online or offline material.
2. “Not Just Java, We Need JavaScript Functions as Rule”: The Motivation Behind
Looking at the teams we have been working with in recent years, we felt that fresh developers were biased toward and probably more comfortable with JavaScript and JavaScript frameworks like Angular, Node, React, etc., rather than Java. Keeping aside JavaScript vs. Java as a topic of perpetual debate, our key takeaway is that people who start as developers and shift to become Business Analysts or execute domain-related roles are more comfortable with JavaScript; at least they seem to retain some of the developers’ traits. Having seen the efficacy of our lightweight rule engine earlier, where we used Java method, functions, and Lambda snippets to define rules, we were intrigued to embrace JavaScript, too, in the solution.
function getDiscount(customerDto){
var age= customerDto.age;
if(age < 12) return 0.4; // 40% discount below 12 years
if(age < 16) return 0.25 // 25% discount for 12 years or above but below 16 years
return 0.15; // for 16 or above, 15% discount
}
2.1 Script Loading
As of the time of writing this article, we support the sources shown in this code snippet to load scripts. Since the loading of scripts is most likely to be implantation-specific, we provide the following factory approach to get the appropriate loader shown in [Fig. 4].
If we are to add support for a new source, say, Azure storage, GitHub, or JIRA, we need to:
- Declare the source type as the enum anylang.scriptloader.ScriptSource
- We must create our implementation of the interface anylang.scriptloader.ScriptLoader
- Provide implantation for the method below
As what we believe would be the simplest example, the code below is for loading the script from the local file system.
The script hierarchy looks like this:
However, this section covers only JavaScript and the next section will elaborately show how support for Python is added. This will be a quick reference guide for the developer community wishing to augment it and introduce newer features and support for other programming languages.
2.2 Execution of Script
Opinions expressed by DZone contributors are their own.
Comments