Future should handle multiple handlers instead of a single - see #3174

This commit is contained in:
Julien Viet
2019-11-01 17:20:34 +01:00
parent b6b718470e
commit 8feaa77803
2 changed files with 106 additions and 9 deletions

View File

@@ -15,6 +15,8 @@ import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import java.util.ArrayList;
import java.util.Objects;
class FutureImpl<T> implements Promise<T>, Future<T> {
@@ -33,14 +35,14 @@ class FutureImpl<T> implements Promise<T>, Future<T> {
/**
* The result of the operation. This will be null if the operation failed.
*/
public T result() {
public synchronized T result() {
return result;
}
/**
* An exception describing failure. This will be null if the operation succeeded.
*/
public Throwable cause() {
public synchronized Throwable cause() {
return throwable;
}
@@ -69,17 +71,41 @@ class FutureImpl<T> implements Promise<T>, Future<T> {
* Set a handler for the result. It will get called when it's complete
*/
public Future<T> setHandler(Handler<AsyncResult<T>> handler) {
boolean callHandler;
Objects.requireNonNull(handler, "No null handler accepted");
synchronized (this) {
callHandler = isComplete();
if (!callHandler) {
this.handler = handler;
if (!isComplete()) {
if (this.handler == null) {
this.handler = handler;
} else {
addHandler(handler);
}
return this;
}
}
if (callHandler) {
dispatch(handler);
return this;
}
private void addHandler(Handler<AsyncResult<T>> h) {
Handlers<T> handlers;
if (handler instanceof Handlers) {
handlers = (Handlers<T>) handler;
} else {
handlers = new Handlers<>();
handlers.add(handler);
handler = handlers;
}
handlers.add(h);
}
protected void dispatch(Handler<AsyncResult<T>> handler) {
if (handler instanceof Handlers) {
for (Handler<AsyncResult<T>> h : (Handlers<T>)handler) {
h.handle(this);
}
} else {
handler.handle(this);
}
return this;
}
@Override
@@ -123,7 +149,7 @@ class FutureImpl<T> implements Promise<T>, Future<T> {
handler = null;
}
if (h != null) {
h.handle(this);
dispatch(h);
}
return true;
}
@@ -195,4 +221,14 @@ class FutureImpl<T> implements Promise<T>, Future<T> {
return "Future{unresolved}";
}
}
private class Handlers<T> extends ArrayList<Handler<AsyncResult<T>>> implements Handler<AsyncResult<T>> {
@Override
public void handle(AsyncResult<T> res) {
for (Handler<AsyncResult<T>> handler : this) {
handler.handle(res);
}
}
}
}

View File

@@ -120,6 +120,22 @@ public class FutureTest extends VertxTestBase {
}
}
@Test
public void testSetNullHandler() throws Exception {
Promise<String> promise = Promise.promise();
try {
promise.future().setHandler(null);
fail();
} catch (NullPointerException ignore) {
}
promise.complete();
try {
promise.future().setHandler(null);
fail();
} catch (NullPointerException ignore) {
}
}
@Test
public void testCallSetHandlerBeforeCompletion() {
AtomicBoolean called = new AtomicBoolean();
@@ -1363,4 +1379,49 @@ public class FutureTest extends VertxTestBase {
}
};
}
@Test
public void testSeveralHandlers1() {
waitFor(2);
Promise<String> promise = Promise.promise();
Future<String> fut = promise.future();
fut.setHandler(ar -> {
complete();
});
fut.setHandler(ar -> {
complete();
});
promise.complete();
await();
}
@Test
public void testSeveralHandlers2() {
waitFor(2);
Promise<String> promise = Promise.promise();
promise.complete();
Future<String> fut = promise.future();
fut.setHandler(ar -> {
complete();
});
fut.setHandler(ar -> {
complete();
});
await();
}
@Test
public void testSeveralHandlers3() {
waitFor(2);
Promise<String> promise = Promise.promise();
Future<String> fut = promise.future();
fut.setHandler(ar -> {
complete();
});
promise.complete();
fut.setHandler(ar -> {
complete();
});
await();
}
}