JSON-RPC Bridge to XML Web Services and usage in Objective-C in iPhone

For me, the main problem about SOAP Web Servicess that they are using XML technology which is useless for both ajax and mobile programming (such as Obj-C and J2ME). I don’t compare JSON and XML in this post, i just like JSON more…

For 2 years XML Web services have not been problem for me because Java handles SOAP web services really good. On the other hand, i really used to get mad when i was using SOAP Web Services via Java Mobile (J2ME). But the idea of converting SOAP Web Services to JSON had never came up.

When i try to write a cocoa application for iPhone which has to use a SOAP Web Service to get the data on air, i totally get insane :). If you want to know how bad is, try to visit these site : iPhone Programming Tutorial : Intro To Soap Web Services (or Turkish version : iPhone ile Web Service Kullanımı)

Thankfully there is a JSON RPC supported by oss.metaparadigm for Java web applications. You can find the details of this library here. I will tell you how easy to build a JSON Bridge to your existing SOAP Web Services and use this bridge to get data from service in iPhone application development.

We Need,

A Java Servlet container like Sun’s GlassFish Server which i use. ( There are plenty servlet containers for J2EE. I assume that you have basic knowledge of web applications in Java)

Than of course we need Sun’s IDE for Java; Java Web and EE enabled Netbeans

JSON-RPC library (Also we need jsonrpc.js for testing JSON service at Web Browser. You do not need this file to implement iPhone application)

For the iPhone development part, we do not need anything to connect to the service and get data back. But in this post i will use ASIHTTPRequest open source connection library to connect to JSON-RPC service (Thanks to Umut GÖKBAYRAK let me know this brilliant connection library) and JSON Cocoa Framework to create and parse JSON data. ( I am not even mentioning about how you can develop iPhone applications :D )

Prepare Java Class,

In this example we use w3school’s test web service

http://www.w3schools.com/webservices/tempconvert.asmx?WSDL

We can see methods when we go http://www.w3schools.com/webservices/tempconvert.asmx via web browser.

TempConvert Web Service

First we create Java Web Application project in netbeans. We call it, TempConvertBridge.

Then we create a web service from WSDL under New menu. We create this Web Service because Netbeans automatically generates Web Service Client for this application and also creates a new Web Service and includes all methods described in WSDL document. So we can grab every methods for class to register to JSON-RPC.

Lets call this Web Service name BridgeService and you have to paste Web Service WSDL address.

Web Service from WSDL Settings

Lets create a new Java Class named; Bridge. This process is not needed so importantly but if we create a new bridge, we can add or edit something on this bridge after data comes from Web Service.

Under created Web Service from WSDL TempConvert copy all methods and paste into class Bridge.

    public java.lang.String fahrenheitToCelsius(java.lang.String fahrenheit) {
        //TODO implement this method
        throw new UnsupportedOperationException("Not implemented yet.");
    }
 
    public java.lang.String celsiusToFahrenheit(java.lang.String celsius) {
        //TODO implement this method
        throw new UnsupportedOperationException("Not implemented yet.");
    }

You can see  every method created to throw an exception UnsupportedOperationException(“Not implemented yet.”); So we have to implement :). We add web service connection to our class Bridge. The Class would be like :

public class Bridge {
 
    private org.tempuri.TempConvertSoap service = (new org.tempuri.TempConvert()).getTempConvertSoap();
 
    public java.lang.String fahrenheitToCelsius(java.lang.String fahrenheit) {
        return service.fahrenheitToCelsius(fahrenheit);
    }
 
    public java.lang.String celsiusToFahrenheit(java.lang.String celsius) {
        return service.celsiusToFahrenheit(celsius);
    }
}

We created a class represents to return data of Web Service. Now we are ready to implement JSON-RPC.

Add JSON-RPC to our project,

We also added json-rpc.jar to library in project, but we have to define com.metaparadigm.jsonrpc.JSONRPCServlet as a servlet to use as Java Bean. So we include this xml node as chid of web-app element in web.xml file of our project.

<servlet>
   <servlet-name>com.metaparadigm.jsonrpc.JSONRPCServlet</servlet-name>
   <servlet-class>com.metaparadigm.jsonrpc.JSONRPCServlet</servlet-class>
</servlet>
<servlet-mapping>
   <servlet-name>com.metaparadigm.jsonrpc.JSONRPCServlet</servlet-name>
   <url-pattern>/TempBridge</url-pattern>
