1

Look at the following use case.

I have a client (Java) application, which wants to get/set the state of another, remote application (C). The communication between them is done via SIP, which is run in another thread.

The SIP interface can do the following:

sendMessage onRequest

I have two ideas for the architecture:

RPC (JSON-RPC)

Define a class which does the marshalling/unmarshalling for JSONRPCRequests and JSONRPCResponse (http://software.dzhuvinov.com/json-rpc-2.0-base.html)

Define a Invoker class, which has something like a call(server, name, arguments) method.

In the Invoker class, the name and arguments are put into a JSONRPCRequest and sent via the SIP layer sendMessage

Now comes my problem. How do i actually get the right back to the caller? The control flow is now:

The onRequest method is called, but I do now know whether it is the answer to my previous call. What i do is putting all responses reaching my server into a Map, and just poll that list in the Invoker.

A rough sketch might be;

Invoker (provides API to client)

class Invoker {

    private Channel channel;

    public Invoker(Channel channel) { this.channel = channel; }

    public Object call(String server, String name, Object .. args) {
        JSONRPCRequest req = ...;
        channel.sendMessage(server, req.toString());
        while( ! channel.hasResponse(req.id()) {
            Thread.sleep(42);
        }
        return channel.getResponse(req.id()).result();        
    }

}

Channel (interface to messenger):

class Channel {

    private Map<Object, JSONRPCResponse> responses = new //;

    private Sip sip = new Sip() {
        public void onRequest(String msg) {
            JSONRPCResponse response = JSONRPCResponse.parse(msg);
            responses.put(msg.id(), response);
        }
    };

    public void sendMessage(String server, String message) {
        sip.sendMessage();
    }

    public boolean hasResponse onRequest(Object id) {
        responses.hasKey(id);
    }

    public JSONRPCResponse getResponse(Object id) {
        responses.get(id);
        responses.delete(id);
    }

}

SIP (messenger itself):

abstract class Sip {

    public void sendMessage(String msg) {
        // SIP magic
    }

    public abstract void onRequest(String msg);    
}

Is there a better way to do that? My biggest problems/code smells are:

  • the blocking in Invoker
  • the protocol is in Invoker, maybe I want to switch marshalling to something else
  • the map as mean to get the correct response for a request
  • the SIP abstract method looks strange
  • No error handling
  • No timeout

Message Passing

Is there an easy way to get rid of RPC, and implement something like RPC with just message passing? Any hints for pattern are welcome. I do not need the code itself, I am totally fine with just architecture. I tried to google for message passing implementations, and how they actually change state with it, but I did not find anything useful. How to implement timeout/ error handling?

Any good books/literature on that topic is also welcome, as I never programmed such distributed stuff.

Any other ideas on which protocol to use inside SIP to change state is welcome, too, as RPC was my initial thought, and I did not find anything other useful.

The code will not compile, I guess, it was just to visualize my idea.

1 Answer 1

1
  • the blocking in Invoker
  • the protocol is in Invoker, maybe I want to
  • switch marshalling to something else the map as mean to get the
  • correct response for a request the SIP abstract method looks strange
  • No error handling No timeout

Your channel by design is NON-BLOCKING. Your implementation with the while() loop makes it not. Employing callbacks could make this much prettier. In C the callbacks could be method pointers or Java an interface-bound handler.

interface AsyncResponder
void result( Object o );
void error( Object o );

Create an ID/SEQUENCE NUMBER for every message and store in a map the ID and the reference to the callback handler. Execute the callback handler when you get a response.

Blocking timeouts are much easier. hasResponse(id) could be very easily adapted to occur on an interval in conjunction with the timeout mechanism.

Non-Blocking timeouts have the duty of removing the request callback from the callback map. If/when a response occurs there should be no callback to execute.

Error handling should be done in the request handler only. Not globally.

Nothing wrong with having the protocol in the invoker unless you expect the invoker to change all the time.

RPC calls must have a SEQUENCE NUMBER, COMMAND NAME, MESSAGE LENGTH, MESSAGE BODY. For responses the COMMAND NAME could be "_result" / "_error". (as done in RTMP)

2
  • Do you have an example implementation or more detailed description/name of that pattern/literature?
    – jcklie
    Jun 25, 2014 at 13:57
  • I am not aware of any pattern. Its one of those that takes about an hour to make and no one over thinks it. The only specifications I can find in a quick search are way too complicated for your case. Maybe this will help: simple-is-better.org/rpc Jun 25, 2014 at 14:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.