Saturday, August 8, 2015

Useful XPath expressions

The following WSO2 ESB proxy service creates a sample XML payload and logs some useful XPath expressions


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse" name="xpathSample" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
   <target>
      <inSequence>
         <payloadFactory media-type="xml">
            <format>
               <students xmlns="">
                  <student student-id="001">
                     <name first="tom" last="hanks" />
                     <age>30</age>
                     <scores>
                        <subject id="sub1">70</subject>
                        <subject id="sub2">80</subject>
                     </scores>
                  </student>
                  <student student-id="002">
                     <name first="tom" last="cruise" />
                     <age>25</age>
                     <scores>
                        <subject id="sub1">60</subject>
                        <subject id="sub2">75</subject>
                     </scores>
                  </student>
                  <student student-id="003">
                     <name first="jessica" last="chastain" />
                     <age>24</age>
                     <scores>
                        <subject id="sub1">75</subject>
                        <subject id="sub2">70</subject>
                     </scores>
                  </student>
               </students>
            </format>
            <args />
         </payloadFactory>
         <log level="custom" separator="&#xA;">
            <property name="student 001's first name" expression="//student[@student-id='001']/name/@first" />
            <property name="student 001's last name" expression="//student[@student-id='001']/name/@last" />
            <property name="student 001's age" expression="//student[@student-id='001']/age" />
            <property name="student 001's sub1 score" expression="//student[@student-id='001']/scores/subject[@id='sub1']/text()" />
            <property name="student 001's sub2 score" expression="//student[@student-id='001']/scores/subject[@id='sub2']/text()" />
            <property name="sub2 score for students whose first name is 'tom'" expression="//student[name[@first='tom']]/scores/subject[@id='sub2']" />
            <property name="sub2 score for students whose first name is 'tom' [with XPath2.0 function]" expression="string-join(//student[name[@first='tom']]/scores/subject[@id='sub2']/text(), ', ')" />
            <property name="students' last name whose age is lesser than '30'" expression="string-join(//student[age/text() &lt; 30]/name/@last, ', ')" />
            <property name="students' last name whose age is greater than '25' OR sub1 score is greater than or equal to '70'" expression="string-join(//student[age/text() /text() &gt; 25 or scores/subject[@id='sub1'] &gt;= 70]/name/@last, ', ')" />
         </log>
         <respond />
      </inSequence>
   </target>
   <description />
</proxy>

once the proxy is invoked using tryit or soapUI you can see the following logs in the terminal
student 001's first name = tom
student 001's last name = hanks
student 001's age = 30
student 001's sub1 score = 70
student 001's sub2 score = 80
sub2 score for students whose first name is 'tom' = 8075
sub2 score for students whose first name is 'tom' [with XPath2.0 function] = 80, 75
students' last name whose age is lesser than '30' = cruise, chastain
students' last name whose age is greater than '25' OR sub1 score is greater than or equal to 70 = hanks, chastain


Please note that, in Line 43, 44 and 45 I am using stirng-join(..) function to concat the results with comma. This function is only supported in XPath 2.0 version. But WSO2 ESB supports XPath 1.0 by default. To enable XPath 2.0 support in WSO2 ESB following line should be uncommented in CARON_HOME/repository/conf/synapse.properties
synapse.xpath.dom.failover.enabled=true




Tuesday, July 21, 2015

How to get WSO2 ESB iterate mediator's iteration count

WSO2 ESB's iterate mediator is very useful to implement the Splitter Enterprise Integration Pattern.
It splits the message based on a given expression and process separately.

This sample shows how to get the iteration count.

Sample request

<symbols>
   <symbol>WSO2</symbol>
   <symbol>MSFT</symbol>
   <symbol>IBM</symbol>
   <symbol>ADBE</symbol>
   <symbol>AAPL</symbol>
   <symbol>ORCL</symbol>
   <symbol>RHT</symbol>
   <symbol>FB</symbol>
   <symbol>TWTR</symbol>
   <symbol>LNKD</symbol>
</symbols>

Sample proxy
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="count_iterate"
       transports="https,http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <inSequence>
         <property name="it_count" value="0" scope="operation"/>
         <iterate expression="//symbols/symbol" sequential="true">
            <target>
               <sequence>
                  <property name="synapse_it_count" expression="get-property('operation', 'it_count')"/>
                  <script language="js">var cnt_str = mc.getProperty('synapse_it_count');
     var cnt = parseInt(cnt_str);
     cnt++;
     mc.setProperty('synapse_it_count', cnt.toString());</script>
                  <property name="it_count" expression="get-property('synapse_it_count')" scope="operation"/>
                  <aggregate>
                     <completeCondition>
                        <messageCount min="-1" max="-1"/>
                     </completeCondition>
                     <onComplete expression="//symbol">
                        <log level="custom">
                           <property name="number of symbols" expression="get-property('operation','it_count')"/>
                        </log>
                        <respond/>
                     </onComplete>
                  </aggregate>
               </sequence>
            </target>
         </iterate>
      </inSequence>
   </target>
   <description/>
</proxy>                               

