From b1c9bcbfb2801742c2e0d40b154fc7e3dd1e0d52 Mon Sep 17 00:00:00 2001 From: Tim Brooks Date: Mon, 13 Aug 2018 17:39:19 -0600 Subject: [PATCH 1/2] Backport: CompletableContext class to avoid throwable This commit backports the CompletableContext class that wraps the CompletableFuture but does not accept Throwable. --- .../common/concurrent/CompletableContext.java | 63 +++++++++++++++++++ .../elasticsearch/action/ActionListener.java | 10 +-- 2 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 libs/core/src/main/java/org/elasticsearch/common/concurrent/CompletableContext.java diff --git a/libs/core/src/main/java/org/elasticsearch/common/concurrent/CompletableContext.java b/libs/core/src/main/java/org/elasticsearch/common/concurrent/CompletableContext.java new file mode 100644 index 0000000000000..e838842931837 --- /dev/null +++ b/libs/core/src/main/java/org/elasticsearch/common/concurrent/CompletableContext.java @@ -0,0 +1,63 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.common.concurrent; + +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; + +/** + * A thread-safe completable context that allows listeners to be attached. This class relies on the + * {@link CompletableFuture} for the concurrency logic. However, it does not accept {@link Throwable} as + * an exceptional result. This allows attaching listeners that only handle {@link Exception}. + * + * @param the result type + */ +public class CompletableContext { + + private final CompletableFuture completableFuture = new CompletableFuture<>(); + + public void addListener(BiConsumer listener) { + BiConsumer castThrowable = (v, t) -> { + if (t == null) { + listener.accept(v, null); + } else { + assert !(t instanceof Error) : "Cannot be error"; + listener.accept(v, (Exception) t); + } + }; + completableFuture.whenComplete(castThrowable); + } + + public boolean isDone() { + return completableFuture.isDone(); + } + + public boolean isCompletedExceptionally() { + return completableFuture.isCompletedExceptionally(); + } + + public boolean completeExceptionally(Exception ex) { + return completableFuture.completeExceptionally(ex); + } + + public boolean complete(T value) { + return completableFuture.complete(value); + } +} diff --git a/server/src/main/java/org/elasticsearch/action/ActionListener.java b/server/src/main/java/org/elasticsearch/action/ActionListener.java index 8579fb55613ce..f639f139b55fc 100644 --- a/server/src/main/java/org/elasticsearch/action/ActionListener.java +++ b/server/src/main/java/org/elasticsearch/action/ActionListener.java @@ -90,18 +90,12 @@ static ActionListener wrap(Runnable runnable) { * @param the type of the response * @return a bi consumer that will complete the wrapped listener */ - static BiConsumer toBiConsumer(ActionListener listener) { + static BiConsumer toBiConsumer(ActionListener listener) { return (response, throwable) -> { if (throwable == null) { listener.onResponse(response); } else { - if (throwable instanceof Exception) { - listener.onFailure((Exception) throwable); - } else if (throwable instanceof Error) { - throw (Error) throwable; - } else { - throw new AssertionError("Should have been either Error or Exception", throwable); - } + listener.onFailure(throwable); } }; } From 1227688ce1b64aebfe78a927c0532fed31a53429 Mon Sep 17 00:00:00 2001 From: Tim Brooks Date: Mon, 13 Aug 2018 18:02:54 -0600 Subject: [PATCH 2/2] Remove unrelated changes --- .../java/org/elasticsearch/action/ActionListener.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/ActionListener.java b/server/src/main/java/org/elasticsearch/action/ActionListener.java index f639f139b55fc..8579fb55613ce 100644 --- a/server/src/main/java/org/elasticsearch/action/ActionListener.java +++ b/server/src/main/java/org/elasticsearch/action/ActionListener.java @@ -90,12 +90,18 @@ static ActionListener wrap(Runnable runnable) { * @param the type of the response * @return a bi consumer that will complete the wrapped listener */ - static BiConsumer toBiConsumer(ActionListener listener) { + static BiConsumer toBiConsumer(ActionListener listener) { return (response, throwable) -> { if (throwable == null) { listener.onResponse(response); } else { - listener.onFailure(throwable); + if (throwable instanceof Exception) { + listener.onFailure((Exception) throwable); + } else if (throwable instanceof Error) { + throw (Error) throwable; + } else { + throw new AssertionError("Should have been either Error or Exception", throwable); + } } }; }