</servlet-mapping>

Value of <url-pattern> element describes where we post and get JSON data at server. In this project we post data to http://localhost:8080/TempConvertBridge/TempBridge ( I am using local GlassFih server at port 8080)

As we prepared servlet JSONRPCServlet we have to register Bridge class to JSONRPCServlet as a session object. So we edit index.jsp page coded below:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
 
<jsp:useBean id="JSONRPCBridge" scope="session"
             class="com.metaparadigm.jsonrpc.JSONRPCBridge" />
<jsp:useBean id="bridge" scope="session"
             class="Services.Bridge" />
<% JSONRPCBridge.registerObject("bridge", bridge);%>
 
Registration Successful...

First content type of page is not important. You can leave the value as it is. And also page encoding.Then we add com.metaparadigm.jsonrpc.JSONRPCBridge and Services.Bridge as java beans. At last we register object bridge to JSONRPCBridge. I also added “Registration Successfull…” text to get some string ;)

This page is so vital that we have to register the object and let JSONRPCBridge to create methods to be used as it is.

JSON-RPC integration is ready to use in iPhone application. But lets go in deeply and test our JSON-RPC service via test jsp page.

Test Time,

Lets create a new jsp page called testBridge.jsp and includes ;

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
 
<jsp:useBean id="JSONRPCBridge" scope="session"
             class="com.metaparadigm.jsonrpc.JSONRPCBridge" />
<jsp:useBean id="bridge" scope="session"
             class="Services.Bridge" />
<% JSONRPCBridge.registerObject("bridge", bridge);%>
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
 
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
        <script type="text/javascript" src="jsonrpc.js"></script>
        <script type="text/javascript">
            function onLoad()
            {
                jsonrpc = new JSONRpcClient("TempBridge");
            }
 
            function convertToC()
            {
                var valNode = document.getElementById("val");
                var result = jsonrpc.bridge.fahrenheitToCelsius(valNode.value);
                alert(valNode.value + "F is : " + result + " C");
            }
 
            function convertToF()
            {
                var valNode = document.getElementById("val");
                var result = jsonrpc.bridge.celsiusToFahrenheit(valNode.value);
                alert(valNode.value + "C is : " + result + " F");
            }
 
        </script>
    </head>
    <body onload="onLoad();">
        <h1>TempConvert JSON RPC Test</h1>
        <input type="text" id="val" name="val" value="" />
        <input type="button" value="Convert to C" name="submit" onclick="convertToC();" />
        <input type="button" value="Convert to F" name="submit" onclick="convertToF();" />
    </body>
</html>

Lets run this file and see what happens with Firebug ultimate plug-in for Firefox. We can see what we post and get data when we press “Convert to C” and “Convert to F” buttons.

We Post,

JSON-RPC Posted Data

And we get,

JSON-RPC Returned Data

as a JSON data and i am very happy to see it :D So we can continue with implementing to iPhone Application.

At the Objective-C side,

As i said i used ASIHTTPRequest library to create connections. But first and again i want to say, we have to register Bridge class to JSONRPCBridge so we have to call index.jsp page once. But you have to remember that this registration is time limited by session timeout. If you develop an application exceeds this time limit, you have to connect index.jsp asynchronously at the backgound ;) This was the tip of the day :)

I create a DataHandler class in Xcode and i put first connection on constructor (init method) like;

- (id) init
{
	self = [super init];
	if (self != nil) {
		NSURL *url = [NSURL URLWithString:@"http://localhost:8080/TempConvertBridge/"];
		ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
		[request start];
		NSError *error = [request error];
		NSString *response;
		if (!error) {
			response = [request responseString];
			NSLog(response);
		} else {
			NSLog([error description]);
		}
	}
	return self;
}

We also check that if there is an error on this connection as NSError object. Lets prepare an async connection and self delegated method to convert Celsius to Fahrenheit.

- (IBAction) convertToC:(int)fValue
{
	NSURL *url = [NSURL URLWithString:@"http://localhost:8080/TempConvertBridge/TempBridge"];
	ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
	NSString *sendData = [NSString stringWithFormat:@"{\"id\": 2, \"method\": \"bridge.fahrenheitToCelsius\", \"params\": [ \"%d\" ]}", fValue];
	[request appendPostData:[sendData dataUsingEncoding:NSUTF8StringEncoding]];
	[request setRequestMethod:@"PUT"];
	[request setDelegate:self];
	[request setDidFinishSelector:@selector(requestDone:)];
	[request setDidFailSelector:@selector(requestWentWrong:)];
	[[self queue] addOperation:request];
}
 
