Enterprise Architecture & Integration, SOA, ESB, Web Services & Cloud Integration

Enterprise Architecture & Integration, SOA, ESB, Web Services & Cloud Integration

Sunday, 15 November 2015

Expose existing SOAP Web Services as REST API using WSO2 ESB

Problem statement

Your enterprise might have invested a lot in exposing software assets as SOAP Web Services to integrate with internal and external applications. If a new "modern" consumer who can (or wants to) consume only REST API, would you rewrite the entire thing to support REST clients?

WSO2 ESB (for example, version 4.8.1 which I have used) supports RESTful integration using API. We can leverage this feature to expose SOAP web services through REST API without changes to SOAP services. So, same time you would be able to support existing SOAP clients and new REST clients.

There are many blogs / web sites available on detailed explanation on REST style. You can follow this https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm from Roy Fielding. Another blog on REST can be found here in http://rest.elkstein.org/2008/02/what-is-rest.html

Steps involved

The following steps are required to achieve what we said.
  1. Define REST API
  2. Transform request REST data into SOAP data
  3. Call the back end application / URL
  4. Transform response SOAP data into REST data (for example JSON)
  5. Respond with JSON response

Sample use case - Student Exam Result Service


Usecase overview

We will implement a simple use case - student exam results application. The organisation has the SOAP service already running in the premise that will take student id as input parameter and responds with marks for four subjects.

Sample request SOAP message:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:stud="http://www.example.org/student/">
   <soapenv:Header/>
   <soapenv:Body>
      <stud:getMarks>
         <student>John Smith</student>
      </stud:getMarks>
   </soapenv:Body>
</soapenv:Envelope>

Sample response message:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:stud="http://www.example.org/student/">
   <soapenv:Header/>
   <soapenv:Body>
      <stud:getMarksResponse>
         <marks>
            <Mathematics>95</Mathematics>
            <Science>97</Science>
            <Lang-I>92</Lang-I>
            <Lang-II>94</Lang-II>
         </marks>
      </stud:getMarksResponse>
   </soapenv:Body>
</soapenv:Envelope>

WSDL:
<wsdl:definitions name="Student" targetNamespace="http://www.example.org/student/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.example.org/student/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <wsdl:types>
      <xsd:schema targetNamespace="http://www.example.org/student/">
         <xsd:element name="getMarks">
            <xsd:complexType>
               <xsd:sequence>
                  <xsd:element name="student" type="xsd:string"/>
               </xsd:sequence>
            </xsd:complexType>
         </xsd:element>
         <xsd:element name="getMarksResponse">
            <xsd:complexType>
               <xsd:sequence>
                  <xsd:element name="marks" type="tns:Marks"/>
               </xsd:sequence>
            </xsd:complexType>
         </xsd:element>
         <xsd:complexType name="Marks">
            <xsd:sequence>
               <xsd:element name="Mathematics" type="xsd:int"/>
               <xsd:element name="Science" type="xsd:int"/>
               <xsd:element name="Lang-I" type="xsd:int"/>
               <xsd:element name="Lang-II" type="xsd:int"/>
            </xsd:sequence>
         </xsd:complexType>
      </xsd:schema>
   </wsdl:types>
   <wsdl:message name="getMarksRequest">
      <wsdl:part element="tns:getMarks" name="parameters"/>
   </wsdl:message>
   <wsdl:message name="getMarksResponse">
      <wsdl:part element="tns:getMarksResponse" name="parameters"/>
   </wsdl:message>
   <wsdl:portType name="Student">
      <wsdl:operation name="getMarks">
         <wsdl:input message="tns:getMarksRequest"/>
         <wsdl:output message="tns:getMarksResponse"/>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name="StudentSOAP" type="tns:Student">
      <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="getMarks">
         <soap:operation soapAction="http://www.example.org/student/getMarks"/>
         <wsdl:input>
            <soap:body use="literal"/>
         </wsdl:input>
         <wsdl:output>
            <soap:body use="literal"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name="Student">
      <wsdl:port binding="tns:StudentSOAP" name="StudentSOAP">
         <soap:address location="http://www.example.org/"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>

Now, lets do some hands on in WSO2 ESB.

1. Define REST API

