Skip to content

Commit

Permalink
Replaced all FutureActions with CompletableFutures
Browse files Browse the repository at this point in the history
  • Loading branch information
BelgianDev committed Dec 28, 2024
1 parent 1a798a9 commit 4d21b76
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 51 deletions.
4 changes: 2 additions & 2 deletions api/src/main/java/fr/atlasworld/event/api/EventNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.google.common.base.Preconditions;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import fr.atlasworld.common.concurrent.action.FutureAction;
import fr.atlasworld.event.api.listener.EventHandler;
import fr.atlasworld.event.api.listener.EventListener;
import fr.atlasworld.event.api.listener.EventListenerBuilder;
Expand All @@ -11,6 +10,7 @@

import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Predicate;

Expand Down Expand Up @@ -108,7 +108,7 @@ static <E extends Event> EventNode<E> create(@NotNull String name, @NotNull Clas
*/
@NotNull
@CanIgnoreReturnValue
<T extends E> FutureAction<T> callEvent(@NotNull T event);
<T extends E> CompletableFuture<T> callEvent(@NotNull T event);

/**
* Adds a child node to this node.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package fr.atlasworld.event.api.executor;

import fr.atlasworld.common.concurrent.action.FutureAction;
import fr.atlasworld.common.concurrent.action.SimpleFutureAction;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.CompletableFuture;

/**
* Represents an event executor, this allows event to be executed asynchronously.
* <p>
Expand All @@ -21,7 +21,7 @@ public interface EventExecutor {
*
* @throws InterruptedException when the requesting thread is interrupted.
*/
FutureAction<Void> request(@NotNull EventRequest request) throws InterruptedException;
CompletableFuture<Void> request(@NotNull EventRequest request) throws InterruptedException;

/**
* Synchronous executor,
Expand All @@ -31,13 +31,13 @@ public interface EventExecutor {
* This could lead to much slower executions on event that have many listeners.
*/
final EventExecutor syncExecutor = request -> {
SimpleFutureAction<Void> future = new SimpleFutureAction<>();
CompletableFuture<Void> future = new CompletableFuture<>();

try {
request.execute();
future.complete(null);
} catch (final Throwable e) {
future.fail(e);
future.completeExceptionally(e);
}

return future;
Expand Down
33 changes: 12 additions & 21 deletions core/src/main/java/fr/atlasworld/event/core/EventNodeImpl.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package fr.atlasworld.event.core;

import com.google.common.base.Preconditions;
import fr.atlasworld.common.concurrent.action.CompositeFutureAction;
import fr.atlasworld.common.concurrent.action.FutureAction;
import fr.atlasworld.common.concurrent.action.SimpleFutureAction;
import fr.atlasworld.common.logging.LogUtils;
import fr.atlasworld.event.api.Event;
import fr.atlasworld.event.api.EventNode;
Expand All @@ -22,6 +19,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
Expand Down Expand Up @@ -68,7 +66,7 @@ public boolean hasParents() {
}

@Override
public @NotNull <T extends E> FutureAction<T> callEvent(@NotNull T event) {
public @NotNull <T extends E> CompletableFuture<T> callEvent(@NotNull T event) {
Preconditions.checkNotNull(event);

if (this.hasParents())
Expand All @@ -78,14 +76,14 @@ public boolean hasParents() {
return this.invokeEvent(event);
}

private <T extends E> FutureAction<T> invokeEvent(@NotNull T event) {
private <T extends E> CompletableFuture<T> invokeEvent(@NotNull T event) {
if (!this.eventCondition.test(event))
return new SimpleFutureAction<T>().complete(event);
return CompletableFuture.completedFuture(event);

CompositeFutureAction.CompositeBuilder builder = CompositeFutureAction.builder();
List<CompletableFuture<?>> futures = new ArrayList<>();

for (EventNodeImpl<?> node : this.children.values()) {
builder.add(node.propagateEvent(event));
futures.add(node.propagateEvent(event));
}

if (this.listeners.containsKey(event.getClass())) {
Expand All @@ -99,29 +97,22 @@ private <T extends E> FutureAction<T> invokeEvent(@NotNull T event) {
continue;
}

builder.add(listener.callEvent(event));
futures.add(listener.callEvent(event));
}
}

// Bad Design, TODO (AtlasCommon): Allow Composite Future actions to be empty.
builder.add(new SimpleFutureAction<>().complete(null)); // Prevents IllegalArgument if the event was executed nowhere.

SimpleFutureAction<T> future = new SimpleFutureAction<>();
FutureAction<Void> groupedFuture = builder.build();
groupedFuture.onFailure(future::fail)
.onSuccess(unused -> future.complete(event));

return future;
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(v -> event);
}

@SuppressWarnings("unchecked")
protected <T extends Event> FutureAction<T> propagateEvent(@NotNull T event) {
protected <T extends Event> CompletableFuture<T> propagateEvent(@NotNull T event) {
Preconditions.checkNotNull(event);

if (!this.eventType.isInstance(event)) // Check if the event is the same as this event type.
return new SimpleFutureAction<T>().complete(event);
return CompletableFuture.completedFuture(event);

return (FutureAction<T>) this.invokeEvent((E) event);
return (CompletableFuture<T>) this.invokeEvent((E) event);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package fr.atlasworld.event.core.listener;

import fr.atlasworld.common.concurrent.action.FutureAction;
import fr.atlasworld.common.concurrent.action.SimpleFutureAction;
import fr.atlasworld.event.api.Event;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;

public abstract class RegisteredListener<E extends Event> {
Expand Down Expand Up @@ -35,21 +34,18 @@ public boolean isExpired(E event) {
return false;
}

public FutureAction<E> callEvent(@NotNull E event) {
SimpleFutureAction<E> future = new SimpleFutureAction<>();

public CompletableFuture<E> callEvent(@NotNull E event) {
if (this.expired.get() && !this.settings.testEvent(event))
return future.complete(null);
return CompletableFuture.completedFuture(event);

CompletableFuture<E> future;

try {
this.settings.executor().request(() -> this.run(event))
.onSuccess(unused -> future.complete(event))
.onFailure(cause -> {
this.handleException(cause);
future.fail(cause);
}); // Proxying future.
future = CompletableFuture.allOf(
this.settings.executor().request(() -> this.run(event)))
.thenApply(unused -> event);
} catch (InterruptedException e) {
future.fail(e);
future = CompletableFuture.failedFuture(e);
}

return future;
Expand Down
20 changes: 11 additions & 9 deletions core/src/test/java/unit/EventListenerTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void testAddAndExecuteLambdaListener() {
builder.executor(EventExecutor.syncExecutor)
);

eventNode.callEvent(new TestEvent()).onSuccess(event -> {
eventNode.callEvent(new TestEvent()).whenComplete((event, cause) -> {
assertEquals(1, counter.get(), "Lambda listener should be executed once.");
});
}
Expand All @@ -47,7 +47,7 @@ public void testAddAndExecuteMethodListener() {
TestListener listener = new TestListener();
eventNode.addListener(listener, builder -> builder.executor(EventExecutor.syncExecutor));

eventNode.callEvent(new TestEvent()).onSuccess(event -> {
eventNode.callEvent(new TestEvent()).whenComplete((event, cause) -> {
assertTrue(listener.isCalled(), "Method listener should be executed once.");
});
}
Expand All @@ -63,11 +63,11 @@ public void testListenerExpiration() {
.failure(Throwable::printStackTrace)
);

eventNode.callEvent(new TestEvent()).onSuccess(event -> {
eventNode.callEvent(new TestEvent()).whenComplete(((event, cause) -> {
assertEquals(1, counter.get(), "Listener should be executed once.");
});
}));

eventNode.callEvent(new TestEvent()).onSuccess(event -> {
eventNode.callEvent(new TestEvent()).whenComplete((event, cause) -> {
assertEquals(1, counter.get(), "Expired listener should not be executed again.");
});
}
Expand All @@ -82,7 +82,7 @@ public void testFilterListeners() {
.executor(EventExecutor.syncExecutor)
);

eventNode.callEvent(new TestEvent()).onSuccess(event -> {
eventNode.callEvent(new TestEvent()).whenComplete((event, cause) -> {
assertEquals(1, counter.get(), "Listener should be executed when filter passes.");
});

Expand All @@ -93,7 +93,7 @@ public void testFilterListeners() {
.executor(EventExecutor.syncExecutor)
);

eventNode.callEvent(new TestEvent()).onSuccess(event -> {
eventNode.callEvent(new TestEvent()).whenComplete((event, cause) -> {
assertEquals(0, counter.get(), "Listener should not be executed when filter fails.");
});
}
Expand All @@ -110,9 +110,11 @@ public void testHandleExceptionsInListeners() {

eventNode.addListener(TestEvent.class, event -> { throw new RuntimeException("Test exception"); }, builder ->
builder.executor(EventExecutor.syncExecutor));
eventNode.callEvent(new TestEvent()).onFailure(throwable -> {

eventNode.callEvent(new TestEvent()).exceptionally(throwable -> {
called.set(true);
}).syncUninterruptibly();
return null;
}).join();

assertTrue(called.get(), "Thrown exception should be returned in exception.");
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/test/java/userend/TaskExecutorThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public boolean queue(@NotNull Runnable runnable) {
Preconditions.checkNotNull(runnable, "Task cannot be null!");

TaskScheduledEvent event = new TaskScheduledEvent(Thread.currentThread(), this);
Main.rootNode.callEvent(event).syncUninterruptibly();
Main.rootNode.callEvent(event).join();

if (event.cancelled())
return false;
Expand Down

0 comments on commit 4d21b76

Please sign in to comment.