Igor Kromin |   Consultant. Coder. Blogger. Tinkerer. Gamer.

NOTE: This article is 3 years or older so its information may no longer be relevant. Read on at your own discretion! Comments for this article have automatically been locked, refer to the FAQ for more details.
I've started exploring the use of Google AppEngine for a project I'm working on. JSON was one of the technologies that was going to be used and JSON-RPC looked like an attractive way of exposing functionality without writing your own server network code.

This is a simple project I've put together in Eclipse that uses the Google AppEngine Java SDK and JSON-RPC library to expose an 'echo' server.

These are the components/libraries needed to make it work:



The project is made up of the following files:
  • JsonRpcAppEngineTestServlet.java - The main servlet class, this is what the AppEngine runs
  • TestEchoServer.java - The echo server interface
  • TestEchoServerImpl.java - The echo server implementation
  • TestEchoClient.java - A client to connect to the echo server


The most important thing to do before starting is to put all the required libraries in the war/WEB-INF/lib directory, otherwise AppEngine will throw ClassDefNotFoundException exceptions. In addition to this, Eclipse needs to be configured with the same libraries for it's build path.

The JsonRpcAppEngineTestServlet.java code is:
package com.colorsin.jsonrpctest;
import java.io.IOException;
import javax.servlet.http.*;
import org.json.rpc.server.JsonRpcExecutor;
import org.json.rpc.server.JsonRpcServletTransport;
@SuppressWarnings("serial")
public class JsonRpcAppEngineTestServlet extends HttpServlet {
private JsonRpcExecutor executor;
@SuppressWarnings("unchecked")
public JsonRpcAppEngineTestServlet() {
executor = new JsonRpcExecutor();
TestEchoServer server = new TestEchoServerImpl();
executor.addHandler("echo", server, TestEchoServer.class);
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
executor.execute(new JsonRpcServletTransport(req, resp));
}
}


What this does is when the servlet is created, it instantiates a JSON-RPC executor and an instance of the echo server, then adds a handler to the executor with the echo server object as the handler. The handler is given the name 'echo', this will be needed in the client code later.

The servlet implements the doPost() method, which means it will respond to HTTP POST requests only. This is something to watch because a default AppsEngine project will create a servlet with the doGet() method only, which will cause the following exception when the client is run:
Exception in thread "main" org.json.rpc.commons.JsonRpcClientException:
unable to get data from transport
at org.json.rpc.client.JsonRpcInvoker.invoke(JsonRpcInvoker.java:91)
at org.json.rpc.client.JsonRpcInvoker.access$000(JsonRpcInvoker.java:37)
at org.json.rpc.client.JsonRpcInvoker$1.invoke(JsonRpcInvoker.java:60)
at com.sun.proxy.$Proxy0.echo(Unknown Source)
at com.colorsin.jsonrpctest.TestEchoClient.main(TestEchoClient.java:19)
Caused by: org.json.rpc.commons.JsonRpcClientException: unexpected status code returned : 405
at org.json.rpc.client.HttpJsonRpcClientTransport.post(HttpJsonRpcClientTransport.java:74)
at org.json.rpc.client.HttpJsonRpcClientTransport.call(HttpJsonRpcClientTransport.java:45)
at org.json.rpc.client.JsonRpcInvoker.invoke(JsonRpcInvoker.java:89)
... 4 more


The TestEchoServer.java code is:
package com.colorsin.jsonrpctest;
public interface TestEchoServer {
String echo(String message);
}


This interface defines the methods that the echo 'server' exposes. In this case it's a single method that takes in a String and returns another String.

The code TestEchoServerImpl.java is:
package com.colorsin.jsonrpctest;
import java.util.Date;
public class TestEchoServerImpl implements TestEchoServer {
@Override
public String echo(String message) {
return (new Date()).toString() + ": " + message;
}
}


This class implements the TestEchoServer interface. The implementation takes the message parameter that is passed into the method and returns a String with the current date prepended to the message.

The code TestEchoClient.java is:
package com.colorsin.jsonrpctest;
import java.net.MalformedURLException;
import java.net.URL;
import org.json.rpc.client.HttpJsonRpcClientTransport;
import org.json.rpc.client.JsonRpcInvoker;
public class TestEchoClient {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws MalformedURLException {
String url = "http://localhost:8888/jsonrpcappenginetest";
HttpJsonRpcClientTransport transport = new HttpJsonRpcClientTransport(new URL(url));
JsonRpcInvoker invoker = new JsonRpcInvoker();
TestEchoServer server = invoker.get(transport, "echo", TestEchoServer.class);
System.out.println(server.echo("Test message"));
}
}


The client code creates a HTTP JSON transport with the URL of the server. This URL is just the localhost (since I'm running this locally) with the servlet mapping URL pattern appended. This comes from the web.xml file in the project:
...
<servlet-mapping>
<servlet-name>JsonRpcAppEngineTest</servlet-name>
<url-pattern>/jsonrpcappenginetest</url-pattern>
</servlet-mapping>
...


Once the client has created the transport, it creates an invoker and generates a proxy object that implements the TestEchoServer interface also. This makes it seem like methods are being called on a local object, whereas in reality they are going over the network to the server that's been created.

Finally the client calls the 'server' object echo() method with a string "Test message".

Running the client produces the following:
Thu Mar 07 09:04:28 EST 2013: Test message


Adding new functionality to the server is as simple as adding a new method to the interface and implementing that method in the impl class!

-i

Skip down to comments...
Hope you found this post useful...

...so please read on! I love writing articles that provide beneficial information, tips and examples to my readers. All information on my blog is provided free of charge and I encourage you to share it as you wish. There is a small favour I ask in return however - engage in comments below, provide feedback, and if you see mistakes let me know.

If you want to show additional support and help me pay for web hosting and domain name registration, donations, no matter how small, are always welcome!

Use of any information contained in this blog post/article is subject to this disclaimer.
 
comments powered by Disqus
Other posts you may like...