RMI over HTTP - A SOAP Implementation

by Ronald Koster, version 1.3, 2002-10-10. Deprecated, use Axis from Apache instead.

Introduction

This document gives a short description on how one can use SOAP to simulate Java RMI over HTTP. It is a SOAP implementation. Only the soap:Body part of the SOAP request and SOAP repsonse message are described.

The idea is to encapsulate remotely invokable interfaces in SOAP in an ordinary RMI like way. A SOAP server publishes on one of its web pages a jar file with all:

Message format

This DTD file is used for the soap:Body. Do this as follows:
<soap:Envelope
xmlns:soap="http://www.w3.org/2002/06/soap-envelope"
xmlns:rmi="http://www.ronaldkoster.net/soap-rmi_10.dtd"
soap:encodingStyle="URL of publishing web page mentioned above">

Implementing classes

Client side implementation
On the client side for each remote interface <interfaceX> an instance of implementing class <interfaceX>Client is running that translates all invokations of any of its remote methods to a SOAP request. It then sends the request message to the SOAP server, waits for the response message and translates it back to Java variables.

Server side implementation
On the Server side for each remote interface <interfaceX> one or more instances of implementing class <interfaceX>Server are running that parse all incoming SOAP requests, executes the request and translates the output to a SOAP response.

Stringable classes

All objects that are to be send to and from the client and server must be implementations of the interface Stringable, which is a Serializable look-alike.

NB. Terminology: an object is an instance of a class or interface;

Example: all exceptions can be made stringable. Here is an example of such a stringable exception: ExceptionTooManySessions.

Flow (server side)

  1. Upon receival of a SOAP request message by the server the message is parsed and all arguments (= parameters) are translated into the appropriate standard type variables and/or objects. This requires calling the fromString(String) method for all stringable class type arguments.
  2. The server searches the server side instance indicated by request.interface (instance of the server side implementing class of the remote interface);
  3. It then calls the indicated (by request.method and the argument types) method and passes the arguments to it;
  4. The output from the method called is translated into a SOAP response message and send back the client. When the return type is a class its asString() method is called.

Examples

With standard Java types only

Client code:
    ...
    Kalender kal = new KalenderClient();
    ...
    kal.getDayOfWeek(2002, 9, 25);
Resulting Request:
<soap:Envelope
xmlns:soap="http://www.w3.org/2002/06/soap-envelope"
xmlns:rmi="http://www.ronaldkoster.net/soap-rmi_10.dtd"
soap:encodingStyle="http://www.ronaldkoster.net/soap-rmi.htm">
    <soap:Body>
        <rmi:request interface="Kalender" methode="getDayOfWeek" type="String">
            <rmi:param name="year" type="int">2002</rmi:param>
            <rmi:param name="month" type="int">9</rmi:param>
            <rmi:param name="day" type="int">25</rmi:param>
        </rmi:request>
    </soap:Body>
</soap:Envelope>
Response:
<soap:Envelope
xmlns:soap="http://www.w3.org/2002/06/soap-envelope"
xmlns:rmi="http://www.ronaldkoster.net/soap-rmi_10.dtd"
soap:encodingStyle="http://www.ronaldkoster.net/soap-rmi.htm">
    <soap:Body>
        <rmi:response interface="Kalender" method="getDayOfWeek" type="String">
            <rmi:return>Wednesday</rmi:return>
        </rmi:response>
    </soap:Body>
</soap:Envelope>
In the following examples the soap:Envelope is identical to the one above but is omitted for clarity reasons.

With stringable types

Client code:
    ...
    Klok klok = new KlokClient();
    ...
    DateTime dt = klok.getCurrentTime();
Request:
<soap:Body>
    <rmi:request interface="Klok" methode="getCurrentTime" type="DateTime"/>
</soap:Body>
Response:
<soap:Body>
    <rmi:response interface="Klok" method="getCurrentTime" type="DateTime">
        <rmi:return>
            <DateTime><Date y="2002" m="9" d="25"><Time h="14" m="31" s="24"></DateTime>
        </rmi:return>
    </rmi:response>
</soap:Body>

Session key

Each client can have its own private session when using the Session key design pattern:
  1. When setting up a session with a server first request a session key;
  2. Mark every following request to the server with that key, making the session uniquely identifiable to the server and server. This way the server can have multiple sessions with one or more clients;
When the data to be transferred is confidential one can use HTTPS instead of HTTP for the tranportation of the XML messages. Or one can encrypt the XML messages themself and transport the encrypted XML messages (cipher text) only.

Ad 1.

Client Code:
    ...
    Session session = new SessionClient();
    ...
    try
    {
        String sessionId = session.getSessionId();
    }
    catch(SoapExceptionTooManySessions ex)
    {
        System.out.println( "No session key available: " + ex.getMessage() );
    }
    catch(Exception ex)
    {
        System.err.println( "Unexpected exception: " + ex.getMessage() );
    }
Request:
<soap:Body>
    <rmi:request interface="Session" methode="getSessionId" type="String"/>
</soap:Body>
Response 1:
<soap:Body>
    <rmi:response interface="Session" method="getSessionId" type="String">
        <rmi:return>A34CZ8901q</rmi:return>
    </rmi:response>
</soap:Body>
Response 2:
<soap:Body>
    <rmi:response interface="Session" method="getSessionId" type="String">
        <rmi:throws>
            <SoapExceptionTooManySessions>Max number of sessions has been reached.</SoapExceptionTooManySessions>
        </rmi:throws>
    </rmi:response>
</soap:Body>

Ad 2.

Client Code:
    ...
    Transaction trans = new Transaction();
    ...
    // code that fills trans
    boolean succes = session.requestTransaction(sessionId, trans);
Request:
<soap:Body>
    <rmi:request interface="Session" methode="requestTransaction" type="boolean">
        <rmi:param name="sessionId" type="String">A34CZ8901q</rmi:param>
        <rmi:param name="transaction" type="Transaction">asString() output of the Transaction object</rmi:param>
    </rmi:request>
</soap:Body>
Response:
<soap:Body>
    <rmi:response interface="Session" method="requestTransaction" type="boolean">
        <rmi:return>true</rmi:return>
    </rmi:response>
</soap:Body>

Publishing remote interfaces

Here are some examples of publications for the above examples:

Soap.java
SoapException.java
Stringable.java
DateTime.java
Kalender.java
KalenderClient.java
Session.java
SessionClient.java
SoapExceptionTooManySessions.java
Transaction.java

Normally the above files, or at least the corresponding class and javadoc files, are published in a jar file.

Here is an example of a server side implementation:

KalenderServer.java


Project direcory