Monday, November 16, 2015

How to use Aggregate Mediator in WSO2 ESB

Aggregate Mediator merges the incoming messages into one message and sends it as a response message.  Aggregate Mediator is required when we use Iterator or Clone Mediator. It keeps collecting the incoming message until completion condition is satisfied. It invokes On Complete sequence once aggregation is completed. You can get the merge message by using XPATH expression.


To use Aggregate Mediator, you can follow 'http://shriwithjava.blogspot.co.nz/2015/11/how-to-use-iterator-mediator-in-wso2-esb.html' blog test case. In this blog I have also put the coding content for Aggregation and Iterator Mediator.

Aggregate mediator is can be added inside the Advance list (After editing the sequence in which Aggregate mediator needs to be defined).


Once you click on the Aggregate mediator you will get the below screen in which you need to pass some parameter.

  • Aggregation ID: However this is the optional parameter but used when Iterator/Clone split messages needs to be aggregated. This Aggregation id must be the same as we define in the Iterator/Clone mediator.
  • Aggregation Expression: An XPATH expression which specify that which message needs to be aggregated.
  • Completion Timeout: We can define the completion timeout; once this timeout is completed Aggregation is completed but this also check the condition of Completion-Max Message. If ‘Completion-Max Message’ is reached to its max value then it does not check the completion time even if there is some time left.
  • Completion Max Message: The number of message it can hold to aggregate once defined value is reached aggregation is completed.
  • Completion Min-Message: This is the minimum message it has to hold for aggregation, it also checks if Completion timeout condition, Aggregation is completed once time is finished even it did not receive even a single message.
  • Correlation Expression: This is an XPATH expression which provides the basis on which response messages should be selected for aggregation.
  • Enclosing Element Property: This parameter is used to accumulate the aggregated messages inside a single property. The name of the relevant property is entered in this field.
  • On Complete: This defines that which sequence has to run once aggregation is completed you can define from the registry and also you can define a new mediator (for example send mediator to send message) as children to send message.

Synapse Code:

