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.