- (void)requestDone:(ASIHTTPRequest *)request
{
	NSString *response = [request responseString];
	NSLog(@"message = %@", reponse);
}
 
- (void)requestWentWrong:(ASIHTTPRequest *)request
{
	NSError *error = [request error];
	NSLog(@"message = %@", [error description]);
}

We created a ASIHTTPRequest connection protocol to “http://localhost:8080/TempConvertBridge/TempBridge” .  We use ASIHTTPRequest by “PUT” method rather than POST method to avoid multi-part form data format. I used sendData as a string, but if you prefer you can create by JSON-Framework. That would be necessary in more complicated projects. We appended post data and defined the delegation class as self. If connection is ok and we can get data, the application will run requestDone method, else requestWentWrong will be fired. Both we can log and see what happens.

One last thing if we create a method called convertToC we have to get the result clearly. So lets use JSON-Framework to get result. We change requestDone like;

- (void)requestDone:(ASIHTTPRequest *)request
{
	NSString *response = [request responseString];
	SBJSON *parser = [[SBJSON alloc] init];
	NSDictionary *object = [parser objectWithString:response error:nil];
	NSLog(@"message = %@", [[object objectForKey:@"result"] description]);
}

I dont know if it is a good way for you to use SOAP Web Services via JSON-RPC Bridge, but this method saved me so much time rather than preparing SOAP Envelopes in Objective-C.

I hope you enjoy :)

PS. Java Web Application project can be found here TempConvertBridge Project

Be Sociable, Share!

15 thoughts on “JSON-RPC Bridge to XML Web Services and usage in Objective-C in iPhone”

  1. There is no native way to develop iPhone applications on Windows operating systems. Also you have a chance to install OS X to some pc emulator programs like Wmware. But iPhone simulator does not work properly and you can not connect to network with simulator and debugger as i know. On the other hand there will be licensing problems and so on. I suggest you to get a mac for developing iPhone applications. The best and easy way ;)

  2. i followed the steps as given in the link .
    now t gives me error “_inflate” referenced from:
    +[ASIHTTPRequest uncompressZippedData:] in ASIHTTPRequest.o
    +[ASIHTTPRequest uncompressZippedDataFronSource:toDestination:]

  3. Thanks a lot! Great help!

    When I test with js everything is ok, but to test this example from objective-c side I got
    {“id”:2,”error”:{“code”:591,”msg”:”method not found (session may have timed out)”}}
    Please help with this issue.

  4. You may get this error for following reasons;

    1. You send wrong or absent method name. Please take a look at firebug again to see exact method name. (it depends on what rpc framework you are using at server side. e.g com.packageName.methodName… )
    2. If session had timed out, you may follow my tip that i have written in post:
    “As i said i used ASIHTTPRequest library to create connections. But first and again i want to say, we have to register Bridge class to JSONRPCBridge so we have to call index.jsp page once. But you have to remember that this registration is time limited by session timeout. If you develop an application exceeds this time limit, you have to connect index.jsp asynchronously at the backgound”
    To do this, create a connection to call index.jsp when you open your application or before you try to call a method first time. You have to keep session alive.
    3. You send wrong parameters to method.

    I hope these will help you.

  5. If the method returns a primitive type or an object having only primitive type of fields, both in JavaScript and Objective-C side everything is OK. As non-primitive type of fields values gives only object reference. So I have to represent all data I need as a string, I get something like this:

    {“id”:2, “result”:”{\”id\”:1, \”mykey\”:\”my value\”}”}

    In JavaScript parsing of it is OK. But in Objective-C side I get an error, because I write the result in a json file:

    [request setDownloadDestinationPath:jsonFile];

    So it takes all backslashes before quotes.

    I don’t know what to do to resolve this problem.

  6. Managing changes to APIs is hard. That is no surprise to anyone who has ever maintained an API of any sort. Web services, being a special case of API, are susceptible to many of the difficulties around versioning as other types of APIs. For HTTP based REST style web services the combination of resources and content negotiation can be used to mitigate most of the issues surrounding API versioning.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>