0

I'm using an asyncronus XML-RPC-Client (https://github.com/gturri/aXMLRPC) in my Project and wrote some methods using the asyncronous Callback-Methods of this Client like this this:

 public void xmlRpcMethod(final Object callbackSync) {
    XMLRPCCallback listener = new XMLRPCCallback() {
        public void onResponse(long id, final Object result) {
            // Do something
            if (callbackSync != null) {
                synchronized (callbackSync) {
                    callbackSync.notify();
                }
            }
        }

        public void onError(long id, final XMLRPCException error) {
            // Do something
            if (callbackSync != null) {
                synchronized (callbackSync) {
                    callbackSync.notify();
                }
            }
        }

        public void onServerError(long id, final XMLRPCServerException error) {
            Log.e(TAG, error.getMessage());
            if (callbackSync != null) {
                synchronized (callbackSync) {
                    callbackSync.notifyAll();
                }
            }
        }
    };

    XMLRPCClient client = new XMLRPCClient("<url>");
    long id = client.callAsync(listener, "<method>");

}

In other methods I like to call this method (here "xmlRpcMethod") and wait until it finished. I wrote methods like this:

public void testMethod(){
    Object sync = new Object();
    xmlRpcMethod(sync);
    synchronized (sync){
        try{
            sync.wait();
        }catch(Interrupted Exception e){
            e.printStackTrace();
        }
    }
    // Do something after xmlRcpFinished
}

But this way of waiting and synchronizing get's ugly when the projects grows larger and I need to wait for many requests to finish. So is this the only possible / best way? Or does someone knows a better solution?

bartolja
  • 487
  • 1
  • 4
  • 13

1 Answers1

0

My first shot to create blocking RPC calls would be:

// Little helper class:
class RPCResult<T>{
     private final T result;
     private final Exception ex;
     private final long id;

     public RPCResult( long id, T result, Exception ex ){
        // TODO set fields
     }

     // TODO getters

     public boolean hasError(){ return null != this.ex; }
} 


public Object xmlRpcMethod() {
    final BlockingQueue<RPCResult> pipe = new ArrayBlockingQueue<RPCResult>(1);
    XMLRPCCallback listener = new XMLRPCCallback() {
        public void onResponse(long id, final Object result) {
            // Do something
            pipe.put( new RPCResult<Object>(id, result, null) );
        }

        public void onError(long id, final XMLRPCException error) {
            // Do something
            pipe.put( new RPCResult<Object>(id, null, error) );
        }

        public void onServerError(long id, final XMLRPCServerException error) {
            Log.e(TAG, error.getMessage());
            pipe.put(new RPCResult<Object>(id, null, error));
        }
    };

    XMLRPCClient client = new XMLRPCClient("<url>");
    long id = client.callAsync(listener, "<method>");
    RPCResult result = pipe.take(); // blocks until there is an element available 
    // TODO: catch and handle InterruptedException!
    if( result.hasError() ) throw result.getError(); // Relay Exceptions - do not swallow them!
    return result.getResult();
}

Client:

public void testMethod(){
    Object result = xmlRpcMethod(); // blocks until result is available or throws exception
}

Next step would be to make a strongly typed version public T xmlRpcMethod().

Fildor
  • 14,510
  • 4
  • 35
  • 67
  • Thanks for this, it looks really easy to use in the Client-Methods - Very nice! In most cases I don't need to give the response back to the calling method. The caller just need's to wait until the response is received and processed(?) by the onResponse-Method of the Listener. Therefore the xmlRpcMethod can also be void in most cases and typing is not necessary. – bartolja Jun 23 '16 at 11:03
  • Ok, in that case you can simply ignore the result. But you have to fetch it from the queue because that's where the blocking happens. And I would throw Exceptions if present. – Fildor Jun 23 '16 at 11:04
  • Mind that `take` might "take" forever ... with `poll` you can introduce a timeout-functionality. May not be necessary but I thought I'd mention it. – Fildor Jun 23 '16 at 11:09
  • Yes right, I already knew but thank you anyway! I applied it already on my project and it works perfect! – bartolja Jun 23 '16 at 12:04