Implementing an RMI Framework using JSON2.0

farflungconvyancerSoftware and s/w Development

Dec 2, 2013 (3 years and 8 months ago)

93 views




Implementing an RMI Framework using JSON2.0


By: Nisrin Abou-Seido

Supervised by Dr. Anthony White
School of Computer Science


COMP 4905 Honours Project
Submitted in partial fulfillment of the requirements for the

Bachelor of Computer Science

at


Carleton University
Ottawa, Ontario
December 2012

2


ABSTRACT

Remote Method Invocation is frequently used in dist ributed systems in order to allow multiple
clients to interact on the same object located on a remote machine. Registries are used in order to
keep track of the objects available and allow a cli ent to locate a particular object/service using a
simple name. Currently the most commonly used objec t-oriented RMI framework is the default
Java RMI library which uses Java serialization. The y key issue here is that it cannot be used in a
system where not all machines are running on a JVM. This report outlines the design of a library
that effectively implements an RMI Registry which i nstead serializes the data using the JSON2
specification, allowing it to be adapted for use ou tside of the Java environment.




3

Table of Contents


Acknowledgements ....................................................................................................................................... 4
Project Description and Motivation .............................................................................................................. 5
Specific Project Objectives ........................................................................................................................... 5
Background Information ............................................................................................................................... 6
Project Design ............................................................................................................................................... 9
Class Diagrams ........................................................................................................................................... 10
Challenges and Design Decisions ............................................................................................................... 15
Testing ........................................................................................................................................................ 17
Results ......................................................................................................................................................... 19
Conclusions ................................................................................................................................................. 20
Contributions to the Field ....................................................................................................................... 20
Concepts Learned .................................................................................................................................... 20
Future Work: ........................................................................................................................................... 20
Bibliography ............................................................................................................................................... 21



4

Acknowledgements

I would like to sincerely thank Dr. Tony White for his supervision and guidance throughout this
project. His insightful advice was usually crucial for helping me get past problems and make
effective design decisions.



5

Project Description and Motivation

RMI, or Remote Method Invocation, is the concept of making a method call on an object that is
on a remote computer or running in a separate application. In Java, it is implemented with Java
Serialization and uses the classes in the java.rmi library. However, as Java serialized objects
cannot be read by other languages, that implementation is specific to Java applications  and the
protocol is not usable for applications that wish to communicate between programs not running
on a JVM.

There is currently no standard accepted method for using RMI outside of Java. One protocol that
would in some ways fulfill this requirements is CORBA but this standard has become obsolete in
recent years. The aim of this project is to implement a remote method invocation framework that
could theoretically be used with programs written outside of Java  and in particular, be used to
develop mobiles applications on Android or iOS.

To do this, the proposed serialization method is the JSON ( JavaScript Object Notation) protocol.
A more human-readable and flexible protocol that XML, this notation provides a way to serialize
an object into a string that can then be de-serialized by any other program.

This project will be implemented in Java because it is the language with which I am most
familiar and allows me to refer to the java.rmi library as reference.

Specific Project Objectives:
1) Create a set of classes that will allow a registry service to link the name of a service with
a reference to a remote object.
2) Using JSON as the serialization method, it should be possible to remotely invoke
methods on the objects stored in the registry.
3) Test the protocol by allowing a client to request a service and then call methods on it as if
it were a local object.

6

Background Information

The following section will describe and explain some of the technology and terminology relevant
to this project.

Java RMI


This technology was not used in this project but it is relevant as it was used as the model that I
would follow in creating a similar RMI service.

Remote Method Invocation in Java is a framework by which java-based applications can send
remote procedure calls in an object-oriented environment to other Java-based applications. The
framework allows the developer to create distributed applications that fulfill the transparency
requirement that it should appear, to the remote client, that they are accessing an object that is
local to them and has the same interface that it would have were it to be local.

Java RMI does this by providing a local dynamic proxy object through which all remote
communications with the actual remote object will be channelled. The general model is that there
is a server, a remote object and its stub and a client. The classes for this protocol are documented
in the Java API under the java.rmi tree.