In WSO2 ESB Management Console, goto Main --> Service Bus --> API and create a new API. The steps are very clearly mentioned in the WSO2 documentation site https://docs.wso2.com/display/ESB480/Getting+Started+with+REST+APIs how to create API. 


The API definition will look like this.

<api xmlns="http://ws.apache.org/ns/synapse"
     name="StudentAPI"
     context="/exam-results">
   <resource methods="GET" uri-template="/student/{student}" >

<inSequence> </inSequence>
<outSequence> </outSequence>
</resources>
</api>

This will provide a REST GET url like this http://localhost:8280/exam-results/student/1002 where 1002 is the student id for which we need the marks scored in four subjects. The URL may directly be accessed from a browser for instance.

2. Transform request REST data into SOAP data

Use Payload Mediator to transform REST data into SOAP data

         <payloadFactory media-type="xml">
            <format>
               <stud:getMarks xmlns:stud="http://www.example.org/student/">
                  <student>$1</student>
               </stud:getMarks>
            </format>
            <args>
               <arg evaluator="xml" expression="get-property('uri.var.student')"/>
            </args>
         </payloadFactory>

3. Call the back end application / URL

Set Action property and configure the SOAP end point URL

         <header name="Action" value="http://www.example.org/student/getMarks"/>
     <send>
            <endpoint>
<address uri="http://localhost:8088/services/Student" format="soap11"/>
            </endpoint>
         </send>

4. Transform response SOAP data into REST data (for example JSON)

Now, you will get the response in SOAP format. Use Payload Mediator to transform into REST data i.e., JSON

         <payloadFactory media-type="json">
            <format>{"Language_1": "$1", "Language_2": "$2", "Maths": "$3", "Science": "$4"}</format>
            <args>
               <arg xmlns:stud="http://www.example.org/student/"
                    evaluator="xml"
                    expression="$body/stud:getMarksResponse/marks/Lang-I"/>
               <arg xmlns:stud="http://www.example.org/student/"
                    evaluator="xml"
                    expression="$body/stud:getMarksResponse/marks/Lang-II"/>
               <arg xmlns:stud="http://www.example.org/student/"
                    evaluator="xml"
                    expression="$body/stud:getMarksResponse/marks/Mathematics"/>
               <arg xmlns:stud="http://www.example.org/student/"
                    evaluator="xml"
                    expression="$body/stud:getMarksResponse/marks/Science"/>
            </args>
         </payloadFactory>

5. Respond with JSON response


Change the response type to JSON and send the response to REST client

         <property name="messageType" value="application/json" scope="axis2"/>
         <send/>









When you execute, the output will look like
{
  "Language_1": "92",
  "Language_2": "94",
  "Maths": "95",
  "Science": "97"
}

See below the complete API definition

<?xml version="1.0" encoding="UTF-8"?>
<api xmlns="http://ws.apache.org/ns/synapse"
     name="StudentAPI"
     context="/exam-results">
   <resource methods="GET" uri-template="/student/{student}">
      <inSequence>
         <log level="custom">
            <property name="student_name_##########"
                      expression="get-property('uri.var.student')"/>
         </log>
         <payloadFactory media-type="xml">
            <format>
               <stud:getMarks xmlns:stud="http://www.example.org/student/">
                  <student>$1</student>
               </stud:getMarks>
            </format>
            <args>
               <arg evaluator="xml" expression="get-property('uri.var.student')"/>
            </args>
         </payloadFactory>
         <header name="Action" value="http://www.example.org/student/getMarks"/>
         <property name="Accept-Encoding" scope="transport" action="remove"/>
         <log level="custom">
            <property name="#body" expression="$body/*"/>
         </log>
         <send>
            <endpoint>
               <address uri="http://localhost:8088/services/Student" format="soap11"/>
            </endpoint>
         </send>
      </inSequence>
      <outSequence>
         <log level="custom">
            <property name="#response-body-from-Backend" expression="$body/*"/>
         </log>
         <payloadFactory media-type="json">
            <format>{"Language_1": "$1", "Language_2": "$2", "Maths": "$3", "Science": "$4"}</format>
            <args>
               <arg xmlns:stud="http://www.example.org/student/"
                    evaluator="xml"
                    expression="$body/stud:getMarksResponse/marks/Lang-I"/>
               <arg xmlns:stud="http://www.example.org/student/"
                    evaluator="xml"
                    expression="$body/stud:getMarksResponse/marks/Lang-II"/>
               <arg xmlns:stud="http://www.example.org/student/"
                    evaluator="xml"
                    expression="$body/stud:getMarksResponse/marks/Mathematics"/>
               <arg xmlns:stud="http://www.example.org/student/"
                    evaluator="xml"
                    expression="$body/stud:getMarksResponse/marks/Science"/>
            </args>
         </payloadFactory>
         <property name="messageType" value="application/json" scope="axis2"/>
         <log level="custom">
            <property name="#body" expression="$body/*"/>
         </log>
         <send/>
      </outSequence>
   </resource>
