While researching for the Oracle SOA Suite 11g Handbook, I wanted to take a quick look at REST(ful) WebServices and see how those can be integrated into the SCA based SOA Composite Applications that we create with the Oracle SOA Suite. Currently, it does not have the HTTP binding that the 10.1.3 release of the SOA Suite used to have. So what are the alternatives? But first, how does one call a simple HTTP only (no SOAP/WS*) service from a piece of Java code? With as little programming and as much framework lifting as possible.
One of the frameworks available for RESTful operations is Jersey – a framework that should be more REST aware than plain HTTP communication oriented libraries like Apache HTTP Client, as well as offer some support for typical formats used in RESTful interactions, such as JSON, XML, RSS, CSV. So let’s create the simples Java application consuming a RESTful service – the Google Translation service – using the Jersey library.
The first steps are quite simple. A small test of the Google Translation API described at http://code.google.com/apis/ajaxlanguage/documentation/ and to be accessed at http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=hello%20world&langpair=en%7Cit. This service takes a string to translate and an indication of a source and a destination language. Though maybe not formally resource oriented enough to be called REST-style (or RESTful) service by some, it is a service that does not require SOAP or WS* but simply a HTTP Get request. So at least quite restful.
Calling this service can be done through ordinary means with a little bit of programming effort, or using frameworks – with a bit of configuration and Googling for examples.
I decide to use the Jersey framework, the Client part of the framework that is. Note that Jersey is frequently used to expose RESTful services – and that it also support the client, consumer end of things. That is the part I use in this article.
1. Download Jersey libraries
I browsed to https://jersey.dev.java.net/nonav/documentation/latest/user-guide.html#chapter_deps and downloaded jersey-archive-1.1.4.1.zip file. I extracted several libraries from that file to add to my project: jersey-client.jar, jersey-core.jar and jsr311-api.jar.
2. Create a Java class to access the Google service using Jersey and print the translation result to the console:
package nl.amis.restclient; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.config.DefaultClientConfig; import com.sun.jersey.core.util.MultivaluedMapImpl; import javax.ws.rs.core.MultivaluedMap; public class TranslationClient { private static String googleTranslationService = "http://ajax.googleapis.com/ajax/services/language"; private static String translateString(String sourceString, String sourceLanguage, String targetLanguage) { ClientConfig config = new DefaultClientConfig(); Client c = Client.create(config); WebResource r = c.resource(googleTranslationService); MultivaluedMap<String, String> params = new MultivaluedMapImpl(); params.add("v", "1.0"); params.add("q", sourceString); // string to translate params.add("langpair", sourceLanguage+"|"+targetLanguage); // translation pair: from language and to language String response = r.path("translate").queryParams(params).get(String.class); return response; } public static void main(String[] args) { String response = translateString("hello world", "en", "it"); System.out.println(response); } }
Running this class produces the following output in the console:
{"responseData": {"translatedText":"ciao a tutti"}, "responseDetails": null, "responseStatus": 200} Process exited with exit code 0.
Now I would like to have this JSON object parsed and turned into a proper Java object structure. It seems that the Jersey Client has support for this. And I really tried to find out how to make it work. I added the jersey-json-1.1.4.1.jar library. I added JAXB support to the project. I have created the DefaultConfiguration and added a JAXBContextResolver.class. I tried some JAXB annotations, I tried to a introduce a ResponseData class to morph the JSON response into. I tried to discover how to create a MessageProvider or a MessageBodyWriter. I failed. I could not get it to work. The Jersey documentation failed me. And Google did so too.
So I decided to go for an easier solution: using the JSON-SIMPLE library it turned out quite simple to create a JSON object and access the translation result in a structured way.
1. Download the JSON-SIMPLE library from http://code.google.com/p/json-simple/ and copy json_simple-1.1.jar to my project.
2. Create a method that parses/inspects/retrieves from the JSON object created from the response from the Google Service:
private static String extractTranslationFromJSON(String response) { final JSONObject jsonObj = (JSONObject)JSONValue.parse(response); String translation=null; if (jsonObj != null && jsonObj.containsKey("responseData")) { final JSONObject responseData = (JSONObject)jsonObj.get("responseData"); translation= responseData.get("translatedText").toString(); } return translation; }
3. Update the main method to leverage this new method:
public static void main(String[] args) { String response = translateString("hello world", "en", "it"); System.out.println(response); System.out.println(extractTranslationFromJSON(response)); System.out.println(extractTranslationFromJSON(translateString("hello world", "en", "de"))); System.out.println(extractTranslationFromJSON(translateString("hello world", "en", "fr"))); System.out.println(extractTranslationFromJSON(translateString("hello world", "en", "es"))); System.out.println(extractTranslationFromJSON(translateString("hello world", "en", "fi"))); }
4. Run the class. Here is the output from the console:
{"responseData": {"translatedText":"ciao a tutti"}, "responseDetails": null, "responseStatus": 200} ciao a tutti Hallo Welt Bonjour tout le monde hola mundo Hei maailma Process exited with exit code 0.
Conclusion
Using Jersey libraries, it is quite simple to make the HTTP requests required for accessing RESTful services. To process the reply from the service, I had a hard time leveraging the JSON support Jersey supposedly provides. Instead, I turned to JSON-SIMPLE. Given the simple, small and straightforward structure of the JSON response this will do for now. For a more complex service response, a mapping from JSON to a POJO structure would be nice.
Resources
Project sources: JerseyRestClient.zip.
Google Translation Service – documentation
Getting started with Jersey – https://jersey.dev.java.net/use/getting-started.html
Jersey Home page (for downloading software)
Consuming RESTful services using Jersey Client
Configuring Jersey Client for JSON
Using JSON Parser to interpret response (rather than Jersey mapping JSON via JAXB
JSON-SIMPLE project on Google Code – encode/decode JSON messages
Calling RESTful service without Jersey
Note: the non-Jersey based client for the RESTful service could be as simple (and messy) as:
package nl.amis.soasuite11g.mediator; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; public class SimpleHttpRequest { // based on http://digiassn.blogspot.com/2008/10/java-simple-httpurlconnection-example.html private static String googleTranslationService = "http://ajax.googleapis.com/ajax/services/language/translate"; /** * @param args */ public static void main(String[] args) { HttpURLConnection connection = null; OutputStreamWriter wr = null; BufferedReader rd = null; StringBuilder sb = null; String line = null; URL serverAddress = null; try { serverAddress = new URL(googleTranslationService +"?v=1.0&&q=hello%20world&&langpair=en%7Cit"); //set up out communications stuff connection = null; //Set up the initial connection connection = (HttpURLConnection)serverAddress.openConnection(); connection.setRequestMethod("GET"); connection.setDoOutput(true); connection.setReadTimeout(10000); connection.connect(); //get the output stream writer and write the output to the server //not needed in this example //wr = new OutputStreamWriter(connection.getOutputStream()); //wr.write(""); //wr.flush(); //read the result from the server rd = new BufferedReader(new InputStreamReader(connection.getInputStream())); sb = new StringBuilder(); while ((line = rd.readLine()) != null) { sb.append(line + '\n'); } System.out.println(sb.toString()); } catch (MalformedURLException e) { e.printStackTrace(); } catch (ProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { //close the connection, set all objects to null connection.disconnect(); rd = null; sb = null; wr = null; connection = null; } } }
Hi Karl-Petter,
Thanks for your comment.
kind regards,
Lucas
Hi,
stumbled upon this when I just tried to get a simple REST client to work. After lots of frustration yesterday I managed to get it to work today. The main issue, which I never understood from the error logs was that I didnt had correct libs loaded. But today I realized that and also discovered a documentation error on the Jersey sight. Firstly I just included only those required by JSON but realized that was just a subchapter of requirements for JAXB http://jersey.java.net/nonav/documentation/latest/chapter_deps.html#d4e1736 but in the list of jars needed one from Jackson was missing which I realized when reading this page http://wiki.fasterxml.com/JacksonDownload
This post is a couple of years old but was good and helped me except the last steps so I hope my comment here can help someone discovering this later!
/Karl-Petter
Check this short tutorial here:
http://sportechno.wordpress.com/2011/08/09/creating-a-restful-web-services-using-jersey/