The benefits to this API are that is simple, easy to use and useful for splitting up an application
into sub-servers running on different machines. The main drawback is that it only supports
distributed systems which run on a Java Virtual Machine as it relies on Java serialization.

Possible Extension:
In the Java.rmi framework there is a security manager system for ensuring that clients and
servers cannot be accessed remotely unless they have activated certain permissions. I did not
implement this aspect of RMI but it is a possible useful extension to this project.



7

Naming Services


A naming service, one example of which is the Java RMI Registry, is an application that serves
as a directory (also known as a dictionary, or a registry) for object references which can be
retrieved if the user knows the name that is bound to the object reference. Associating a name
with an object is called binding. Retrieving the object associated with a name is a lookup. A
name can only be used once in a particular registry/directory. In this project, creating a naming
service, which can be used to retrieve remote objects, is the main objective.

Reflection (in java.lang library)


The java reflection library is used in this project to return objects to the client as a proxy object.
The primary motivation for using reflection to return the object references is to ensure
transparency in the distributed system (i.e.: methods can be called on remote objects in the same
way that they are called on local objects)

JSON


JSON (JavaScript Object Notation) is a light-weight and human-readable format for serializing
data, including primitives, arrays and objects, into a simple string. JSON can represent four
primitive types (Strings, Numbers, Booleans and Null) and two structured types ( Arrays and
Numbers).

There are many open-source parsers for JSON available. The main ones for parsing JSON into
Java are Gson and Jackson. For this project, I chose to go with Gson as it seemed simple to use
and easy to extend to suit my particular requirements.






8

JSON-RPC 2.0


This is a protocol which specifies a standard for implementing remote procedure calls using
JSON to serialize request and response messages. It is described as being stateless and light-
weight as well as being language-agnostic. The types of messages that can be sent in this
specification are Requests, Responses, Errors, and Notifications. For more detail, refer to the
specification on the Json-Rpc 2.0 website [1].
Summary of specification:
Request consists of:
jsonrpc (2.0)
method (Stirng)
params, (Parameter structure: either by position as an Array or by name through an object)
id (String or Number)

Notification: same as a Response object, but without an id

Response consists of:
jsonrpc (2.0),
result (Object)
error ( Object)
id (String or Number)

Error consists of:
code (integer)
message (String)
data (may be omitted)

9

Project Design:

The design of this RMI framework was influenced by the standard Java RMI protocol. For
example, the LocateRegistry class is responsible for creating and returning the instance of the
naming service. In both java.rmi and in my framework, the following clsses exist:
LocateRegistry.java and Registry.java.

The following process is the one followed in Java.rmi and my project follows the same general
process as well:

1) RMI Registry is launched by server process

2) The server process creates an object and registers/binds the actual instance of the object
to the naming service under a logical name (registry.bind())

3) The client application request a stub from the server ( from the naming service) using the
known service name
a. a stub for the server object is created
b. the stub is serialized as part of the response
c. bytes are sent to the client application which uses them to create a new instance of
the server object which can be accessed by dynamic proxy



10

Class Diagrams:

RMIRequest

In Figure 1, the relationship between the serializing helper classes and the RMI Request object is
demonstrated. As shown in the diagram, the RMI Request was too complex to serialize using
GSONs default , so it was necessary to create a custom serializer and deserializer for it.



Figure 1: RMIRequest.java and related classes

A key component of implementing the JSON-RPC 2 specification was determining the best way
to represent an RPC request as an object that can be serialized to a Json2 string. The most

11

important design decision that was made in the implementation of this class was about how best
to represent the service name on which the request has been invoked. The JSON 2 specification
does not have a field for handling this, so I decided to implement a fairly straightforward
solution to this problem in the form of including the service name string as part of the ID string.
The advantage to this method is that it is simple and allows the request string to still conform to
the JsonRpc2 specification. Example ID String: BANK:1 where BANK is the service name,
: is the delimiter, and 1 is the actual id number of the request/response pair.

RMIResponse

This object is created by the registry when it receives a request for a remote method invocation.
Its fields follow the specification of Json-Rpc2. However, a few challenges were faced while
creating this object, the most significant of which was determining the best way to represent the
result parameter. At first, what I tried was to just serialize the actual object. Therefore, in the
RMIResponse object one of the fields was Object result.

