Script Mediator with Nashorn Support
From WSO2 EI 6.2.0 onwards, the Script Mediator of the ESB profile uses Nashorn to execute JavaScripts in addition to its default Rhino engine. You can perform all Script Mediator functionalities that the Rhino engine provides, with the Nashorn engine as well.
You need to install JDK 8 version update 112 or later to use Nashorn support, If not, you get the following exception when you call the setPayloadJSON()
method: java.lang.ClassCastException:
jdk.nashorn.internal.runtime.Undefined cannot be cast to java.lang.String
For more information, see the bug that causes this, which is fixed in JDK 8 version update 112 or later.
The Rhino engine uses E4X XML objects to handle XML payloads. However, E4X is deprecated in the Nashorn engine. Instead, Nashorn supports the AXIOM XML parser to parse XML streams. You can use the getParsedOMElement(InputStream stream)
method to parse an XML stream into an OMElement, and the getXpathResult(String expression)
method to retrieve the AXIOMXPath using an Xpath query expression to access and modify it.
The XPath equivalents for a few common XML navigation operations are as follows.
Operation | XPath expression | E4X equivalent |
---|---|---|
Select all the children of an element | element/* | element.* |
Select all the attributes of element | element/@* | element.@* |
Select all the descendants (children, grandchildren, etc.) of an element | element//descendent | element..descendent |
Select the parent of an element | .. or parent::element | element.parent() |
Select a specific child (e.g. foo:bar ) of an element, where 'foo' is the prefix of a declared namespace |
|
|
Return the full name (including prefixes if available) of an element | name(element) | element.name() |
Return the local name of an element | local-name(element) | element.localName() |
Return the namespace URI of an element (if available) | namespace-uri(element) | element.namespace() |
Return the collection of namespaces.
| element/namespace::* | element.inScopeNamespaces() |
Return the processing instructions of the specified children of an element (returns all if omitted) | element/processing-instructions(name) | element.processingInstructions(name) |
Return the concatenated text nodes and descendants of an element | string(element) | stringValue(element); |
You can create a Script mediator with Nashorn support using one of the following methods.
Store the JavaScript program statements in a separate file, and refer it via a Local or Remote Registry entry.
Embed the JavaScript program statements inline within the Synapse configuration.
You can invoke a function within the corresponding script using the Script Mediator. Hence, you can predefine the Synapse configuration in a script variable named mc
, and access it via these functions. The mc
variable represents an implementation of the NashornScriptMessageContext.java
MessageContext. It is an implementation of the ScriptMessageContext
interface, which contains the following methods. You can access these methods within the script (e.g., mc.methodName
).
Method name | Description | If a value is returned or not |
---|---|---|
getParsedOMElement(stream) | Converts the input stream of an XML String or document into an OMElement. This is useful to traverse the XML document. | Yes |
getXpathResult(expression) | Converts a String, which represents an Xpath expression into an AXIOM Xpath. This is useful to traverse the XML document. | Yes |
addHeader(mustUnderstand, content) | Adds a new SOAP header to the message. Content can be XML, String, parsed w3c.dom.Document, or an OMElement returned by the getParsedOMElement(stream) method. | No |
getEnvelopeXML() | Retrieves the XML representation of the complete SOAP envelope. | Yes |
getPayloadJSON() | Retrieves the JSON representation of a SOAP Body payload. | Yes |
getPayloadXML() | Retrieves the XML representation of a SOAP Body payload. This method Returns a OMElement so the user can directly access elements using Xpath. | Yes |
getProperty(name) | Retrieves a specified property from the current message context. | Yes |
setPayloadJSON(payload) | Sets the JSON representation of a payload obtained via the getPayloadJSON() method in the current message context. | No |
setPayloadXML(payload) | Sets the SOAP body payload from the XML. Payload can be XML, String, parsed w3c.dom.Document or an OMElement returned by the getParsedOMElement(stream) method. | No |
setProperty(key, value) | Replaces the existing property values a property in the current message context. | No |
The Script Mediator has the flexibility of a class Mediator, with access to the Synapse Message Context and Synapse Environment APIs. For both types of script mediator definitions, the Message Context passed into the script has additional methods over the standard Synapse Message Context, to enable working with natural XML to JavaScript.
The Script mediator is a content aware mediator.
Syntax
Click on the relevant tab to view the syntax for a script mediator using an Inline script, or a script mediator using a script of the Registry.
Configuration
Click on the relevant tab to view the required UI configuration depending on the script type you have selected. The available script types are as follows:
- Inline: If this script type is selected, the script is specified inline.
- Registry Key: If this script type is selected, a script which is already saved in the registry will be referred using a key.
Examples
Assume the below SOAP envelope for the following examples:
<?xml version='1.0' encoding='utf-8'?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header> <AuthenticationInfo xmlns="http://www.x" soapenv:mustUnderstand="0"> <userName>”wso2”</userName> <password>”wso2”</password> </AuthenticationInfo> </soapenv:Header> <soapenv:Body> <company> <staff id="1001"> <firstname>”yong”</firstname> <lastname>”mook kim”</lastname> <nickname>”mkyong”</nickname> <salary>100000</salary> </staff> <staff id="2001"> <firstname> “low”</firstname> <lastname>”yin fong”</lastname> <nickname>”fong fong”</nickname> <salary>200000</salary> </staff> </company> </soapenv:Body> </soapenv:Envelope>
Example 1 - Using an inline script
The following configuration is an example of using a Nashorn JavaScript script inline in the Script Mediator. In this script, you get the message payload in XML and you use an Xpath query to access the elements of it.
<script language="nashornJs"><![CDATA[var symbol = mc.getPayloadXML(); var expression = "//firstname"; var xpath = mc.getXpathResult(expression); var c1l = xpath.selectNodes(symbol); var first_name = c1l.get(0).getText(); ]]></script>
Example 2 - Using a script saved in the registry
In the following example, the script is loaded from the Registry using the key repository/conf/sample/resources/script/test.js
.
<script language="nashornJs" key="repository/conf/sample/resources/script/test.js" function="testFunction"/>
The script language="nashornJs"
property indicates that the invoked function should be in the Nashorn JavaScript language. You need to save the function named testFunction
, which is invoked in the above example as a resource in the Registry. Following is an example for the script of the function.
function testFunction(mc) { var symbol = mc.getPayloadXML(); var expression = "//firstname"; var xpath = mc.getXpathResult(expression); var c1l = xpath.selectNodes(symbol); var first_name = c1l.get(0).getText(); }
Examples for methods
The following Script Mediator configuration examples show how you can include some of the commonly used methods in the invoked script.
Methods | SOAP envelope | Sample Script Mediator configuration |
---|---|---|
| <?xml version='1.0' encoding='utf-8'?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header> <AuthenticationInfo xmlns="http://www.x" soapenv:mustUnderstand="0"> <userName>”wso2”</userName> <password>”wso2”</password> </AuthenticationInfo> </soapenv:Header> <soapenv:Body> <company> <staff id="1001"> <firstname>”yong”</firstname> <lastname>”mook kim”</lastname> <nickname>”mkyong”</nickname> <salary>100000</salary> </staff> <staff id="2001"> <firstname> “low”</firstname> <lastname>”yin fong”</lastname> <nickname>”fong fong”</nickname> <salary>200000</salary> </staff> </company> </soapenv:Body> </soapenv:Envelope> | <script language="nashornJs"><![CDATA[ var symbol = mc.getPayloadXML(); var expression = "//firstname"; var xpath = mc.getXpathResult(expression); var nameList = xpath.selectNodes(symbol); var name = nameList.get(0).getText(); mc.setPayloadXML(symbol); //here we are setting payload by a parsed xml document or this coud be done by passing xml string as well var password = "wso2"; var username = "wso2"; var headerXml = "<AuthenticationInfo xmlns=\"http://www" + ".w3.org/1999/xhtml\"><userName>" + username + "</userName><password>"+ password + "</password" + "></AuthenticationInfo>"; mc.addHeader(false, headerXml ); var envelope = mc.getEnvelopeXML(); expression = "//nickname"; stream = new byteArrayStream(envelope.getBytes()); var docEnvelope = mc.getParsedOMElement(stream); xpath = mc.getXpathResult(expression); var nickNameList = xpath.selectNodes(docEnvelope); var nickname = nickNameList.get(0).getText(); ]]></script> |
| <?xml version='1.0' encoding='utf-8'?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <jsonObject> <appointmentNo>55</appointmentNo> <doctorName>thomascollins</doctorName> <patient>JohnDoe</patient> <actualFee>7000.0</actualFee> <discount>0</discount> <discounted>7000.0</discounted> <paymentID>c3b7cab3-8e22-4319-a43f-b1bef3de2693</paymentID> <status>Settled</status> </jsonObject> </soapenv:Body> </soapenv:Envelope> | <script language="nashornJs"><![CDATA[ var doctor = { name : "x", fee : 200 }; mc.setProperty("scriptObject", doctor); var payload = mc.getPayloadJSON(); var results = payload.actualFee; doctor.fee = results; mc.setPayloadJSON(doctor); ]]></script> |