package io.craft.atom.rpc; import io.craft.atom.protocol.rpc.model.RpcMessage; import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * @author mindwind * @version 1.0, Aug 19, 2014 */ public class DefaultRpcFuture<V> implements RpcFuture<V> { private volatile RpcMessage response ; private volatile Exception exception; private volatile boolean done ; private volatile int waiters ; // ~ ------------------------------------------------------------------------------------------------------------ @Override public boolean await(long timeout, TimeUnit unit) throws InterruptedException { long timeoutMillis = unit.toMillis(timeout); long endTime = System.currentTimeMillis() + timeoutMillis; synchronized (this) { if (done) return done; if (timeoutMillis <= 0) return done; waiters++; try { while (!done) { wait(timeoutMillis); if (endTime < System.currentTimeMillis() && !done) { exception = new TimeoutException(); break; } } } finally { waiters--; } } return done; } @Override public Exception getException() { return exception; } @Override public RpcMessage getResponse() throws IOException, TimeoutException { Exception e = getException(); if (e != null) { if (e instanceof IOException ) throw (IOException) e; if (e instanceof TimeoutException) throw (TimeoutException) e; throw new RpcException(RpcException.UNKNOWN, "unkonw error", e); } return response; } @Override public void setException(Exception exception) { synchronized (this) { if (done) return; this.exception = exception; done = true; if (waiters > 0) { notifyAll(); } } } @Override public void setResponse(RpcMessage response) { synchronized (this) { if (done) return; this.response = response; done = true; if (waiters > 0) { notifyAll(); } } } @Override public V get() throws InterruptedException, ExecutionException { try { return get(Long.MAX_VALUE, TimeUnit.DAYS); } catch (TimeoutException e) { throw new InterruptedException(e.getMessage()); } } @SuppressWarnings("unchecked") @Override public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { await(timeout, unit); try { RpcMessage rsp = getResponse(); return (V) RpcMessages.unpackResponseMessage(rsp); } catch (Exception e) { throw new ExecutionException(e); } } @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return done; } }