Showing posts with label WSO2. Show all posts
Showing posts with label WSO2. Show all posts

Wednesday, March 14, 2018

How to read values in ESB from secure vault


Some time we have a requirement in which we have to keep our credentials in any secure message store. WSO2 provide secure vault feature in ESB to keep your credentials and you can get these hidden details with below property and use anywhere in your ESB logic.

Code:


<property expression="wso2:vault-lookup('Username')"
    name="UserName" scope="default" type="STRING" xmlns:ns="http://org.apache.synapse/xsd"/>

Setup Secure Vault in WSO2 ESB


  • Go to the your ESB home/bin directory 
  • Execute command “ciphertool.bat -Dconfigure” as mentioned below

You should be getting the below outcome of it. It will ask you the password for Carbon server, please provide "wso2carbon"


C:\Work\WSO2\wso2esb-4.9.0\repository\conf\security>ciphertool.bat -Dconfigure
'ciphertool.bat' is not recognized as an internal or external command,
operable program or batch file.

C:\Work\WSO2\wso2esb-4.9.0\repository\conf\security>cd ciphertool.bat
The system cannot find the path specified.

C:\Work\WSO2\wso2esb-4.9.0\repository\conf\security>cd C:\Work\WSO2\wso2esb-4.9.0\bin

C:\Work\WSO2\wso2esb-4.9.0\bin>ciphertool.bat -Dconfigure
'ant' is not recognized as an internal or external command,
operable program or batch file.
Using CARBON_HOME:   C:\Work\WSO2\wso2esb-4.9.0
Using JAVA_HOME:    C:\Program Files\Java\jdk1.8.0_151
[Please Enter Primary KeyStore Password of Carbon Server : ]

Primary KeyStore of Carbon Server is initialized Successfully

Protected Token [UserManager.AdminUser.Password] is updated in repository/conf/user-mgt.xml successfully

Protected Token [Carbon.Security.KeyStore.KeyPassword] is updated in repository/conf/carbon.xml successfully

Protected Token [Server.Service.Connector.keystorePass] is updated in repository/conf/tomcat/catalina-server.xml successfully

Protected Token [Carbon.Security.TrustStore.Password] is updated in repository/conf/carbon.xml successfully

Protected Token [Carbon.Security.KeyStore.Password] is updated in repository/conf/carbon.xml successfully

Protected Token [Datasources.WSO2_CARBON_DB.Configuration.Password] is updated in repository/conf/datasources/master-datasources.xml successfully


Encryption is done Successfully


Encryption is done Successfully


Encryption is done Successfully


Encryption is done Successfully


Encryption is done Successfully


Encryption is done Successfully


Secret Configurations are written to the property file successfully

C:\Work\WSO2\wso2esb-4.9.0>


Once you get above message, you can now add secure vault from ESB console UI.

How to add password in secure vault in WSO2 ESB


  • Start the ESB server and login with admin/admin.
  • Click on the “Manage password” link under the Secure vault Tool and click on the “Add New Password to encrypt and store” on link 

  • You might get below error, means you have not setup your secure vault yet. To DO that please follow this blog

And in the logs you can see below error


  • If you have not got above error, means all good and now you can provide key and password as mentioned below.

  • Click on “Add” button

Your values has been added successfully

Monday, October 16, 2017

Create a dynamic/filtered query service in WSO2 DSS.



Sometimes we have requirement in which we have to call a database query at run time. For example, we have an employee table and need to get details from this table with some condition like “where emp_last_name=? and address=?”. In above scenario if we don’t know the how many condition cab be there at run time, DSS filtered query can be used.


DSS file:


<data name="DynamicDS" transports="http https local">
   <config enableOData="false" id="DynamicQueryEmp">
      <property name="driverClassName">com.mysql.jdbc.Driver</property>
      <property name="url">jdbc:mysql://localhost:3306/emp</property>
      <property name="username">root</property>
      <property name="password">root</property>
   </config>
   <query id="DynaminQuery" useConfig="DynamicQueryEmp">
      <sql>select id, name, address from emp :filterQuery</sql>
      <result defaultNamespace="http://shriwithjava.blogspot.co.nz/" element="employees" rowName="employee">
         <element column="id" name="id" xsdType="xs:string"/>
         <element column="name" name="name" xsdType="xs:string"/>
         <element column="address" name="address" xsdType="xs:string"/>
      </result>
      <param name="filterQuery" sqlType="QUERY_STRING"/>
   </query>
   <operation name="getEmployees">
      <call-query href="DynaminQuery">
         <with-param name="filterQuery" query-param="filterQuery"/>
      </call-query>
   </operation>