The problem with this was that for deserializing, the Gson object expected a object type to
deserialize to, and only providing it with Object.class did not work.

The solution applied for this problem was to wrap the result in an object (ResultWrapper) that
would also include as a field the result objects type. This made it possible to successfully and
easily deseralize the result object regardless of its class. Many thanks go to Dr. White for
suggesting this solution to my problem.

As can be seen in Figure 2, the error parameter is also represented as a new object type, as
opposed to simply returning an Exception object. The Exception object would have been
insufficient to express the information specified in the Json-Rpc2.0 specification, which is that
an error object should consist of a code (from the integer range specified), a String defining the
message, and extra data about the message if pertinent. An enum was used to represent the
present error codes defined in the specification in order to make it easier to return those
particular errors.

12






Figure 2: RMIResponse.java and related classes



13

Registry and Related Classes

In the following class diagram ( Figure 3), the classes shown are the ones that are most important
for implementing the actual remote method invocation and handling requests and responses
between the clients and the server.


Figure 3: Registry.java and related classes

Registry:

The registry serves as the naming service and uses a Map object to link the service names with
the objects, so each name can only be associated with one object.

The methods in the Registry object are similar to those in the java.rmi librarys Registry object.
However, one key difference is that for this project I decided to create a method in the Registry
which would handle method calls. This method takes in an RMIRequest object and returns an

14

RMIResponse object. At this point the RegistryRequestListener would have already parsed the
JSON string and converted it into an actual object so it is more straightforward for the Registry
object to interpret it. The RegistryRequestListener is also responsible for converting the
RMIResponse object into a string and putting it on the socket stream for the client.

The method in the Registry that is responsible for handling method calls uses the information in
the RMIRequest to determine on which object to invoke the requested method. One design
decision that was made here was the decision to allow the registry to handle both its own method
calls (such as calls to lookup and bind) as well as those calls that are invoked on the objects it is
storing. This decision was made because, although it would have been possible to allow another
object to handle cases like lookup and bind requests it was just simpler to allow all of the method
calling and creating Response objects to be in one place.

RegistryRequestListener:
This object serves as something like an agent for the Registry object as it listens for Requests
on a particular socket and when a String arrives it parses it to send to the Registrys handle
method call procedure. It is also responsible for t aking the RMIResponse that the registry returns
and serializing it to a String in order to put it o n the object output stream.

RemoteClientInvocation:
This class is similar to that of the RMIRequest in that it listens on a socket, but it serves instead
as an agent for a client object. It creates a remot e proxy object when it returns a response to the
client.

15

Challenges and Design Decisions

Finding a JSON to Java parser that would be suitable for parsing JSON-RPC 2.0:

The parser chosen for converting json strings to ob jects and back again is Gson. It is one of the
most commonly used in Java applications.[2] One of the key reasons this parser was chosen over
Jackson ( another very popular JSON to Java convert er) is that , as the project originally intended
that this application be used in an Andoroid applic ation , a Google-based application seemed
more logical.

Googles JSON parser is a commonly used API for con verting to and from JSON strings and
regular Java objects. For simple conversion involvi ng only primitive variables, Gson is actually
very simple. However, as soon as the regular Java o bjects get too complex (especially if nested
or recursive) then it becomes necessary to create c ustom serializers and custom de-serializers for
the object. Therefore, any object that you wish to access remotely needs to only consist of
primitives  else you need to write a JsonSerialize r and JsonDeserializer for it.


Returning an object so that methods can be invoked on it:

Although it would have been easier for the response object to return an actual object instead of a
dynamic proxy, this would not have worked because t he client would only be able to have access
to new object with the same values as opposed to a reference to the actual remote object

The solution here was to use java.lang.Proxy in ord er to return the stub of an object, as this is a
standard way in Java to create a way to call method s despite not having the actual object.

The only issue with this is that each remote object needs to implement an interface which defines
all the method calls that should be available to a remote client. However, this is not overly
complex so as long as it is documented clearly woul d still allow for fairly straight-forward use of
the framework.

