1

I'm implementing a layer to wrap a 3rd party communication layer.

The contract I need to implement is:

FutureTask<SomeData> send(Request request);

My layer has an onMessageReceived method, which is called by the 3rd party when a response arrives.

The approach I've taken to implement my layer is as follows:

I have a callable, which waits on a condition with a timeout:

interface MyCallable<T> extends Callable<T> {
    void signal();
}

class CallableWithSignal<T> implements MyCallable<T> {
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private long waitTime;

    public CallableWithSignal(int waitTimeSeconds){
        this.waitTime=waitTimeSeconds;
    }
    @Override
    public T call() throws Exception {
        lock.lock();
        try {
            boolean wasSignaled = condition.await(waitTime, TimeUnit.SECONDS);
            if(wasSignaled)
                return null;

            System.out.println("throwing exeption");
            throw new Exception("timeout");                         
        } finally {
            lock.unlock();
        }        
    }
    @Override
    public void signal() {
        lock.lock();

        try {
            condition.signal();
        } finally {
            lock.unlock();
        }
    }   
}

I also have extended FutureTask to expose the set method, as follows:

class MyFutureTask<V> extends FutureTask<V> {
    private MyCallable<V> myCallable;

    public MyFutureTask(MyCallable<V> r) { super(r); myCallable = r;}
    @Override
    public void set(V x) { super.set(x); }
    @Override
    public void setException(Throwable t) { super.setException(t); }

    @Override
    protected void done() {
        super.done();
        myCallable.signal();
    }
}

When the task is done, I signal the callable to stop it.

So every time a send is called, I create a new MyFutureTask, run it using an executor, save it in a map and return it.

When onMessageReceived is called I find the task in the map and set its result with the set method.

Is this a good approach?

And another question: is it a good approach to move the executor logic inside the task? I mean, to create a start method for it, which will run the task using the executor.

please advice.

AntonKam
  • 163
  • 11

0 Answers0