<sequence name="ManageManagerService_IN">
        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/" name="Id" expression="//man:Id/text()"/>
        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/" name="Name" expression="//man:Name/text()"/>
        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/" name="Address" expression="//man:Address/text()"/>
        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/" name="NoOfDepartment" expression="count(//man:Departments/man:DepartmentDetails)"/>
        <iterate xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/" id="ITR_AGG" expression="//man:Departments/man:DepartmentDetails">
            <target>
                <sequence>
                    <property name="DepartmentName" expression="//man:DepartmentName/text()"/>
                    <property name="NoOfPeople" expression="//man:NoOfPeople/text()"/>
                    <property name="OfficeLocation" expression="//man:OfficeLocation/text()"/>
                    <script language="js" key="ManageManagerServiceScript" function="ManageManagerDetailsServiceRequest"/>
                    <send>
                        <endpoint key="DSS_ManageManagerDetails_EPR"/>
                    </send>
                </sequence>
            </target>
        </iterate>
    </sequence>
                                  <sequence name="ManageManagerService_OUT">
        <log level="full"/>
        <aggregate id="ITR_AGG">
            <completeCondition>
                <messageCount min="-1" max="-1"/>
            </completeCondition>
            <onComplete xmlns:s12="http://www.w3.org/2003/05/soap-envelope" xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/" expression="s11:Body/child::*[position()=1] | s12:Body/child::*[position()=1]">
                <property xmlns:man="http://shriwithjava.blogspot.co.nz/managemanagerdetails" name="ResultCode" expression="//man:ManageManagerDetailsResponse/man:ResultCode/text()"/>
                <property xmlns:man="http://shriwithjava.blogspot.co.nz/managemanagerdetails" name="ResultDescription" expression="//man:ManageManagerDetailsResponse/man:ResultDescription/text()"/>
                <filter xpath="contains(get-property('ResultCode'),'1')">
                    <then>
                        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managemanagerdetails" name="RESCULT_CODE" expression="//man:ManageManagerDetailsResponse[man:ResultCode='1'][1]/man:ResultCode/text()"/>
                        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managemanagerdetails" name="RESCULT_DESC" expression="//man:ManageManagerDetailsResponse[man:ResultCode='1'][1]/man:ResultDescription/text()"/>
                    </then>
                    <else>
                        <property name="RESCULT_CODE" value="0"/>
                        <property name="RESCULT_DESC" value="Success"/>
                    </else>
                </filter>
                <payloadFactory>
                    <format>
                        <man:ManagerDetailsResponse xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/">
                            <man:ResponseCode>$1</man:ResponseCode>
                            <man:ResponseDescription>$2</man:ResponseDescription>
                        </man:ManagerDetailsResponse>
                    </format>
                    <args>
                        <arg expression="get-property('RESCULT_CODE')"/>
                        <arg expression="get-property('RESCULT_DESC')"/>
                    </args>
                </payloadFactory>
                <property name="RESPONSE" value="true"/>
                <header name="To" action="remove"/>
                <log level="full"/>
                <send/>
                <drop/>
            </onComplete>
        </aggregate>
    </sequence>

For more detail regarding above test case and Synapse code please visit my previous blog http://shriwithjava.blogspot.co.nz/2015/11/how-to-use-iterator-mediator-in-wso2-esb.html.

How to use Iterator Mediate in WSO2 ESB

Iterator mediator is used when a message needs to be split into multiple messages by finding the XPATH expression. A new message is created in each matching elements.

Test Case:

We have a Manager Management portal in which we have to keep records like how many departments are taken care or come in one manager. For example one manager can handle more than 1 or 2 department like IT and CS department.

We have created a request in which we can submit the manager records with his owned departments.

Use of Iterator in this test case:


When we are submitting the department records, department may be more than one so we will use Iterator to create new messages everything for each department and save it into our database.

Database:


We have created 3 tables which contain Department mapping, department details and manager details.

  • Department
  • department_details
  • manager_detail

Now we have to create a stored procedure which will be called from the DSS to store the manager details with their department.

Stored Procedure:

-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `MANAGE_MANAGER_DETAIL`(
IN MANAGER_ID VARCHAR(50),
IN MANAGER_NAME VARCHAR(50),
IN ADDRESS VARCHAR(50),
IN DEPARTMENT_NAME VARCHAR(50),
IN NO_OF_PEOPLE VARCHAR(50),
IN OFFICE_LOCATION VARCHAR(50) ,
OUT RESULT_CODE VARCHAR(10),
OUT RESULT_DESC VARCHAR(50)
)
BEGIN
declare DEPARTMENT_ID INT;

SELECT DEPARTMENT_ID_N INTO DEPARTMENT_ID FROM DEPARTMENT WHERE DEPARTMENT_NAME_V=DEPARTMENT_NAME;

IF DEPARTMENT_ID IS NOT NULL THEN
INSERT INTO MANAGER_DETAIL VALUES (MANAGER_ID, MANAGER_NAME, ADDRESS, DEPARTMENT_ID);
INSERT INTO DEPARTMENT_DETAILS VALUES (DEPARTMENT_NAME, NO_OF_PEOPLE, OFFICE_LOCATION);
SET RESULT_CODE = '0';
SET RESULT_DESC='SUCCESS';
elseif DEPARTMENT_ID is null then
SET RESULT_CODE = '1';
SET RESULT_DESC='FAILED';
rollback;
END if;
commit;
END

Create DSS (ManageManagerDetailsService.dbs):

<data name="ManageManagerDetailsService">
   <description>This service manage the managers details</description>
    <config id="DataSourceEmp">     
      <property name="org.wso2.ws.dataservice.driver">com.mysql.jdbc.Driver</property>     
      <property name="org.wso2.ws.dataservice.protocol">jdbc:mysql://localhost:3308/emp</property>     
      <property name="org.wso2.ws.dataservice.user">root</property>     
      <property name="org.wso2.ws.dataservice.password">root</property>     
      <property name="org.wso2.ws.dataservice.minpoolsize"></property>     
      <property name="org.wso2.ws.dataservice.maxpoolsize"></property>     
      <property name="org.wso2.ws.dataservice.validation_query"></property>  
   </config> 
   <query id="ManageManagerDetailsQuery" useConfig="DataSourceEmp">
      <sql>call MANAGE_MANAGER_DETAIL(?,?,?,?,?,?,?,?)</sql>
      <result defaultNamespace="http://shriwithjava.blogspot.co.nz/managemanagerdetails" element="ManageManagerDetailsResponse" rowName="">
         <element column="RESULT_CODE" name="ResultCode" xsdType="xs:string"/>
         <element column="RESULT_DESC" name="ResultDescription" xsdType="xs:string"/>
      </result>
      <param name="MANAGER_ID" ordinal="1" paramType="SCALAR" sqlType="STRING" type="IN"/>
      <param name="MANAGER_NAME" ordinal="2" paramType="SCALAR" sqlType="STRING" type="IN"/>
      <param name="ADDRESS" ordinal="3" paramType="SCALAR" sqlType="STRING" type="IN"/>
      <param name="DEPARTMENT_NAME" ordinal="4" paramType="SCALAR" sqlType="STRING" type="IN"/>
      <param name="NO_OF_PEOPLE" ordinal="5" paramType="SCALAR" sqlType="STRING" type="IN"/>
                                    <param name="OFFICE_LOCATION" ordinal="6" paramType="SCALAR" sqlType="STRING" type="IN"/>
      <param name="RESULT_CODE" ordinal="7" paramType="SCALAR" sqlType="STRING" type="OUT"/>
      <param name="RESULT_DESC" ordinal="8" paramType="SCALAR" sqlType="STRING" type="OUT"/>
   </query>
   <operation name="ManageManagerDetails">
      <description>This service manage the managers details</description>
      <call-query href="ManageManagerDetailsQuery">
         <with-param name="MANAGER_ID" query-param="ManagerId"/>
         <with-param name="MANAGER_NAME" query-param="ManagerName"/>
         <with-param name="ADDRESS" query-param="Address"/>
         <with-param name="DEPARTMENT_NAME" query-param="DepartmentName"/>
         <with-param name="NO_OF_PEOPLE" query-param="NoOfPeople"/>
         <with-param name="OFFICE_LOCATION" query-param="OfficeLocation"/>
      </call-query>
   </operation>
</data>


Create WSDL:

Now we have to create a WSDL in which multiple departments can be accepted for one employee id.

Request XML:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/">
   <soapenv:Header/>
   <soapenv:Body>
      <man:ManagerDetailsRequest>
         <man:Id>?</man:Id>
         <man:Name>?</man:Name>
         <man:Address>?</man:Address>
         <man:Departments>
            <!--1 or more repetitions:-->
            <man:DepartmentDetails>
               <man:DepartmentName>?</man:DepartmentName>
               <man:NoOfPeople>?</man:NoOfPeople>
               <man:OfficeLocation>?</man:OfficeLocation>
            </man:DepartmentDetails>
         </man:Departments>
      </man:ManagerDetailsRequest>
   </soapenv:Body>
</soapenv:Envelope>

Response XML:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/">
   <soapenv:Header/>
   <soapenv:Body>
      <man:ManagerDetailsResponse>
         <man:ResponseCode>?</man:ResponseCode>
         <man:ResponseDescription>?</man:ResponseDescription>
      </man:ManagerDetailsResponse>
   </soapenv:Body>
</soapenv:Envelope>

Use Iterator:

We have created a IN sequence, OUT sequence and fault sequence for this service, to use Iterator mediator go to below highlighted IN sequence and click on Edit.


You can find the Iterator mediator in Advance list. Select Iterator Mediator


There are some parameters which you need to define and also the Iterate Expression from which you need to split messages.


  • Iterator Id: we have to define a unique id for the iterator so than all the split message can be identify with this mediator. It is useful in case of aggregation.
  • Sequence Mediator: it defines that how message needs to be split parallel (False) or sequentially (True). By default it is False.
  • Continue Parent: Defines that original message needs to be continue or dropped. Default value is false.
  • Preserve Payload: Specify that original message needs to be used as a template for split message or not. Default value is False.
  • Iterate Expression: This is important parameter this expression matches the string that from where message needs to be split.
  • Attached Path: You can specify the XPATH expression for the new messages that split elements are attached to:



You will get the above screen once you click on the Target Configuration.
  • SOAP Action: Define the message Action.
  • To Address: Defines the endpoint address.
  • Sequence: You can define any sequence from the registry or define a new sequence by adding mediator to current target mediator as children.
  • Endpoint: Send the message from endpoints, you can pick up from registry or can define new one.


Synapse Code:

<definitions xmlns="http://ws.apache.org/ns/synapse">
    <proxy name="ManageManagerServiceProxy" transports="http" startOnLoad="true" trace="disable" statistics="enable">
        <target inSequence="ManageManagerService_IN" outSequence="ManageManagerService_OUT" faultSequence="ManageManagerServiceFaultHandler"/>
        <publishWSDL key="ManageManagerService_WSDL"/>
    </proxy>
                                  <localEntry key="ManageManagerService_WSDL" src="file:repository/conf/managerDetails/wsdl/ManagerDetails.wsdl"/>
    <localEntry key="ManageManagerServiceScript" src="file:repository/conf/managerDetails/scripts/ManagerDetails.js"/>
                                   <sequence name="ManageManagerServiceFaultHandler">
        <payloadFactory>
            <format>
                <man:ManagerDetailsResponse xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/">
                    <man:ResponseCode>-1</man:ResponseCode>
                    <man:ResponseDescription>Unknown Exception</man:ResponseDescription>
                </man:ManagerDetailsResponse>
            </format>
        </payloadFactory>
        <property name="RESPONSE" value="true"/>
        <header name="To" action="remove"/>
        <log level="full"/>
        <send/>
        <drop/>
    </sequence>
                                   <sequence name="ManageManagerService_IN">
        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/" name="Id" expression="//man:Id/text()"/>
        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/" name="Name" expression="//man:Name/text()"/>
        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/" name="Address" expression="//man:Address/text()"/>
        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/" name="NoOfDepartment" expression="count(//man:Departments/man:DepartmentDetails)"/>
<!—ITERATOR CODE -à
        <iterate xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/" id="3ITR_AGG" expression="//man:Departments/man:DepartmentDetails">
            <target>
                <sequence>
                    <property name="DepartmentName" expression="//man:DepartmentName/text()"/>
                    <property name="NoOfPeople" expression="//man:NoOfPeople/text()"/>
                    <property name="OfficeLocation" expression="//man:OfficeLocation/text()"/>
                    <script language="js" key="ManageManagerServiceScript" function="ManageManagerDetailsServiceRequest"/>
<!—Calling DSS - à
                    <send>
                        <endpoint key="DSS_ManageManagerDetails_EPR"/>
                    </send>
                </sequence>
            </target>
        </iterate>
    </sequence>
                                  <sequence name="ManageManagerService_OUT">
        <log level="full"/>
        <aggregate id="ITR_AGG">
            <completeCondition>
                <messageCount min="-1" max="-1"/>
            </completeCondition>
            <onComplete xmlns:s12="http://www.w3.org/2003/05/soap-envelope" xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/" expression="s11:Body/child::*[position()=1] | s12:Body/child::*[position()=1]">
                <property xmlns:man="http://shriwithjava.blogspot.co.nz/managemanagerdetails" name="ResultCode" expression="//man:ManageManagerDetailsResponse/man:ResultCode/text()"/>
                <property xmlns:man="http://shriwithjava.blogspot.co.nz/managemanagerdetails" name="ResultDescription" expression="//man:ManageManagerDetailsResponse/man:ResultDescription/text()"/>
                <filter xpath="contains(get-property('ResultCode'),'1')">
                    <then>
                        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managemanagerdetails" name="RESCULT_CODE" expression="//man:ManageManagerDetailsResponse[man:ResultCode='1'][1]/man:ResultCode/text()"/>
                        <property xmlns:man="http://shriwithjava.blogspot.co.nz/managemanagerdetails" name="RESCULT_DESC" expression="//man:ManageManagerDetailsResponse[man:ResultCode='1'][1]/man:ResultDescription/text()"/>
                    </then>
                    <else>
                        <property name="RESCULT_CODE" value="0"/>
                        <property name="RESCULT_DESC" value="Success"/>
                    </else>
                </filter>
                <payloadFactory>
                    <format>
                        <man:ManagerDetailsResponse xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/">
                            <man:ResponseCode>$1</man:ResponseCode>
                            <man:ResponseDescription>$2</man:ResponseDescription>
                        </man:ManagerDetailsResponse>
                    </format>
                    <args>
                        <arg expression="get-property('RESCULT_CODE')"/>
                        <arg expression="get-property('RESCULT_DESC')"/>
                    </args>
                </payloadFactory>
                <property name="RESPONSE" value="true"/>
                <header name="To" action="remove"/>
                <log level="full"/>
                <send/>
                <drop/>
            </onComplete>
        </aggregate>
    </sequence>
<!—DSS Endpoint -à
<endpoint name="DSS_ManageManagerDetails_EPR">
        <address uri="http://localhost:9763/services/ManageManagerDetailsService">
            <timeout>
                <duration>10000</duration>
                <responseAction>fault</responseAction>
            </timeout>
            <suspendOnFailure>
                <errorCodes>101500,101501,101506,101507,101508</errorCodes>
                <initialDuration>3000</initialDuration>
                <progressionFactor>0.0</progressionFactor>
            </suspendOnFailure>
            <markForSuspension>
                <errorCodes>101504,101505</errorCodes>
                <retriesBeforeSuspension>3</retriesBeforeSuspension>
                <retryDelay>1</retryDelay>
            </markForSuspension>
        </address>
    </endpoint>


Used JS:

<x><![CDATA[  
function ManageManagerDetailsServiceRequest(mc) {
var Id = mc.getProperty("Id");
var Name = mc.getProperty("Name");
var Address = mc.getProperty("Address");
var DepartmentName = mc.getProperty("DepartmentName");
var NoOfPeople = mc.getProperty("NoOfPeople");
var OfficeLocation = mc.getProperty("OfficeLocation");
                                 
 mc.setPayloadXML(
    <man:ManageManagerDetails xmlns:man="http://shriwithjava.blogspot.co.nz/managemanagerdetails">
         <man:ManagerId>{Id}</man:ManagerId>
         <man:ManagerName>{Name}</man:ManagerName>
         <man:Address>{Address}</man:Address>
         <man:DepartmentName>{DepartmentName}</man:DepartmentName>
         <man:NoOfPeople>{NoOfPeople}</man:NoOfPeople>
         <man:OfficeLocation>{OfficeLocation}</man:OfficeLocation>
      </man:ManageManagerDetails>

                                     );
}                                 
]]></x>


Execution:

To execute this service, load the project in SOAP UI and hit below request, in this request we are trying to insert data in database while using Iterator mediator. If you see below request you can find that one manager is handles 2 department (CS and IT) and same data we will insert into our database.

Request:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/">
   <soapenv:Header/>
   <soapenv:Body>
      <man:ManagerDetailsRequest>
         <man:Id>1234</man:Id>
         <man:Name>Shri</man:Name>
         <man:Address>Raebareli</man:Address>
         <man:Departments>
            <!--1 or more repetitions:-->
            <man:DepartmentDetails>
               <man:DepartmentName>IT</man:DepartmentName>
               <man:NoOfPeople>30</man:NoOfPeople>
               <man:OfficeLocation>Noida</man:OfficeLocation>
            </man:DepartmentDetails>
            <man:DepartmentDetails>
               <man:DepartmentName>COMPUTER SCIENCE</man:DepartmentName>
               <man:NoOfPeople>40</man:NoOfPeople>
               <man:OfficeLocation>Delhi</man:OfficeLocation>
            </man:DepartmentDetails>
         </man:Departments>
      </man:ManagerDetailsRequest>
   </soapenv:Body>
</soapenv:Envelope>

Response:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <man:ManagerDetailsResponse xmlns:man="http://shriwithjava.blogspot.co.nz/managerdetails/">
         <man:ResponseCode>0</man:ResponseCode>
         <man:ResponseDescription>Success</man:ResponseDescription>
      </man:ManagerDetailsResponse>
   </soapenv:Body>
</soapenv:Envelope>

Now if you look at the database you can find the records.