</api>

Hope this is useful to you. Please let me know if any further help.

Wednesday, 14 October 2015

Enable TLS in Standalone Java to connect to WSO2 IS

Some days ago, I wrote a blog on how to disable SSL and enable TLS in WebLogic application server. The link is here if you are interested to read further http://ayyappan-gandhirajan.blogspot.in/2015/09/enable-tls-security-in-weblogic-n-WSO2-IS.html

My colleague has approached me today to know how to do the same thing in a Core Java environment - I mean he is running a standalone program which uses HttpURLConnection to connect to HTTPS URL (which is hosted in WSO2 Identity Server, available at http://wso2.com/products/identity-server/)

After spending some time, I found a way to do this which has been described below:

1. Add JVM argument -Dhttps.protocols=TLSv1 on the client side

2. Or add this line into your the jave program - java.lang.System.setProperty("https.protocols", "TLSv1");

He just added JVM argument, and now he is able to connect the HTTPS URL without any issue.

Hope you like it.

Wednesday, 30 September 2015

Enable TLS security in Weblogic Application server to avoid "Read channel closed" error

Some host servers have been configured "not" to use SSL v1, v2 and v3 protocols for security reasons. Instead, they have been configured to use TLS protocol to ensure more secure HTTPS traffic.

Recently, I faced an issue with using SSL. My WebLogic application server had to connect to WSO2 Identity Server (http://wso2.com/products/identity-server/) for getting access token (https://docs.wso2.com/display/IS500/OpenID+Connect+with+the+WSO2+Identity+Server+and+WSO2+OAuth2+Playground) using an HTTPS URL. However, I was initially getting error "Read channel closed" on the WebLogic side. There was no other useful information. My other colleague, who takes care of WSO2 IS, troubleshooted and found that SSL has been disabled on the WSO2 IS server. This gave me a clue and then finally found the following option to make WebLogic to use TLS rather than SSL for initiating HTTPS traffic.

Pass this JVM argument -Dweblogic.security.SSL.protocolVersion=TLS1 into your WebLogic application server start up script. Restart the server and it is DONE.

With the above, my WebLogic server is now able to connect to WSO2 IS using HTTPS protocol.

Hope this helps.


Wednesday, 15 April 2015

How to find out character set in Oracle database

There is a simple SQL Query which can be used to find out the character set used in Oracle database

select * from nls_database_parameters where parameter='NLS_CHARACTERSET';

When I executed this, I got this below.

NLS_CHARACTERSET    AR8MSWIN1256

Wednesday, 31 December 2014

Configuring proper roles to access ActiveVOS console using standard alone server

ActiveVOS serve that is embedded with designer does not have any login screen and by default you will be able to access the console that shows up dashboards, monitor, catalog and other features. But when you install ActiveVOS server as stand alone, you need to configure the server with
proper user and roles. Otherwise, you would not be able to access your http://localhost:8080/activevos page.

If you are familiar with Tomcat, you can add "admin" as user and role. Now you would be able to login as admin user. But you can't still see any contents as you do not have necessary privilege. You need to add these roles again your "admin" user to see proper contents of ActiveVOS console page.

For your reference, I am pasting contents from ActiveVOS site.

1) tomcat\conf\server.xml (file-based configuration)
<Realm className= "org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>


2) tomcat\conf\tomcat-users.xml file:

<role rolename="abTaskClient"/>
<role rolename="abServiceConsumer"/>
<role rolename="abAdmin"/>
<user username="admin" password="admin" roles="abAdmin, abTaskClient, abServiceConsumer"/>


 For further read, please follow this http://infocenter.activevos.com/infocenter/ActiveVOS/v92/index.jsp?topic=/doc.server_userguide/html/SvrUG3-4.html