</data> 




In this DSS file we can use any database condition and pass it to DSS as parameter




Sunday, August 6, 2017

How to implement NTLM security in WSO2 ESB

Unfortunately, WSO2 does not provide any plugins or mediator directly to implement NTLM security. However, this can be done by using the custom mediator. You can write a java class with this security handler and call it from WSO2 container.

In order to write a Class mediator, you can follow this blog and put the custom jar into the WSO2 lib folder.  



package poc.ntlm;

import java.io.IOException;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.NTCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;

public class NLTMSecurity {

 public static void main(String[] args) throws HttpException, IOException {
  System.out.println("started");
  String result = invokeService();
  System.out.println("output  : " + result);

 }

 public static String invokeService()
   throws HttpException, IOException {
  String responseString = null;
  try {
   HttpClient client = new HttpClient();

   String URL = "http://XXX.XXX.XXX/XX/XXX/2011/OrganizationData.svc/ListSet?$select=ListId,ListName,StateCode";
   GetMethod getMethod = new GetMethod(URL);
   NTCredentials credentials = new NTCredentials("USER_NAME", "PASSWORD", "HOST_NAME", "DOMAIN");
   client.getState().setCredentials(new AuthScope(null, -1, null),
     credentials);
   int status = client.executeMethod(getMethod);

   System.out.println("Status : " + status);

   responseString = getMethod.getResponseBodyAsString();

   System.out.println("responseString : " + responseString);

  } catch (Exception e) {
   System.out.println(e);
  }

  return responseString;

 }

}




You can set this response and the HTTP code in the WSO2 ESB container.



import org.apache.synapse.MessageContext;
import org.apache.synapse.mediators.AbstractMediator;


public class NTLMSecurityMediator extends AbstractMediator { 

 public boolean mediate(MessageContext context) { 

 context.setProperty("Response", responseString );
      
context.setProperty("HTTP_STATUS", status );      return true;
      
    
  
 }
}

How to apply Certificate in WSO2 ESB


In our previous blog, we have converted the .pfx file to .cer file. In this blog we will see how to apply certificate in WSO2 ESB.

Until certificate is added, we can't connect to the 3rd party services if this certificate is implemented there. This can be done by using very simple below steps.

You have to reach to the WSO2 ESB (wso2esb-4.9.0) security folder and execute the below steps.


C:\>cd C:\Work\WSO2\wso2esb-4.9.0\repository\resources\security

C:\Work\WSO2\wso2esb-4.9.0\repository\resources\security>keytool -importcert -file C:\Users\ShriK\Desktop\nzgpp\certificate\nzgpp.cer -keystore client-truststore.jks -alias nzgpp


  • Use "wso2carbon" password if asked.

Enter keystore password:
Owner: CN=XXXXX.jqdev.local
Issuer: CN=XXXXX.jqdev.local
Serial number: 7c74XXXXXXXXX1b12ac2808bc
Valid from: Thu Aug 03 13:29:13 NZST 2017 until: Fri Aug 03 12:00:00 NZST 2018
Certificate fingerprints:
         MD5:  5C:4B:E3:AD:57:E9:6F:08:76:95:6D:60:A3:04:2A:EB
         SHA1: AE:58:76:XX:XX:9A:64:84:55:62:XX:17:XX:A7:9A:54:1B:E9:C4:14
         SHA256: F5:53:66:05:E3:41:CF:65:E7:9D:14:1F:1D:81:39:D7:96:XX:90:26:51:XX:A7:9A:54:1B:E9:27:CD:14:F9
         Signature algorithm name: SHA1withRSA
         Version: 3

Extensions:

#1: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
  serverAuth
]

#2: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
  Key_Encipherment
  Data_Encipherment
]


  • Type "yes" and enter

Trust this certificate? [no]:  yes
Certificate was added to keystore



