Skip to Content
Technical Articles
Author's profile photo Lionel Hu

Try use JavaScript scripting instead of Groovy scripting in your CPI project

Dear CPI folks,

We used to write Groovy scripting in our CPI integration projects. But if you are a big fan of JavaScript like me, why not to use JavaScript to write the script in your next CPi integration project?

Unfortunately by searching on SAP community, it is very hard to find any resource on how to do that. With some research on this topic, I managed to test successfully with JS script powerned iFlow. That’s the reason why I want to share my findings in the community.

Background

Based on SAP Help Portal document: https://help.sap.com/docs/cloud-integration/sap-cloud-integration/define-local-script-step. The scripting engine that was used in CPI runtime environment is so called ‘Rhino‘.

JavaScript Engine (Rhino)

1.7 R4

It is very easy to find the home of this Rhino engine on the Internet: https://github.com/mozilla/rhino/. The README document is showing very clear information that the Rhino is “an implementation of JavaScript in Java“.

The API document is here: https://javadoc.io/doc/org.mozilla/rhino/1.7R4/index.html

Local Test Environment

It is always joyful that we can play around with scripting locally before using it officially in our project.

To prepare a playground on your local environment. Download the jar file from https://mvnrepository.com/artifact/org.mozilla/rhino/1.7R4, put it in somewhere on your PC. And then use the command line “java -jar rhino-1.7R4.jar -debug -version 180” to start the shell to test.

Rhino%20Shell%20in%20Command%20Line

Rhino Shell in Command Line

I still haven’t figure out what is the difference between these possibile version no: -version 100|110|120|130|140|150|160|170|180. But from the screenshot above you can see, “help()” is very useful to get some idea on how to setup the shell environment and version() will give you exactly what you set for the version.

This is very similar to the Node.JS shell that can be used to test some js function/class before adding to your productive js file.

To test the local script file, you can use “-f” parameter like following:

java -jar rhino-1.7R4.jar -f <filename of your rhino js file>

CPI iFlow Implementation:

Now let’s implement some simple CPI scripting features in the iFlow:

When you select “JavaScript” as the scripting language in CPI iFlow design, you will see the template that SAP has prepared for you, so you don’t have to build the wheel again.

overview%20of%20the%20iFlow%20design

overview of the iFlow design

In my test iFlow design,

  • The iFlow will be triggered only once by Timer so that the test can be triggered/managed by deployment on demand.
  • The XML payload was generated by a SFAPI (SOAP) query to the Compound Employee entity of sandbox SFSF tenant.
  • I chained two scripts (JS and Groovy) in order to get the logging message to compare the results.
  • The XML Modifier is used to remove the XML head from the payload so that your JS script can work without any issue.

Note:

I tried to use Regular Expression in JS to replace(remove) the XML head but unfortunately that was failed with the error “The choice of Java method java.lang.String.replace matching JavaScript argument types (function,string) is ambiguous; candidate methods are: class java.lang.String replace(char,char)”). I guess that was caused by the supportability of the RegEx in Rhino. As long as the XML modifier can do the trick, I don’t care about it anymore.

payload = payload.replace(/<\?xml[^>]*\?>/, "");

The script itself is very straight forward. The only thing that I want to mention is that the Rhino JS engine supports the ECMAScript for XML (E4X) which is an extension to provide the native support of XML in Rhino.

So you can easily access the XML payload with single line of code, but please bear in mind if you use “typeof parsedPayload” to check the object type, it is “xml” instead of “object“.

const parsedPayload = new XML(body);

you can get more details about this topic from here: https://svn.wso2.org/repos/wso2/tags/carbon/0.1alpha/mashup/java/xdocs/e4xquickstart.html#modifying

Source Code of my script:

/* Refer the link below to learn more about the use cases of script.
https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/148851bf8192412cba1f9d2c17f4bd25.html

If you want to know more about the SCRIPT APIs, refer the link below
https://help.sap.com/doc/a56f52e1a58e4e2bac7f7adbf45b2e26/Cloud/en-US/index.html */
importClass(com.sap.gateway.ip.core.customdev.util.Message);

function processData(message) {
    //Body
    var body = message.getBody(java.lang.String);
    const payload = new XML(body);
    
    const counter = payload.CompoundEmployee.length();
    
    const firstElement = payload.CompoundEmployee[0];

    const messageLog = messageLogFactory.getMessageLog(message);
    if(messageLog != null){
        messageLog.setStringProperty("JS Logger", "Logger")
        messageLog.addAttachmentAsString("JavaScript MessageCounter", counter, "text/plain");
        messageLog.addAttachmentAsString("JavaScript First CompoundEmployee", firstElement , "text/plain");
     }
    
    return message;
}

After deployment of the iFlow, I got the successfully result as expected. The total number of Compound Employee records and the first employee payload appear in the attachment.

Counter:

First Employee Payload:

 

Simple like that !

With the power of JavaScript native JSON support, you may get more from the JSON based integration scenarios with JSON.parse and JSON.stringify.

I hope this blog can inspire you on using Java Script as the scripting language in your next project. Enjoy it. 🙂

Thank you

Best Regards
Lionel

Assigned Tags

      6 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Dhruvin Mehta
      Dhruvin Mehta

      This is cool! 🙂 Will try it. Is it possible for CPI on Cloud Foundry?

      Author's profile photo Morten Wittrock
      Morten Wittrock

      Yes; JavaScript is supported both in Neo and Cloud Foundry.

      Have fun with Cloud Integration!

      Regards,

      Morten

      Author's profile photo Lionel Hu
      Lionel Hu
      Blog Post Author

      Hi Dhruvin,

      Yes, it works the same way as Neo. I did a test in my CF trial account and it runs fine without any problem.

      To make it simple, I fetch data from Northwind and generate a csv with ProductID and ProductName only.

      Author's profile photo VICTOR GONZALEZ
      VICTOR GONZALEZ

      Thanks Lionel, your blog is very useful.

      Do you know if it is posible import libreries, for example from https://jwt.io/#libraries-io, for token management?

       

      Thanks!

      Victor

      Author's profile photo Lionel Hu
      Lionel Hu
      Blog Post Author

      Hi Victor,

      I'm afraid that it is impossible. As Rhino is only a JS engine which is used to run JS script based on Java environment. It did not implement the full feature of modularization and other advanced techniques from JS world.

      However it still can use the library class from Java just like Groovy. e.g. when you create the skeleton JS script file, it already includes these two imports:

      importClass(com.sap.gateway.ip.core.customdev.util.Message);
      importClass(java.util.HashMap);

      Unfortunately I'm not a Java guy so I have no idea how these importClass work.

      In Rhino command line mode, there're some modularization functions like following, but I haven't test them yet. I will do some test once I have some free time in the next few weeks.

      defineClass(className) Define an extension using the Java class
                             named with the string argument.
                             Uses ScriptableObject.defineClass().
      load(["foo.js", ...])  Load JavaScript source files named by
                             string arguments.
      loadClass(className)   Load a class named by a string argument.
                             The class must be a script compiled to a
                             class file.

      Thank you

      Best Regards
      Lionel

      Author's profile photo Otto Frost
      Otto Frost

      Why can not Nashorn be used as script engine? Nashorn is included in sap java 8 so it would be trivial for sap to enable it.

      We use alot of nashorn javascript in sap po and we do not want to backport from nashorn to rhino.