| WSO2 ESB | 4.5.x |
In a given SOA implementation, Service Integration plays a critical role. As SOA is all about services and their consumers, the infrastructure of implementing SOA; the Enterprise Service Bus (ESB), has the responsibility of interaction between all the services and consumers. Therefore, Service Integration is also a major requirement of any ESB implementation.
This article provides a closer look at the concepts of 'Service Integration' and a complete overview on service integration with the WSO2 ESB by using a real world healthcare scenario that involves service chaining.
Today's modern enterprise is comprised of so many systems and services which may be built based on open standards, custom-built, acquired from a third party, part of a legacy system or any such combination. With the advent of Service-Oriented Architecture (SOA) as the blue print for enterprise integration, most organizations tend to move away from monolithic applications and they expose their business functionalities as 'Services'. A 'Service' is defined as a logical representation of a repeatable business activity that has a specified outcome and does not depend on other services, unless it reuses them or it is composed of other services. By grouping various business functionalities as services in a well-defined and self-contained manner, the need for integrating these services to fulfil a business requirement has became a major challenge in the SOA world.
Figure 1 : Spaghetti Integration Dilemma
Obviously, there are many ways of integrating services and systems. If an organization really doesn't really care about the maintainability, scalability, troubleshooting, governance etc, then its most likely that the final integration outcome will end up in some sort of a Spaghetti Integration style. This is why the SOA needs a proper infrastructure that can provide a neat way of integrating diverse systems by preserving the ease of scalability, maintainability, troubleshooting and governance.
Figure 2 : Integration with an ESB
The standard infrastructure to implement the SOA concept is the Enterprise Service Bus (ESB) and therefore all the communication between the services and the consumers are done via the ESB. Hence, the notion of service integration is a major requirement of any ESB implementation. ESBs should facilitate not just standards based integrations (such as web services) but also other types of integration such as integrating with legacy systems.
The best way to illustrate the WSO2 ESB's service integration capabilities is that by implementing a real world service integration scenario. Let's take a typical healthcare scenario where a given healthcare organization wants to expose some of their functionalities as a service to the external world.
Figure 3 : Healthcare Scenario
One of the most common business use case of a service integration is to expose internal services to the client who will be consuming the services via a Mobile App. As depicted in the Figure 3, the main objective of the mobile user is to find the details of the nearest healthcare center/facilities based on his geographical coordinate (longitude and latitude).
However, in this scenario, there is no direct mapping between the coordinates and the Healthcare facilities. Apparently, the organization has 3 different services (for simplicity, we'll assume that all 3 services are exposed as SOAP services) which can collaboratively provide the required business functionality. So, this is a typical service integration scenario, where we need to have seamless integration of these 3 services and expose the integrated business functionality as a single (virtual) service.
Before proceeding further, lets have a closer look at the available services and their service interfaces.
Figure 4 : Healthcare Scenario - Services
Geo service is capable of mapping a given coordinate to a Zip Code (Postal Code). The request and the response formats are shown below.
Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:geo="http://geo.wso2">
<soapenv:Header/>
<soapenv:Body>
<geo:getZipCode>
<geo:longitude>1.0</geo:longitude>
<geo:latitude>2.0</geo:latitude>
</geo:getZipCode>
</soapenv:Body>
</soapenv:Envelope>
Response
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:getZipCodeResponse xmlns:ns="http://geo.wso2">
<ns:return>32746</ns:return>
</ns:getZipCodeResponse>
</soapenv:Body>
</soapenv:Envelope>
HC Facility Locator Service can resolve a given zip code to the Healthcare center codes (IDs). One important thing to note here is that, for a given zip code, there may be multiple healthcare center codes returning from the service.
Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:heal="http://healthcare.wso2">
<soapenv:Header/>
<soapenv:Body>
<heal:getHCCenters>
<heal:postalCode>32746</heal:postalCode>
</heal:getHCCenters>
</soapenv:Body>
</soapenv:Envelope>
Response
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:getHCCentersResponse xmlns:ns="http://healthcare.wso2">
<ns:return>2583</ns:return>
<ns:return>5201</ns:return>
<ns:return>5575</ns:return>
<ns:return>805</ns:return>
<ns:return>2285</ns:return>
</ns:getHCCentersResponse>
</soapenv:Body>
</soapenv:Envelope>
Finally, Healthcare Center Information Service, resolves the Healthcare Center code to the matching healthcare center details.
Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:heal="http://healthcare.wso2">
<soapenv:Header/>
<soapenv:Body>
<heal:getHCCenterInfo>
<heal:hcCenterCode>2583</heal:hcCenterCode>
</heal:getHCCenterInfo>
</soapenv:Body>
</soapenv:Envelope>
Response
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:getHCCenterInfoResponse xmlns:ns="http://healthcare.wso2">
<ns:return xsi:type="ax2494:HCInfo" xmlns:ax2494="http://healthcare.wso2/xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ax2494:address>2583 South Volusia Ave (17-92), Suite 300</ax2494:address>
<ax2494:approxDistance>13.1</ax2494:approxDistance>
<ax2494:city>Orange City, FL</ax2494:city>
<ax2494:hcCenterName>Orange City CBOC</ax2494:hcCenterName>
<ax2494:phone>386-456-2080 Or 386-456-2082</ax2494:phone>
</ns:return>
</ns:getHCCenterInfoResponse>
</soapenv:Body>
</soapenv:Envelope>
Lets start with deploying the sample services on WSO2 Application Server. I have created all 3 sample services which can be downloaded from the attachments section of this article.
1
Now that we have a good understanding about the Healthcare Service Integration scenario, let's move on with the implementation level details. If we analyze the business requirements again, we need to implement the business functionality as a service, which can provide the details of the nearest Healthcare Center based on the Geographical coordinate provided by the user.
In the ESB's perspective, we need to expose a 'virtual service', that provides the required business functionality by seamless integration of Geo Service, HC Facility Locator Service and HC Center Information Service. In the WSO2 ESB, such service is termed as a 'Proxy Service'. Before jumping in to the actual implementation of the service, it's mandatory to understand some basic concepts related to WSO2 ESB.
Figure 5 : WSO2 ESB - Proxy Services fundamentals
Now that we have deployed/tested the required backend services and understood the basic concepts of ESB, we are all set to start integrating the services with WSO2 ESB
As the initial setup, we need to define the service definition of the virtual service that we are going to expose from the ESB. Since this will be implemented as a Proxy Service inside the WSO2 ESB, we simply need to create a WSDL for the proxy service with the required schema and operations.
Figure 6 : Service Integration with WSO2 ESB
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="GeoEP">
<address statistics="disable" trace="disable" uri="http://localhost:9764/services/GeoService/"/>
</endpoint>
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="HCFacilityLocatorServiceEP">
<address statistics="disable" trace="disable" uri="http://localhost:9764/services/HCFacilityLocatorService"/>
</endpoint>
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="HCInformationService">
<address statistics="disable" trace="disable" uri="http://localhost:9764/services/HCInformationService"/>
</endpoint>
Before we dive deep in to the implementation details, its important to have a high level understanding about the implementation. What follows is the implementation of the message flow
Figure 7 : Healthcare Scenario - Summary
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:heal="http://healthcare.wso2">
<soapenv:Body>
<heal:getHealthcareCenterInfo>
<heal:longitude>34.3</heal:longitude>
<heal:latitude>-43.2</heal:latitude>
</heal:getHealthcareCenterInfo>
</soapenv:Body>
</soapenv:Envelope>
<property action="set"
expression="//heal:getHealthcareCenterInfo/heal:longitude/text()"
name="longitude" scope="default" type="STRING" xmlns:heal="http://healthcare.wso2"/>
<property action="set"
expression="//heal:getHealthcareCenterInfo/heal:latitude/text()"
name="latitude" scope="default" type="STRING" xmlns:heal="http://healthcare.wso2"/>
<log category="INFO" level="custom" separator=",">
<property expression="$ctx:longitude" name="Longitude"/>
<property expression="$ctx:latitude" name="Latitude"/>
</log>
<enrich>
<source clone="true" type="inline">
<geo:getZipCode xmlns:geo="http://geo.wso2">
<geo:longitude>0</geo:longitude>
<geo:latitude>0</geo:latitude>
</geo:getZipCode>
</source>
<target action="replace" type="body"/>
</enrich>
<enrich>
<source clone="true" property="longitude" type="property"/>
<target action="replace" type="custom"
xmlns:geo="http://geo.wso2" xpath="//geo:getZipCode/geo:longitude/text()"/>
</enrich>
<enrich>
<source clone="true" property="latitude" type="property"/>
<target action="replace" type="custom"
xmlns:geo="http://geo.wso2" xpath="//geo:getZipCode/geo:latitude/text()"/>
</enrich>
<log category="INFO" level="custom" separator=",">
<property name="MessageFlow" value="======================= Sending Request To : GeoWS ======================="/>
</log>
<log category="INFO" level="full" separator=","/>
<inSequence>
<property action="set"
expression="//heal:getHealthcareCenterInfo/heal:longitude/text()"
name="longitude" scope="default" type="STRING" xmlns:heal="http://healthcare.wso2"/>
<property action="set"
expression="//heal:getHealthcareCenterInfo/heal:latitude/text()"
name="latitude" scope="default" type="STRING" xmlns:heal="http://healthcare.wso2"/>
<log category="INFO" level="custom" separator=",">
<property expression="$ctx:longitude" name="Longitude"/>
<property expression="$ctx:latitude" name="Latitude"/>
</log>
<enrich>
<source clone="true" type="inline">
<geo:getZipCode xmlns:geo="http://geo.wso2">
<geo:longitude>0</geo:longitude>
<geo:latitude>0</geo:latitude>
</geo:getZipCode>
</source>
<target action="replace" type="body"/>
</enrich>
<enrich>
<source clone="true" property="longitude" type="property"/>
<target action="replace" type="custom"
xmlns:geo="http://geo.wso2" xpath="//geo:getZipCode/geo:longitude/text()"/>
</enrich>
<enrich>
<source clone="true" property="latitude" type="property"/>
<target action="replace" type="custom"
xmlns:geo="http://geo.wso2" xpath="//geo:getZipCode/geo:latitude/text()"/>
</enrich>
<log category="INFO" level="custom" separator=",">
<property name="MessageFlow" value="======================= Sending Request To : GeoWS ======================="/>
</log>
<log category="INFO" level="full" separator=","/>
<send receive="hcfRequest">
<endpoint key="GeoEP"/>
</send>
</inSequence>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="hcfRequest">
<log category="INFO" level="custom" separator=",">
<property name="MessageFlow" value="------------------- Response Received - From : GeoWS ----------------------------------"/>
</log>
<log category="INFO" level="full" separator=","/>
<property action="set"
expression="//geo:getZipCodeResponse/geo:return/text()"
name="zipcode" scope="default" type="STRING"
xmlns:geo="http://geo.wso2"
xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd"/>
<log category="INFO" level="custom" separator=",">
<property expression="$ctx:zipcode" name="zipcode"
xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd"/>
</log>
<payloadFactory>
<format>
<heal:getHCCenters xmlns:heal="http://healthcare.wso2">
<heal:postalCode>$1</heal:postalCode>
</heal:getHCCenters>
</format>
<args>
<arg expression="$ctx:zipcode"
xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd"/>
</args>
</payloadFactory>
<log category="INFO" level="custom" separator=",">
<property name="MessageFlow" value="==================== Sending Request To : HCFacilityLocatorService ================"/>
</log>
<log category="INFO" level="full" separator=","/>
<send receive="hciRequest">
<endpoint key="HCFacilityLocatorServiceEP"/>
</send>
</sequence>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="hciRequest">
<log level="full"/>
<iterate xmlns:hfs="http://healthcare.wso2" xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" preservePayload="true" attachPath="//hfs:getHCCentersResponse" expression="//hfs:getHCCentersResponse/hfs:return">
<target>
<sequence>
<payloadFactory>
<format>
<heal:getHCCenterInfo xmlns:heal="http://healthcare.wso2">
<heal:hcCenterCode>$1</heal:hcCenterCode>
</heal:getHCCenterInfo>
</format>
<args>
<arg xmlns:hcc="http://healthcare.wso2" expression="//hcc:getHCCentersResponse/hcc:return/text()"/>
</args>
</payloadFactory>
<log level="full"/>
<send>
<endpoint key="HCInformationService"/>
</send>
</sequence>
</target>
</iterate>
</sequence>
<log category="INFO" level="custom" separator=",">
<property name="MessageFlow" value="------------------------Response Received - From : HCInformationService ------------------------"/>
</log>
<log category="INFO" level="full" separator=","/>
<aggregate>
<completeCondition timeout="0">
<messageCount max="-1" min="-1"/>
</completeCondition>
<onComplete expression="//hcc:getHCCenterInfoResponse" xmlns:hcc="http://healthcare.wso2">
<log category="INFO" level="custom" separator=",">
<property name="MessageFlow" value="======================= Sending Back the Aggregated Responses. ==============="/>
</log>
<log category="INFO" level="full" separator=","/>
<send/>
</onComplete>
</aggregate>
Now that we have analyzed implementation details of the entire scenario, it's time to try out the Healthcare Scenario with the WSO2 ESB and WSO2 Application Server. I have added all the required services and ESB configuration as an attachment. ESB configuration is created using the WSO2 Developer Studio and it is available as a WSO2 Carbon application-cApp : Service_Integration_CApp_1.0.0.car.
Service_Integration_Artifacts
├── cApp
│ └── Service_Integration_CApp_1.0.0.car
└── services
├── GeoService.wsdl
├── geows-SNAPSHOT.aar
├── HCCService.wsdl
├── HCFacilityLocatorService.wsdl
├── hcfacilitylocator-SNAPSHOT.aar
├── hcinformationservice-SNAPSHOT.aar
└── HCInformationService.wsdl
After deploying all the required services in WSO2 Application Server, you can simply deploy the attached cApp (Service_Integration_CApp_1.0.0.car) as an Application using WSO2 ESB management console.
Once everything is deployed you can use the SOAP UI project created based on the WSDL of the HCCProxyService and send a request to the HCCProxyService.
You will see various log messages, that we put in using the log mediators in each mediation flow.
Service Integration is a very common integration requirement and the WSO2 ESB provides a rich set of features to cater to these requirements. We have discussed a real world service integration scenario and we implemented it from scratch using the WSO2 ESB. For simplicity, we considered some SOAP services. However in a future article I will touch on service integration with some heterogeneous services as well. Also, one might suggest to use WS-BPEL for the exact same scenario with WSO2 BPS, which is still a valid candidate. I will cover the topic of when to use the ESB and when to use WSO2 BPS in a future article as well.
Kasun Indrasiri, Associate Technical Lead, WSO2 Inc
| Attachment | Size |
|---|---|
| Service_Integration_Artifacts.zip | 34.92 KB |