16


RPC for an Object-Oriented System

One of the issues encountered in trying to implemen t the JSON-RPC protocol for an object
oriented application is that the specification does not take the object which to call into
consideration.

A possible solution for this would have been to hav e each object manage its own RPC calls, but
this seemed like it would add an unnecessary layer of complexity to remote objects. Therefore,
the specification was adapted so that the ID field always contains the service name of the object
as described in the registry.

Therefore, when the client looks up a service by pa ssing in the service name, this parameter will
be used to create a new invocation handler that sto res the service name as a field. Then, any time
a method is invoked for that particular service, th e service name is passed in the id field and the
registry can invoke the request on the correct corr esponding object.



17

Testing

The project was tested using a simple Java client t hat ran as a separate application from the
server running the registry. The application created to test this is a client-server application in
which the server creates a registry on a local port and binds an object to it. In this particular
example, the object is a Bank object with the servi ce name BANK. The clients in this
application use LocateRegistry to find the registry on the known port. The registry object
returned is a proxy object.

This test was successful. The output for the test c an be seen in the following screenshot.

Servers output


In the server output the serialized Response object s are printed and show the simple JSON
strings which are used to transmit messages back to the client.

In the following two screenshots, the output for ea ch of the clients method invocations is
printed. Notice that the the bank object for both c lients is the same object and that methods
invoked on the bank by the first client affect the object that the second client accesses,
demonstrating that both clients are accesing the sa me remote object.





18

First client output:


Second clients output:




19

Results

In general the main objectives of this project have been achieved. In particular, remote method
invocation using JSON as the serialization protocol was shown to be a feasible and useful
alternative to the standard Java RMI library. In ad dition, using Gson to simplify the serialization
was successful although there were a few complexiti es as noted earlier in the design decisions
section.
At the moment, the only major component that is not fully implemented is error handling.
Although the registry does have a way to return an error, it does not always do so and does not
always provide an accurate error message. Also, eve n though the error parameter is included as
part of the response object that is sent to the cli ent, the client does not really have a way to
actually see what the error was without leading to a runtime exception. This is because the
invocation handler returns a proxy object to the cl ient based on the result object and returns a
null object if the result is null. I think that on e way to solve this would be to throw the exception
and have the client catch it and in this case the c lient may be able to know more about the error
that caused the result object to be null. However, due to time constraints I did not have the
opportunity to try and test this idea.



20

Conclusions
Contributions to the Field
This projects main goal was to build a framework w ithin which a registry that supports remote
method invocation using JSON serialization could be created. In that respect, the project has
contributed a usable tool/library for someone looki ng to create a distributed system on a non-
Java object oriented environment. While not as robust, scalable or complex as the original
java.rmi library, it is usable and also easy to exp and upon if necessary. Therefore, this project has
contributed, at least in some small way, to the fie ld of distributed development.

Concepts Learned
Throughout this project, I have had to conduct a la rge amount of independent research in order to
become more knowledgeable about some of the background topics like Json serialization and
using dynamic proxies in Java. In addition, I have also learned about using Gson, and both
refreshed and expanded my knowledge of distributed computing learned in COMP4104.

Future Work:
There are certainly extensions that could be made t o this project if someone were to continue
work on it. First of all, the trader application co uld be implemented as it was originally part of
the original proposal and it would also not be sign ificantly more complex than the registry
application because it could reuse much of the exis ting framework
One aspect of Json-Rpc 2.0 that I did not end up implementing because it was not crucial to the
functionality of the framework is the Notification  object. Currently there is no real way for the
client to send just a notification to the registry, although calling a void method in the registry is
similar in concept in that the client does not expe ct a response back. Implementing this feature
could be a useful addition to the framework in the future.
In general, there are many features that can be add ed in terms of future work as the basic
framework is already there and would not need to be significantly modified.

21

Bibliography

[1]
http://www.jsonrpc.org/specification

[2]
http://programmerbruce.blogspot.ca/2011/06/gson-v-jackson.html

[3]
http://docs.oracle.com/javase/6/docs/api/java/rmi/package-summary.html