diff --git a/milky-common/src/main/java/cn/sliew/milky/common/concurrent/CallableWrapper.java b/milky-common/src/main/java/cn/sliew/milky/common/concurrent/CallableWrapper.java new file mode 100644 index 00000000..3296fa62 --- /dev/null +++ b/milky-common/src/main/java/cn/sliew/milky/common/concurrent/CallableWrapper.java @@ -0,0 +1,55 @@ +package cn.sliew.milky.common.concurrent; + +import java.util.concurrent.Callable; + +public interface CallableWrapper extends Callable { + + @Override + default T call() throws Exception { + T result = null; + try { + onBefore(); + result = doCall(); + onAfter(result); + } catch (Exception t) { + onFailure(t); + } finally { + onFinal(); + } + return result; + } + + /** + * This method has the same semantics as {@link Runnable#run()} + * + * @throws InterruptedException if the run method throws an InterruptedException + */ + T doCall() throws Exception; + + /** + * This method is invoked for all exception thrown by {@link #doCall()} + */ + void onFailure(Exception e); + + /** + * This method is called before all execution for init. + */ + default void onBefore() throws Exception { + + } + + /** + * This method is called after execution. + */ + default void onAfter(T result) throws Exception { + + } + + /** + * This method is called in a finally block after successful execution + * or on a rejection. + */ + default void onFinal() { + // nothing by default + } +} diff --git a/milky-common/src/main/java/cn/sliew/milky/common/concurrent/RunnableWrapper.java b/milky-common/src/main/java/cn/sliew/milky/common/concurrent/RunnableWrapper.java new file mode 100644 index 00000000..54affa9e --- /dev/null +++ b/milky-common/src/main/java/cn/sliew/milky/common/concurrent/RunnableWrapper.java @@ -0,0 +1,51 @@ +package cn.sliew.milky.common.concurrent; + +public interface RunnableWrapper extends Runnable { + + @Override + default void run() { + try { + onBefore(); + doRun(); + onAfter(); + } catch (Exception t) { + onFailure(t); + } finally { + onFinal(); + } + } + + /** + * This method has the same semantics as {@link Runnable#run()} + * + * @throws InterruptedException if the run method throws an InterruptedException + */ + void doRun() throws Exception; + + /** + * This method is invoked for all exception thrown by {@link #doRun()} + */ + void onFailure(Exception e); + + /** + * This method is called before all execution for init. + */ + default void onBefore() throws Exception { + + } + + /** + * This method is called after execution. + */ + default void onAfter() throws Exception { + + } + + /** + * This method is called in a finally block after successful execution + * or on a rejection. + */ + default void onFinal() { + // nothing by default + } +} diff --git a/milky-common/src/main/java/cn/sliew/milky/common/filter/ActionListener.java b/milky-common/src/main/java/cn/sliew/milky/common/filter/ActionListener.java index 6c22e357..009d2ca2 100644 --- a/milky-common/src/main/java/cn/sliew/milky/common/filter/ActionListener.java +++ b/milky-common/src/main/java/cn/sliew/milky/common/filter/ActionListener.java @@ -1,5 +1,12 @@ package cn.sliew.milky.common.filter; +import cn.sliew.milky.common.concurrent.CallableWrapper; +import cn.sliew.milky.common.concurrent.RunnableWrapper; + +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; + /** * A listener for action responses or failures. */ @@ -13,5 +20,68 @@ public interface ActionListener { /** * A failure caused by an exception at some phase of the task. */ - void onFailure(Exception e); + void onFailure(Throwable throwable); + + default CompletableFuture toFuture() { + CompletableFuture future = new CompletableFuture(); + future.whenComplete((response, throwable) -> { + if (throwable != null) { + onFailure(throwable); + } else { + onResponse(response); + } + }); + return future; + } + + default BiConsumer toBiConsumer() { + return new BiConsumer() { + @Override + public void accept(Response response, Throwable throwable) { + if (throwable != null) { + onFailure(throwable); + } else { + onResponse(response); + } + } + }; + } + + static Runnable wrap(Runnable runnable, ActionListener listener) { + return new RunnableWrapper() { + @Override + public void doRun() throws Exception { + runnable.run(); + } + + @Override + public void onAfter() { + listener.onResponse(null); + } + + @Override + public void onFailure(Exception e) { + listener.onFailure(e); + } + }; + } + + static Callable wrap(Callable callable, ActionListener listener) { + return new CallableWrapper() { + @Override + public T doCall() throws Exception { + return callable.call(); + } + + @Override + public void onFailure(Exception e) { + listener.onFailure(e); + } + + @Override + public void onAfter(T result) throws Exception { + listener.onResponse(result); + } + }; + } } \ No newline at end of file diff --git a/milky-common/src/main/java/cn/sliew/milky/common/filter/DelegatingActionListener.java b/milky-common/src/main/java/cn/sliew/milky/common/filter/DelegatingActionListener.java new file mode 100644 index 00000000..9bead4d4 --- /dev/null +++ b/milky-common/src/main/java/cn/sliew/milky/common/filter/DelegatingActionListener.java @@ -0,0 +1,20 @@ +package cn.sliew.milky.common.filter; + +public class DelegatingActionListener implements ActionListener { + + private final ActionListener delegate; + + public DelegatingActionListener(ActionListener delegate) { + this.delegate = delegate; + } + + @Override + public void onResponse(Response response) { + delegate.onResponse(response); + } + + @Override + public void onFailure(Throwable throwable) { + delegate.onFailure(throwable); + } +} \ No newline at end of file