Idea behind this sample is, using the 'operation' scope property[line 10]to increment the count in each iteration. The operation scope property cannot be read inside the script mediator (it supports only the synapse scope property) so introducing a synapse scope property[line 14] to be used inside the script mediator. After script mediator the value is assigned again to the operation scope property [line 19].
If we didn't use the operation scope property the value will not be remain in the next iteration. Also please note that the iterate mediator is in the sequential mode.

Getting the count like this method is useful when we have to map two different array based on its indexes. But please note if you want to only get the number of nodes in the message you can use the XPath function 'count' as follows

<property name="total_symbols" expression="count(//symbol)"/>


UPDATE on 28/09/2018:
The proxy can be simplified as follows by using the XPATH's number() function. Instead of using the script mediator to increment the count
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="count_iterate"
       startOnLoad="true"
       statistics="disable"
       trace="disable"
       transports="https,http">
   <target>
      <inSequence>
         <property name="it_count" scope="operation" value="0"/>
         <iterate expression="//symbols/symbol" sequential="true">
            <target>
               <sequence>
                  <property expression="number(get-property('operation','it_count') +1)"
                            name="it_count"
                            scope="operation"/>
                  <aggregate>
                     <completeCondition>
                        <messageCount max="-1" min="-1"/>
                     </completeCondition>
                     <onComplete expression="//symbol">
                        <log level="custom">
                           <property expression="get-property('operation','it_count')"
                                     name="number of symbols"/>
                        </log>
                        <respond/>
                     </onComplete>
                  </aggregate>
               </sequence>
            </target>
         </iterate>
      </inSequence>
   </target>
   <description/>
</proxy> 

To get rid of the decimal place in the result, we can use the string() and round() XPATH functions as follows

<property expression="string(round(get-property('operation','it_count')))" name="number of symbols"/>

Sunday, June 14, 2015

WSO2 ESB as a Runtime Environment for WSO2 Developer Studio



To configure the WSO2 ESB as a runtime environment in the developer studio,
Go to
Window --> Preferences
Server --> Runtime Environment  [Add..]
WSO2 --> WSO2 Carbon 4.2 based server


Configure the CARBON_HOME as your ESB HOME directory 


Friday, March 27, 2015

Calling an admin service with Signed JWT using Jaggery

This sample shows how to call admin services using Signed JWT from a Jaggery application.
The advantage of using Signed JWT header in the admin service call is, we do not have to hard code the user name or the password. (Though, In this sample I have hard coded the user name since this is a single page sample) This is very helpful when tenants are logging into the application. I have extracted the token generation logic. Please find the source code here. By building the source you can get the signed-jwt-header-1.0.0.jar
I'll be calling ESB's SequenceAdminService as an example. (My ESB is running in port offset 2)
ESB to authenticate the JWT, add the following jars into ESB_HOME/repository/components/dropins/ nimbus.jarsignedjwt-authenticator.jar

The quick way to setup the environment is creating a Jaggery application in wso2 application server.
Download the application server and unzip it in your installs location. And add the nimbus.jar into wso2as-<version>/repository/components/dropins and add the custom signed-jwt-header-1.0.0.jar into wso2as-<version>/repository/components/lib/
Create a directory in wso2as-<version>/repository/deployment/server/jaggeryapps/
For example admin-call, which is our project name. Inside the directory create the following index.jag


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%
var ws = require("ws");
var req = new ws.WSRequest();
var options = new Array();
var log = new Log();

var carbon = require('carbon');
var username = "admin";
var adminCallUtil = Packages.com.se.sample.AdminCallUtil;

var fullName = username + "@" + carbon.server.tenantDomain();
var authHeader = adminCallUtil.getAuthHeader(fullName);

options["HTTPHeaders"] = [{name: "Authorization", value: String(authHeader)}];

options.useSOAP = 1.2;
options.action = "urn:getSequence";

var payload = '<xsd:getSequence xmlns:xsd="http://org.apache.synapse/xsd">'
        + '<xsd:sequenceName>main</xsd:sequenceName>'
        + '</xsd:getSequence>';

var result;
try {
    req.open(options, "https://localhost:9445/services/SequenceAdminService", false);
    req.send(payload);
    result = req.responseE4X;
} catch (e) {
    log.error(e.toString());
}
print('<textarea rows="20" cols="100">');
print(result);
print('</textarea>');
%>

Start the application server by running 'sh wso2as-<version>/bin/wso2server.sh'
Go to the management console https://localhost:9443/carbon/
In the  application list view you'll see your project name as a jaggery application click on the Go To URL. You'll see the main sequence configuration as the output

Monday, February 9, 2015

Add, Modify resources in WSO2 Governance Registry using Jaggery

The Following piece of code shows how to add a resource(file) to wso2 governance registry and Modify its content.
The quickest (I guess)  way of setting up the environment is creating a jaggery app in wso2 application server.
Download the application server and unzip it in your installs location.
Create a directory in wso2as-<version>/repository/deployment/server/jaggeryapps/
For example reg-test, which is our project name. Inside the directory create the following index.jag

Start the application server by running 'sh wso2as-<version>/bin/wso2server.sh'
Go to the management console https://localhost:9443/carbon/
In the  application list view you'll see your project name as a jaggery application click on the Go To URL.
On the first time you'll get printed an exception and a resource file will be created under /_system/governance/sen/