Thursday, October 21, 2010

Client-server communication with JSON

A long time ago, XML was the emerging, fashionable technology. Those times have clearly passed and nowadays XML is just another boring piece of basic technology. If you want to be trendy, you have to go for something else. Luckily, there is a new in thing, JavaScript Object Notation, JSON. In this post, I show you a simple client-server application based on Android, JSON and Google App Engine.

JSON is based on JavaScript object literals and is a textual representation of complex data instances. It has 4 basic types: strings, numbers, booleans and null. Objects and arrays can be constructed out of these 4 types, object is really just the JSON slang for key-value pairs. The entire thing is specified in RFC 4627 so I stick to just some simple examples so that you have that JSON feeling if you don't want to read the RFC.

This is a JSON number: -4.7e12
This is another JSON number: 0
This is NOT a JSON number: 00012 (no leading zeros!)
This is a JSON string: "JSON"
This is another JSON string: "\u005C" (always 4 hexa digits after the \u, just one character, the \)
This is not a JSON string: 'notJSON'
These are JSON literals: true, false, null
This is a JSON array: [1,"hello",null]
This is a JSON array having two other JSON arrays as elements: [[1,"hello"],[2,"hallo"]]
This is a JSON object: {"a":1,"b":"hello"}
This is a JSON object having another object associated with "a" key and an array with "b" key:
{"a":{"aa":1,"bb":2},"b":[3,4]}

I think this is enough for starter because it is evident that JSON has quite powerful data structures. Arrays are equivalent of Lisp lists while objects can be represented as lists of dotted pairs.

How does JSON compare to the incumbent serialization standard, XML? JSON is fashionable in mobile communication because it is somewhat more bandwidth-efficient than XML. E.g. the last example can be written in (ugly) XML like this (XML tag mangling due to blog engine limitations):

[l]
[a]

[aa]1[/aa]

[bb]2[/bb]

[/a]

[b]

[k]3[/k]

[k]4[/k]
[/b]
[/l]

Not counting the white spaces, this is 58 characters while the JSON representation is just 32 characters, about 45% less. The situation is worse if we consider many "well-designed" XMLs out there (like e.g. SOAP documents) which are full of namespace declarations, long tag names, etc. JSON with its simple yet powerful syntax definitely has a space in mobile application design.

Click here to download the example program.

I will demonstrate the power of JSON with a simple client-server example application. This application is a batch-mode calculator. The user first enters operations on the device's UI. These operations are not calculated immediately. When the user selects the "Process list" menu item, the collected operations are sent to the server in one batch. The server calculates the operations that are sent back to the client which displays the results. As you might have guessed, the client and the server communicates with JSON data structures.



The client part needs to be deployed on Android emulator (let's start with the emulator, I will return to this) like usual. The server part, however, requires the Google App Engine SDK for Python. Download the SDK, edit server/ae_jsoncalcserver.sh so that it suits your directory layout then start the shell script (Windows users will have to turn this one-line shell script into a .bat file). If you access localhost:8080 with your browser, you get a short message that GET is not supported. If you get there, you installed the server part properly.

Now you can start the client on the emulator and you can start to play with it. The most interesting part is the process() method in JsonCalc.java. I structured the program so that the generation of JSON request and the parsing of the response is all there. The org.json package has been part of Android from the beginning and this package is really easy to use. For the server part, I used the simplejson JSON parser for Python.

The Android client logs the JSON requests and responses in the Android log (adb logcat). I represented the batch operation and its result as array of objects. Request and response objects have different keys.

Request example:
[{"op":2,"v1":2,"id":1,"v2":3.3},{"op":3,"v1":4,"id":2,"v2":6},{"op":4,"v1":6.6,"id":3,"v2":2.2}]

Response example:
[{"id": 1, "result": -1.2999999999999998}, {"id": 2, "result": 24}, {"id": 3, "result": 2.9999999999999996}]


In case you want to try it out on a real phone, you'd better deploy the server part on Google infrastructure. Then edit Config.java in the client source so that APP_BASE_URI points to your server's address and you are ready to go. When you recompile, make sure that you delete the client/bin/classes directory - chances are that javac will not notice your changes you made to Config.java because of its broken dependency resolution.

11 comments:

Chinmaya said...

My Url is: http://xyz/userLogin.html?json=[{"password":"123456789", "emailid":"ratheeshcp@xyz.com"}]

Response: {"login":{"loginmsg":"successful","userid":"3","user_type":"Admin"}}

for this I am writing code like this:

JSONArray elements = new JSONArray();
try {

JSONObject obj = new JSONObject();
obj.put("emailid", "ratheeshcp@xyz.com");
obj.put("password", "123456789");

elements.put(obj);

String request = elements.toString();
System.out.println(request);
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, REGISTRATION_TIMEOUT);
ConnManagerParams.setTimeout(params, REGISTRATION_TIMEOUT);
HttpPost post = new HttpPost( "http://xyz/userLogin.html?");
// post.addHeader( "Content-Type", "text/vnd.com.json.req" );
post.setEntity( new StringEntity(request) );
HttpResponse resp = httpClient.execute( post );
InputStream is = resp.getEntity().getContent();
BufferedReader br = new BufferedReader(new InputStreamReader(is));

String line = br.readLine();
System.out.println(line);

} catch( Exception ex ) {
ex.printStackTrace();
}
....................