Once above highlighted message is printed, means your certificate is successfully installed. you shouyld be getting expected results. 

Convert .PFX file to .cer file

In this logs I will show that how to convert .pfx file to .cer file. In order to do that you should have a .pfx file which I have taken it from Microsoft CRM where this certificate has been installed.



    • Search “internet option” in start and open it.


    • Click on the Content tab

    • Click on the Certificate Button

    • Click on Import button and click Next

    • Select .pfx file

    • Click Open and OK.
    In above steps we have successfully imported the .pfx file and now need to covert it to .cer file.

    • Follow the same steps above and reach to the certificate location.

    • Select certificate and click on export
    • Click Next and again click next in next screen

    • Click Next
    • Give the file name and the location and save it.
    Now in next blog we will see how to install this certificate in WSO2 ESB in order to connect to CRM services.

    Sunday, September 4, 2016

    How to set a static response or property in class mediator in WSO2 ESB

    WSO2 ESB provides us luxury to create a custom functionality in java as class mediator. In class mediator we can write our desired functionality in java class and that can be called from the ESB synapse file. We can pass some property from ESB file to class mediator and in a same way we can set some property in java class and that can be read from synapse file.

    Here is an example in which I need to reply a static response to customer. However this can be done from many ways but I am choosing class mediator just to show how this can be done from class mediator.


     I want below static response to be shown in as actual response of the service. I have put this “StaticEmployeeDetails.xml” file in “XX\wso2esb-4.0.3\repository\conf\stub\StubXml\ StaticEmployeeDetails.xml” location.

    Static XML Code:

    <EmployeeDetails xmlns="http://shriwithjava.blogspot.co.nz/">
       <EmployeeData>
          <EmployeeId>201</EmployeeId>
          <EmployeeName>Shri</EmployeeName>
          <EmployeeAddress>Auckland</EmployeeAddress>
          <Department>IT</Department>
       </EmployeeData>
       <EmployeeData>
          <EmployeeId>202</EmployeeId>
          <EmployeeName>Bhajan</EmployeeName>
          <EmployeeAddress>Wellington</EmployeeAddress>
          <Department>IT</Department>
       </EmployeeData>
    </EmployeeDetails>
    



    Here is the Class mediator code which will be called from the wso2 Synapse file.

    Class Mediator Code:

    package org.wso2.custom;
    
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    import org.apache.synapse.MessageContext;
    import org.apache.synapse.mediators.AbstractMediator;
    
    public class CustomMediator extends AbstractMediator {
    
                    private static String Response = "StaticResponse";
                    private static String ResponseXml = "";
                    private static String FileName = "";
                    private static String FilePath = "F:\\Shri Kant\\WSO2\\wso2esb-4.0.3\\repository\\conf\\stub\\StubXml\\";
                    public boolean mediate(MessageContext context) {
                                    // TODO Implement your mediation logic here
                                    //FileName=context.getProperty("").toString();
                                    FileName=(String)context.getProperty("FileName");
                                    BufferedReader br = null;
                                    try {
    
                                                    String sCurrentLine;
    
                                                    br = new BufferedReader(new FileReader(FilePath+FileName+".xml"));
    
                                                    while ((sCurrentLine = br.readLine()) != null) {
                                                                    ResponseXml+=               sCurrentLine;
                                                    }
                                                    context.setProperty(Response, ResponseXml);
                                                   
                                                    System.out.println(context.getSoapAction()+" : This is the SOAP Action");
                                                    System.out.println(context.getConfiguration()+" : This is the getConfiguration");
                                                    System.out.println(context.getMessageID()+" : This is the getMessageID");
                                                    System.out.println(context.getTracingState()+" : This is the getTracingState");
                                                    System.out.println(context.getWSAAction()+" : This is the getWSAAction");
                                                    System.out.println(context.getWSAMessageID()+" : This is the getWSAMessageID");
                                                    System.out.println(context.getClass()+" : This is the getClass");
                                                    System.out.println(context.getContextEntries()+" : This is the getContextEntries");
                                                    System.out.println(context.getEnvelope()+" : This is the getEnvelope");
                                                    System.out.println(context.getEnvironment()+" : This is the getEnvironment");
                                                    System.out.println(context.getFaultSequence()+" : This is the getFaultSequence");
                                                    System.out.println(context.getFaultStack()+" : This is the getFaultStack");
                                                    System.out.println(context.getPropertyKeySet()+" : This is the getPropertyKeySet");
                                                    System.out.println(context.getServiceLog()+" : This is the getServiceLog");
                                                    System.out.println(context.isDoingGET()+" : This is the isDoingGET");
                                                    System.out.println(context.isDoingMTOM()+" : This is the isDoingMTOM");
                                                    System.out.println(context.isDoingPOX()+" : This is the isDoingPOX");
                                                    System.out.println(context.isDoingSWA()+" : This is the isDoingSWA");
                                                    System.out.println(context.isFaultResponse()+" : This is the isFaultResponse");
                                                    System.out.println(context.isSOAP11()+" : This is the isSOAP11");
                                                    System.out.println(context.isResponse()+" : This is the isResponse");
                                                   
                                    } catch (IOException e) {
                                                    e.printStackTrace();
                                    } finally {
                                                    Response="";
                                                    try {
                                                                    if (br != null){
                                                                                    br.close();
                                                                                   
                                                                    }
                                                    } catch (IOException ex) {
                                                                    ex.printStackTrace();
                                                    }
                                    }
                                   
                                   
                                    return true;
                    }
    }
    




    • ·         Different property has been used in above code just to show that what all we can set from class mediator and use it in our synapse file.
    • ·         Create ja jar file of this above code and place it in the “X\ wso2esb-4.0.3\repository\components\lib\CustomMediator.jar”
    • ·         Now we need to provide the reference of this class from the synapse.xml file

    I am creating a service “MyCustomProxy”. You can see that I have used “<class name="org.wso2.custom.CustomMediator"/>” code to call the class mediator. I have also used the javascript function which will change the response from string to xml. “<property name="StaticResponse" action="set" expression="get-property('StaticResponse')"/>” is used to get response from the class mediator which will be read from the static xml file.

    Synpse.xml:

    <localEntry key="StaticServiceScript" src="file:repository/conf/stub/StaticTransformResponse.js"/>
                   
    <proxy name="MyCustomProxy" transports="http" startOnLoad="true" statistics="enable" trace="disable">
                    <target inSequence="MyCustom_IN" outSequence="MyCustom_OUT" faultSequence="CommonFaultHandler"/>
                    <publishWSDL key="MyCustom_wsdl"/>
    </proxy>
    <localEntry key="MyCustom_wsdl" src="file:repository/conf/employee/OverseaseEmployee.wsdl"/>
    <sequence name="MyCustom_IN">
                    <property name="FileName" value="StaticEmployeeDetails" action="set"/>     
                    <class name="org.wso2.custom.CustomMediator"/>
                    <property name="StaticResponse" action="set" expression="get-property('StaticResponse')"/>
                    <script language="js" key="StaticServiceScript" function="sendStaticResponse"/>
                    <property name="RESPONSE" value="true"/>
                    <header name="To" action="remove"/>
                    <send/>
                    <drop/>
    </sequence>    
    




    Java Script Code:
    I am using a java script code which will be called from synapse.xml file. This will create a string text to xml content.

    StaticTransformResponse.js


    <x><![CDATA[  
    
                    function sendStaticResponse(mc) {
                    var StaticResponse = new XML(mc.getProperty("StaticResponse"));
                                                    mc.setPayloadXML(StaticResponse);
                   
                      }
    ]]></x>
    




    Just restart the server to reflect the changes and hit the “MyCustomProxy” service and you will get the desired response. If you want to change the static response just change the content of the “StaticEmployeeDetails.xml” file located inside of “wso2esb-4.0.3\repository\conf\stub\StubXml” and restart the server.


    Above image shows all the parameter what we have set in out java class. Same things we can get it in synapse.xml file as per our requirement.

    Monday, August 1, 2016

    How to use Clone Mediator in WSO2 ESB

    Clone mediator is used to send same massage to multiple endpoints. It basically clone same message to multiple message based on our requirement and send it to multiple endpoints. We can aggregate the response which we get from the multiple endpoints and show as one response.

    Requirement:

    Suppose there is a requirement where we have to get the entire IT employee details who all works overseas. We have different databases and different places and each database has employee records. We have only one input parameter which is department, all I need is IT employee details.

    Solution:

    I have created 3 data services, first provides Indian employee detail, second provide USA employee details and 3rd provides New Zealand employee details. I have created same format DSS with same namespace with one input parameter and 4 output parameter in one employee list and response can have multiple employee list.


    DSS:
    <data name="EmployeeDetailsNZ" enableBatchRequests="false" enableBoxcarring="false" serviceStatus="active">
       <description>This provides Employee details</description>
       <config id="EMPDS">
          <property name="org.wso2.ws.dataservice.driver">oracle.jdbc.driver.OracleDriver</property>
          <property name="org.wso2.ws.dataservice.protocol">jdbc:oracle:thin:SYSTEM/SYSTEM@localhost:1521/xe</property>
          <property name="org.wso2.ws.dataservice.user">SYSTEM</property>
          <property name="org.wso2.ws.dataservice.password">SYSTEM</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="EmpDetailsQuery" useConfig="EMPDS">
          <sql>select * from EMP_DETAILS_NZ where DEPARTMENT_V=?</sql>
          <result element="EmployeeDetails" rowName="EmployeeData" defaultNamespace="http://shriwithjava.blogspot.co.nz/">
             <element name="EmployeeId" column="EMP_ID_N" xsdType="xs:string" />
       <element name="EmployeeName" column="EMP_NAME_V" xsdType="xs:string" />
       <element name="EmployeeAddress" column="EMP_ADD_V" xsdType="xs:string" />
       <element name="Department" column="DEPARTMENT_V" xsdType="xs:string" />
       </result>
          <param name="Department" paramType="SCALAR" sqlType="STRING" type="IN" />
       
       </query>
       <operation name="getEmployeeDetails">
          <description></description>
          <call-query href="EmpDetailsQuery">
             <with-param name="Department" query-param="Department" />
       
          </call-query>
       </operation>
    </data>
    

    DSS request and response format:

    Request:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:shr="http://shriwithjava.blogspot.co.nz/">
       <soapenv:Header/>
       <soapenv:Body>
          <shr:getEmployeeDetails>
             <shr:Department>IT</shr:Department>
          </shr:getEmployeeDetails>
       </soapenv:Body>
    </soapenv:Envelope>
    

    Response:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
       <soapenv:Body>
          <EmployeeDetails xmlns="http://shriwithjava.blogspot.co.nz/">
             <EmployeeData>
                <EmployeeId>201</EmployeeId>
                <EmployeeName>Shri</EmployeeName>
                <EmployeeAddress>Auckland</EmployeeAddress>
                <Department>IT</Department>
             </EmployeeData>
             <EmployeeData>
                <EmployeeId>202</EmployeeId>
                <EmployeeName>Bhajan</EmployeeName>
                <EmployeeAddress>Wellington</EmployeeAddress>
                <Department>IT</Department>
             </EmployeeData>
          </EmployeeDetails>
       </soapenv:Body>
    </soapenv:Envelope>
    



    ESB Changes:

    I have created a service which will get all the details of the overseas employee for different department. I will call all the endpoints (Indian, USA and New Zealand employee details) and aggregate the response into one. I have to use same input and that will be cloned for each endpoint from the clone mediator.

    Synapse Code:

    <definitions>
    <proxy name="OverseasEmpDetailsProxy" transports="http" startOnLoad="true" trace="disable" statistics="enable">
       <target inSequence="OverseasEmpDetails_IN" outSequence="OverseasEmpDetails_OUT" faultSequence="CommonFaultHandler"/>
       <publishWSDL key="OverseasEmpDetails_wsdl"/>
    </proxy>
    <localEntry key="OverseasEmpDetails_wsdl" src="file:repository/conf/employee/OverseaseEmployee.wsdl"/>
     
    <sequence name="OverseasEmpDetails_IN">
     <clone>
      <target>
       <endpoint key="NZEmployeeDetails_EPR"/>
      </target>
      <target>
       <endpoint key="INDEmployeeDetails_EPR"/>
      </target>
      <target>
       <endpoint key="USAEmployeeDetails_EPR"/>
      </target>
     </clone>
    </sequence>
     
    <sequence name="OverseasEmpDetails_OUT">
       <aggregate>
      <completeCondition>
       <messageCount min="-1" max="-1"/>
      </completeCondition>
      <onComplete xmlns:shr="http://shriwithjava.blogspot.co.nz/" expression="//shr:EmployeeDetails/shr:EmployeeData">
       <send/>
      </onComplete>
     </aggregate>
    </sequence>
     
     <endpoint name="NZEmployeeDetails_EPR">
     <address uri="http://localhost:9763/services/EmployeeDetailsNZ">
      <timeout>
       <duration>10000</duration>
       <responseAction>fault</responseAction>
      </timeout>
      <suspendOnFailure>
       <errorCodes>101500,101501,101506,101507,101508</errorCodes>
       <progressionFactor>0.0</progressionFactor>
      </suspendOnFailure>
      <markForSuspension>
       <errorCodes>101504,101505</errorCodes>
      </markForSuspension>
     </address>
    </endpoint>
     <endpoint name="INDEmployeeDetails_EPR">
     <address uri="http://localhost:9763/services/EmployeeDetailsIndia">
      <timeout>
       <duration>10000</duration>
       <responseAction>fault</responseAction>
      </timeout>
      <suspendOnFailure>
       <errorCodes>101500,101501,101506,101507,101508</errorCodes>
       <progressionFactor>0.0</progressionFactor>
      </suspendOnFailure>
      <markForSuspension>
       <errorCodes>101504,101505</errorCodes>
      </markForSuspension>
     </address>
    </endpoint>
     <endpoint name="USAEmployeeDetails_EPR">
     <address uri="http://localhost:9763/services/EmployeeDetailsUSA">
      <timeout>
       <duration>10000</duration>
       <responseAction>fault</responseAction>
      </timeout>
      <suspendOnFailure>
       <errorCodes>101500,101501,101506,101507,101508</errorCodes>
       <progressionFactor>0.0</progressionFactor>
      </suspendOnFailure>
      <markForSuspension>
       <errorCodes>101504,101505</errorCodes>
      </markForSuspension>
     </address>
    </endpoint>
     
    <sequence name="CommonFaultHandler">
     <log level="custom">
      <property name="MESSAGE" value="Executing default &quot;fault&quot; sequence"/>
      <property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
      <property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
     </log>
     <header name="To" action="remove"/>
     <drop/>
    </sequence>
     
     
    </definitions>
    


    Restart the ESB and load the WSDL in SOAP UI results will look like:

    Request:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:shr="http://shriwithjava.blogspot.co.nz/">
       <soapenv:Header/>
       <soapenv:Body>
          <shr:getEmployeeDetails>
             <shr:Department>IT</shr:Department>
          </shr:getEmployeeDetails>
       </soapenv:Body>
    </soapenv:Envelope>
    


    Response:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
       <soapenv:Body>
          <EmployeeDetails xmlns="http://shriwithjava.blogspot.co.nz/">
             <EmployeeData>
                <EmployeeId>201</EmployeeId>
                <EmployeeName>Shri</EmployeeName>
                <EmployeeAddress>Auckland</EmployeeAddress>
                <Department>IT</Department>
             </EmployeeData>
             <EmployeeData>
                <EmployeeId>202</EmployeeId>
                <EmployeeName>Bhajan</EmployeeName>
                <EmployeeAddress>Wellington</EmployeeAddress>
                <Department>IT</Department>
             </EmployeeData>
             <EmployeeData>
                <EmployeeId>004</EmployeeId>
                <EmployeeName>Viru</EmployeeName>
                <EmployeeAddress>Kanpur</EmployeeAddress>
                <Department>IT</Department>
             </EmployeeData>
             <EmployeeData>
                <EmployeeId>111</EmployeeId>
                <EmployeeName>Tahseen</EmployeeName>
                <EmployeeAddress>New York</EmployeeAddress>
                <Department>IT</Department>
             </EmployeeData>
             <EmployeeData>
                <EmployeeId>113</EmployeeId>
                <EmployeeName>JD</EmployeeName>
                <EmployeeAddress>Washington</EmployeeAddress>
                <Department>IT</Department>
             </EmployeeData>
          </EmployeeDetails>
       </soapenv:Body>
    </soapenv:Envelope>
    

    You can see the response from different service have been merged into one and we only sent a single request with a department parameter.