diff --git a/callback/src/main/java/com/iluwatar/callback/App.java b/callback/src/main/java/com/iluwatar/callback/App.java
index 7b630f8da247..9afaa3fc33fa 100644
--- a/callback/src/main/java/com/iluwatar/callback/App.java
+++ b/callback/src/main/java/com/iluwatar/callback/App.java
@@ -39,6 +39,11 @@ private App() {}
/** Program entry point. */
public static void main(final String[] args) {
var task = new SimpleTask();
- task.executeWith(() -> LOGGER.info("I'm done now."));
+
+ LOGGER.info("=== Synchronous callback ===");
+ task.executeWith(() -> LOGGER.info("Sync callback executed."));
+
+ LOGGER.info("=== Asynchronous callback ===");
+ task.executeAsyncWith(() -> LOGGER.info("Async callback executed.")).join();
}
}
diff --git a/callback/src/main/java/com/iluwatar/callback/Callback.java b/callback/src/main/java/com/iluwatar/callback/Callback.java
index 7b75b5c71077..67b2880e1681 100644
--- a/callback/src/main/java/com/iluwatar/callback/Callback.java
+++ b/callback/src/main/java/com/iluwatar/callback/Callback.java
@@ -25,6 +25,7 @@
package com.iluwatar.callback;
/** Callback interface. */
+@FunctionalInterface
public interface Callback {
void call();
diff --git a/callback/src/main/java/com/iluwatar/callback/Task.java b/callback/src/main/java/com/iluwatar/callback/Task.java
index d69697454dff..d58d55540f52 100644
--- a/callback/src/main/java/com/iluwatar/callback/Task.java
+++ b/callback/src/main/java/com/iluwatar/callback/Task.java
@@ -25,15 +25,30 @@
package com.iluwatar.callback;
import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
-/** Template-method class for callback hook execution. */
+/**
+ * Template-method class for callback hook execution.
+ *
+ *
Provides both synchronous and asynchronous execution with callback support.
+ */
public abstract class Task {
- /** Execute with callback. */
+ /** Execute the task and call the callback method synchronously upon completion. */
final void executeWith(Callback callback) {
execute();
Optional.ofNullable(callback).ifPresent(Callback::call);
}
+ /** Execute the task and asynchronously call the callback method upon completion. */
+ final CompletableFuture executeAsyncWith(Callback callback) {
+ return CompletableFuture.runAsync(
+ () -> {
+ execute();
+ Optional.ofNullable(callback).ifPresent(Callback::call);
+ });
+ }
+
+ /** Actual work to be implemented by subclasses. */
public abstract void execute();
}
diff --git a/callback/src/test/java/com/iluwatar/callback/CallbackTest.java b/callback/src/test/java/com/iluwatar/callback/CallbackTest.java
index 99939d491f4e..64780babec84 100644
--- a/callback/src/test/java/com/iluwatar/callback/CallbackTest.java
+++ b/callback/src/test/java/com/iluwatar/callback/CallbackTest.java
@@ -26,6 +26,9 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
/**
@@ -39,19 +42,44 @@ class CallbackTest {
private Integer callingCount = 0;
@Test
- void test() {
- Callback callback = () -> callingCount++;
-
+ void testSynchronousCallback() {
+ var counter = new AtomicInteger();
+ Callback callback = counter::incrementAndGet;
var task = new SimpleTask();
- assertEquals(Integer.valueOf(0), callingCount, "Initial calling count of 0");
-
+ assertEquals(0, counter.get(), "Initial count should be 0");
task.executeWith(callback);
+ assertEquals(1, counter.get(), "Callback should be called once");
+ task.executeWith(callback);
+ assertEquals(2, counter.get(), "Callback should be called twice");
+ }
- assertEquals(Integer.valueOf(1), callingCount, "Callback called once");
+ @Test
+ void testAsynchronousCallback() {
+ var task = new SimpleTask();
- task.executeWith(callback);
+ var counter1 = new AtomicInteger();
+ final CompletableFuture future1 = new CompletableFuture<>();
+ Callback callback1 =
+ () -> {
+ counter1.incrementAndGet();
+ future1.complete(null);
+ };
+ var f1 = task.executeAsyncWith(callback1);
+ future1.orTimeout(1, TimeUnit.SECONDS).join();
+ f1.join();
+ assertEquals(1, counter1.get(), "Async callback should increment once");
- assertEquals(Integer.valueOf(2), callingCount, "Callback called twice");
+ var counter2 = new AtomicInteger();
+ final CompletableFuture future2 = new CompletableFuture<>();
+ Callback callback2 =
+ () -> {
+ counter2.incrementAndGet();
+ future2.complete(null);
+ };
+ var f2 = task.executeAsyncWith(callback2);
+ future2.orTimeout(1, TimeUnit.SECONDS).join();
+ f2.join();
+ assertEquals(1, counter2.get(), "Async callback should increment once again");
}
}