When I am running this code I am getting


{"login":{"loginmsg":"The username or password you entered is incorrect."}}

as response


CAn Any One help me in that.


Thanks in Advance.

Chinmaya said...

Hi All

I am working on a project which requires httpRequest in the Form of JSOn and It Give Response in the JSON format

My Url is: http://xyz/userLogin.html?json=[{"password":"123456789", "emailid":"ratheeshcp@xyz.com"}]

Response: {"login":{"loginmsg":"successful","userid":"3","user_type":"Admin"}}

for this I am writing code like this:

JSONArray elements = new JSONArray();
try {

JSONObject obj = new JSONObject();
obj.put("emailid", "ratheeshcp@xyz.com");
obj.put("password", "123456789");

elements.put(obj);

String request = elements.toString();
System.out.println(request);
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, REGISTRATION_TIMEOUT);
ConnManagerParams.setTimeout(params, REGISTRATION_TIMEOUT);
HttpPost post = new HttpPost( "http://xyz/userLogin.html?");
// post.addHeader( "Content-Type", "text/vnd.com.json.req" );
post.setEntity( new StringEntity(request) );
HttpResponse resp = httpClient.execute( post );
InputStream is = resp.getEntity().getContent();
BufferedReader br = new BufferedReader(new InputStreamReader(is));

String line = br.readLine();
System.out.println(line);

} catch( Exception ex ) {
ex.printStackTrace();
}
....................

When I am running this code I am getting


{"login":{"loginmsg":"The username or password you entered is incorrect."}}

as response


Can Any One help me in that.

Gabor Paller said...

I can see two problems:

"[{"password":"123456789", "emailid":"ratheeshcp@xyz.com"}]"

This is a JSON array with 1 element (a JSON struct). I cannot see that JSON array in your code, only the JSON struct (that you should add to the array)

"post.setEntity( new StringEntity(request) ); "

It seemed to me that your JSON entity should be added as a GET parameter but here you created a POST request. Depending on the server, this may be wrong.

Also, if you indeed want to transfer JSON objects in GET requests, you need to URL encode them.

Chinmaya said...

Thanks Gabor Paller.

Can u modify the code for this in application so that I can get getter Idea.

Chinmaya said...

Now I have changed it to get type still its not working


JSONArray elements = new JSONArray();
JSONObject obj = new JSONObject();
obj.put("emailid", "ratheeshcp@xyz.com");
obj.put("password", "123456789");

elements.put(obj);

DefaultHttpClient httpClient = new DefaultHttpClient();

HttpGet get = new HttpGet( "http://xyz/userLogin.html");
HttpParams params = get.getParams();
params.setParameter("emailid", "ratheeshcp@xyz.com");
params.setParameter("password", "123456789");
HttpResponse resp = httpClient.execute( get );
InputStream is = resp.getEntity().getContent();
BufferedReader br = new BufferedReader(new InputStreamReader(is));

String line = br.readLine();
System.out.println(line);



Even if I am sending as url also it is not working

HttpGet get = new HttpGet("http://xyz/userLogin.html?json="+elements.toString());

Gabor Paller said...

Sorry, Chinmaya, I have no idea what went wrong. Could you maybe capture a succesful login (with e.g. wireshark) and compare it with whatever your android program produces?

Anthony said...

Gabor Paller,

Im trying to create a client-server application in which the mobile client sends GPS points to the server.

Resources on client-server methods for android are often very different to each other and was hoping to use your this post as some enlightenment.

However, after unzipping Eclipse does not notice the client directory as a project!

Any ideas ?

Thank you,
Anthony

Gabor Paller said...

Anthony, this project was not created with Eclipse. Use File/Import in Eclipse to import it into your workspace (or leave it as it is, you just need to type "ant" to compile it).

andry said...

very good tutorial and can hopefully help me in building json in the application that I created for this lecture. thank you

ET said...
This comment has been removed by the author.
panqnik said...

hey,

it was really a good read, thank you. lately, I've reversed client - server communication but in online game, would you mind to come and leave your comment? here is a link:

http://blog.szulak.org/dev/reversing-client-and-server-communication-in-tibia/

regards,
szulak