SOA Suite 11g doesn't provide an out of box way to call JSON based REST
services. In this blog we shall the alternative options to achieve the same.
HTTP binding in SOA
Suite 11g has ability to make calls to endpoints based on
HTTP verbs(GET, POST only) in request-response (or) one way modes as depicted
below.
However Oracle's Documentation states that -"An outbound HTTP binding reference supports only XML
as a response from an external HTTP endpoint. The response should contain the
correct XML part name according to outbound expectations."
In
other words Http binding supports only XML as output for either
GET/POST. For input it supports only url-encoded and xml. Though the
url-encoded input has to be expressed/defined in an xsd format as shown below.
Another
major hindrance is that - Majority of the REST services created in IT
world use JSON rather than XML as their messaging standard dues to its light
weight and simplicity ( the same reason to use REST as against SOAP). HTTP
adapter/binding has no support for calling REST endpoints which use JSON
as a message standard as against XML.
Does this leave us no
way to call REST services using JSON ? Well not really. We always have Java to
fall back on to do something that can't be done ( or provided) in SOA Suite.
The below Java code can be used to call REST service using JSON. The input of
the methods is an xml format represented in a string ( to make it easier to
interact with bpel). The following are the key points of this code
a. Takes input in XML string format.
b. Converts the XML
string to JSON object.
c. Creates a
HTTPClient and makes a call to post/get method using the REST URI providing the
required basic http authentication credentials.
d. Extra code to
bypass the SSL layer ( only to be used in dev mode). In production one should
import the right certificates to authenticate themselves.
RestService.java
package oracle.soa.rest;
import java.io.BufferedReader;
import
java.io.IOException;
import
java.io.InputStreamReader;
import org.apache.http.HttpResponse;
import
org.apache.http.client.ClientProtocolException;
import
org.apache.http.client.methods.HttpPost;
import
org.apache.http.entity.StringEntity;
import
org.apache.http.impl.client.DefaultHttpClient;
import net.sf.json.JSON;
import
net.sf.json.xml.XMLSerializer;
import org.apache.http.auth.AuthScope;
import
org.apache.http.auth.Credentials;
import
org.apache.http.auth.UsernamePasswordCredentials;
import
org.apache.http.client.methods.HttpGet;
public class RestService
{
public
HttpResponse callPOSTService(String xmlStr,String url) throws
ClientProtocolException, IOException
{
// Convert
the input XML to the JSON String
XMLSerializer xmlSerializer = new
XMLSerializer();
JSON json = xmlSerializer.read(xmlStr);
System.out.println(json);
// Call POST of REST Service with JSON input
DefaultHttpClient client = new DefaultHttpClient();
client =
WebClientDevWrapper.wrapClient(client);
Credentials creds = new UsernamePasswordCredentials("username",
"password");
client.getCredentialsProvider().setCredentials( new
AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), creds);
HttpPost post = new HttpPost(url);
StringEntity se = new StringEntity(
json.toString());
post.setEntity(se);
HttpResponse response =
client.execute(post);
return response;
}
public
HttpResponse callGETService(String url) throws ClientProtocolException,
IOException
{
// Call GET of
REST Service
DefaultHttpClient client = new DefaultHttpClient();
client =
WebClientDevWrapper.wrapClient(client);
Credentials creds = new UsernamePasswordCredentials("username",
"password");
client.getCredentialsProvider().setCredentials( new
AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), creds);
HttpGet get = new HttpGet(url);
HttpResponse
response = client.execute(get);
return response;
}
public static void main(String[] args) throws
ClientProtocolException, IOException
{
RestService rs = new RestService();
/*
String inputString="<?xml version=\"1.0\"
encoding=\"UTF-8\"?>\n" +
"<root>\n" +
" <description>Product New
one</description>\n" +
" <sku>146-4100-901</sku>\n" +
"</root>";
// Create the product with SKU mentioned above.
HttpResponse response =
rs.callPOSTService(inputString,"https://abc.com/api/v1/products");
// Get the URL to update the product - Eg:
"https://abc.com/api/v1/products/18"
Header header = response.getFirstHeader("Location");
String update_url=header.toString().substring(10);
System.out.println(update_url);*/
/* // Update the product
String updatedinputString="<?xml version=\"1.0\"
encoding=\"UTF-8\"?>\n" +
"<root>\n" +
" <description>Update Product New
one</description>\n" +
" <family>Items</family>\n" +
"</root>";
System.out.println(rs.callIPOSTService(updatedinputString,"https://abc.com/api/v1/products/22"));
*/
// Get Product
HttpResponse response =
rs.callGETService("https://abc.com/api/v1/products/22");
String xmlResponse = "";
BufferedReader rd = new BufferedReader (new
InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
xmlResponse+=line;
}
System.out.println(xmlResponse);
}
}
WebClientDevWrapper.java - Used to bypass the SSL
package oracle.soa.rest;
import java.io.IOException;
import java.security.cert.CertificateException;
import
java.security.cert.X509Certificate;
import
javax.net.ssl.SSLContext;
import
javax.net.ssl.SSLException;
import
javax.net.ssl.SSLSession;
import
javax.net.ssl.SSLSocket;
import
javax.net.ssl.TrustManager;
import
javax.net.ssl.X509TrustManager;
import
org.apache.http.conn.ClientConnectionManager;
import
org.apache.http.conn.scheme.Scheme;
import
org.apache.http.conn.scheme.SchemeRegistry;
import
org.apache.http.conn.ssl.SSLSocketFactory;
import
org.apache.http.conn.ssl.X509HostnameVerifier;
import
org.apache.http.impl.client.DefaultHttpClient;
/*
*/
public class
WebClientDevWrapper {
public static DefaultHttpClient wrapClient(DefaultHttpClient
base) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public void
checkClientTrusted(X509Certificate[] xcs,
String
string) throws CertificateException {
}
public void
checkServerTrusted(X509Certificate[] xcs,
String
string) throws CertificateException {
}
public
X509Certificate[] getAcceptedIssuers() {
return null;
}
};
X509HostnameVerifier verifier = new X509HostnameVerifier()
{
@Override
public void verify(String string,
SSLSocket ssls) throws IOException {
}
@Override
public void verify(String string,
X509Certificate xc) throws SSLException {
}
@Override
public void verify(String string, String[]
strings,
String[] strings1) throws SSLException {
}
@Override
public boolean verify(String string,
SSLSession ssls) {
return true;
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ssf.setHostnameVerifier(verifier);
ClientConnectionManager ccm = base.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", ssf, 443));
return new DefaultHttpClient(ccm, base.getParams());
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}
The
following are the libraries added to the class path:
I googled and found all of these in the net and added to
the class path.
The main() method
provides a way to
1. perform GET to
retrieve the records using the URL
2. perform POST to
create.
3. perform POST to
update.
The Java code can be
called via a BPEL/Mediator component using Java Embedding ( or more cleaner way
by using a Spring component). The code in main method could replace the most of
the code in the Java embedding. Most importantly we need to create an XML
schema containing the request/response in accordance to the JSON
request/response schema of the REST URI.
Eg : In JSON
{
"sku":"130-01-099",
"description":"Test"
}
equivalent XML for
the same
<?xml
version="1.0" encoding="UTF-8" ?>
<root>
<sku>130-01-099</sku>
<description>Test</description>
</root>
You could use the
following tool for this conversion
- http://www.utilities-online.info/xmltojson/#.U9_NevldWAg
You can create an XSD
based on the above XML and accordingly use it in the BPEL process to call the
Java embedding code/Spring Context component that calls REST service using JSON
messaging standard.
Conclusion:
While Oracle SOA
Suite 12c provides an out of box solution for interacting with REST services
with JSON data standard using HTTPAdapter, 11g still need to seek the help of
Java code to achieve the same. The way of creating a Java class that
takes XML as input ,converting it to an equivalent JSON and then calling
REST service using JSON ,provides us an interoperability between SOA suite
components those primarily still rely on XML messaging with REST services
relying on JSON.