diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml
index 215ca2a..fc510b6 100644
--- a/.github/workflows/checks.yaml
+++ b/.github/workflows/checks.yaml
@@ -30,7 +30,7 @@ jobs:
needs: formatting-check
strategy:
matrix:
- os: [ubuntu-latest, windows-latest, macos-latest]
+ os: [ubuntu-latest] #windows-latest, macos-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-java@v5
diff --git a/app/pom.xml b/app/pom.xml
index 962806c..e6a8434 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -13,6 +13,12 @@
UTF-8
+
+ com.diffplug.spotless
+ spotless-maven-plugin
+ 2.46.1
+
+
org.tooppism_framework
@@ -58,6 +64,41 @@
+
+ com.diffplug.spotless
+ spotless-maven-plugin
+ 2.46.1
+
+
+ origin/main
+
+
+
+
+
+ .gitattributes
+ .gitignore
+
+
+
+
+
+ true
+ 4
+
+
+
+
+
+
+ 1.28.0
+
+ true
+ true
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/org/toop/Main.java b/app/src/main/java/org/toop/Main.java
index a79e324..77f6e6c 100644
--- a/app/src/main/java/org/toop/Main.java
+++ b/app/src/main/java/org/toop/Main.java
@@ -1,57 +1,86 @@
package org.toop;
+import java.util.Arrays;
+import org.toop.app.gui.LocalServerSelector;
import org.toop.framework.eventbus.EventFlow;
-import org.toop.framework.networking.events.NetworkEvents;
import org.toop.framework.networking.NetworkingClientManager;
import org.toop.framework.networking.NetworkingInitializationException;
-import org.toop.app.gui.LocalServerSelector;
-
-import java.util.Arrays;
+import org.toop.framework.networking.events.NetworkEvents;
public class Main {
- static void main(String[] args) {
- initSystems();
+ static void main(String[] args) {
+ initSystems();
- EventFlow a = new EventFlow()
- .addPostEvent(
- NetworkEvents.StartClient.class,
- "127.0.0.1",
- 7789)
- .onResponse(Main::login)
-// .onResponse(Main::sendCommand)
-// .onResponse(Main::closeClient)
- .asyncPostEvent();
+ EventFlow a =
+ new EventFlow()
+ .addPostEvent(NetworkEvents.StartClient.class, "127.0.0.1", 7789)
+ .onResponse(Main::login)
+ // .onResponse(Main::sendCommand)
+ // .onResponse(Main::closeClient)
+ .asyncPostEvent();
- new Thread(() -> {
- while (a.getResult() == null) {
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {}
- }
- long clid = (Long) a.getResult().get("clientId");
- new EventFlow()
- .addPostEvent(new NetworkEvents.SendCommand(clid, "get playerlist"))
- .listen(NetworkEvents.PlayerListResponse.class, response -> {
- if (response.clientId() == clid) System.out.println(Arrays.toString(response.playerlist()));
- })
- .asyncPostEvent();
- }).start();
+ new Thread(
+ () -> {
+ while (a.getResult() == null) {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ }
+ }
+ long clid = (Long) a.getResult().get("clientId");
+ new EventFlow()
+ .addPostEvent(
+ new NetworkEvents.SendSubscribe(clid, "tic-tac-toe"))
+ .listen(
+ NetworkEvents.PlayerlistResponse.class,
+ response -> {
+ if (response.clientId() == clid)
+ System.out.println(
+ Arrays.toString(response.playerlist()));
+ })
+ .listen(
+ NetworkEvents.ChallengeResponse.class,
+ response -> {
+ if (response.clientId() == clid)
+ System.out.println(response.challengeId());
+ })
+ .listen(
+ NetworkEvents.ChallengeCancelledResponse.class,
+ response -> {
+ if (response.clientId() == clid)
+ System.out.println(response.challengeId());
+ })
+ .listen(
+ NetworkEvents.GamelistResponse.class,
+ response -> {
+ if (response.clientId() == clid)
+ System.out.println(
+ Arrays.toString(response.gamelist()));
+ })
+ .asyncPostEvent();
+ })
+ .start();
- new Thread(() -> javax.swing.SwingUtilities.invokeLater(LocalServerSelector::new)).start();
- }
+ new Thread(() -> javax.swing.SwingUtilities.invokeLater(LocalServerSelector::new)).start();
+ }
- private static void login(NetworkEvents.StartClientResponse event) {
- new Thread(() -> {
- try {
- Thread.sleep(1000);
- new EventFlow()
- .addPostEvent(new NetworkEvents.SendCommand(event.clientId(), "login bas"))
- .asyncPostEvent();
- } catch (InterruptedException e) {}
- }).start();
- }
+ private static void login(NetworkEvents.StartClientResponse event) {
+ new Thread(
+ () -> {
+ try {
+ Thread.sleep(1000);
+ new EventFlow()
+ .addPostEvent(
+ new NetworkEvents.SendCommand(
+ event.clientId(), "login bas"))
+ .asyncPostEvent();
+ } catch (InterruptedException e) {
+ }
+ })
+ .start();
+ }
- private static void initSystems() throws NetworkingInitializationException {
- new NetworkingClientManager();
- }
-}
\ No newline at end of file
+ private static void initSystems() throws NetworkingInitializationException {
+ new NetworkingClientManager();
+ }
+}
diff --git a/app/src/main/java/org/toop/app/gui/RemoteGameSelector.java b/app/src/main/java/org/toop/app/gui/RemoteGameSelector.java
index 8a62644..3e09acc 100644
--- a/app/src/main/java/org/toop/app/gui/RemoteGameSelector.java
+++ b/app/src/main/java/org/toop/app/gui/RemoteGameSelector.java
@@ -7,9 +7,9 @@ import javax.swing.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.toop.framework.eventbus.EventFlow;
+import org.toop.framework.networking.NetworkingGameClientHandler;
import org.toop.framework.networking.events.NetworkEvents;
import org.toop.tictactoe.LocalTicTacToe;
-import org.toop.framework.networking.NetworkingGameClientHandler;
import org.toop.tictactoe.gui.UIGameBoard;
public class RemoteGameSelector {
@@ -55,36 +55,44 @@ public class RemoteGameSelector {
&& !portTextField.getText().isEmpty()) {
AtomicReference clientId = new AtomicReference<>();
- new EventFlow().addPostEvent(
- NetworkEvents.StartClient.class,
- (Supplier)
- new NetworkingGameClientHandler(clientId.get()),
- "127.0.0.1",
- 5001
- ).onResponse(
- NetworkEvents.StartClientResponse.class,
- (response) -> {
- clientId.set(response.clientId());
- }
- ).asyncPostEvent();
+ new EventFlow()
+ .addPostEvent(
+ NetworkEvents.StartClient.class,
+ (Supplier)
+ new NetworkingGameClientHandler(clientId.get()),
+ "127.0.0.1",
+ 5001)
+ .onResponse(
+ NetworkEvents.StartClientResponse.class,
+ (response) -> {
+ clientId.set(response.clientId());
+ })
+ .asyncPostEvent();
-// GlobalEventBus.subscribeAndRegister(
-// NetworkEvents.ReceivedMessage.class,
-// event -> {
-// if (event.message().equalsIgnoreCase("ok")) {
-// logger.info("received ok from server.");
-// } else if (event.message().toLowerCase().startsWith("gameid")) {
-// String gameId =
-// event.message()
-// .toLowerCase()
-// .replace("gameid ", "");
-// GlobalEventBus.post(
-// new NetworkEvents.SendCommand(
-// "start_game " + gameId));
-// } else {
-// logger.info("{}", event.message());
-// }
-// });
+ // GlobalEventBus.subscribeAndRegister(
+ // NetworkEvents.ReceivedMessage.class,
+ // event -> {
+ // if
+ // (event.message().equalsIgnoreCase("ok")) {
+ // logger.info("received ok from
+ // server.");
+ // } else if
+ // (event.message().toLowerCase().startsWith("gameid")) {
+ // String gameId =
+ // event.message()
+ // .toLowerCase()
+ // .replace("gameid
+ // ", "");
+ // GlobalEventBus.post(
+ // new
+ // NetworkEvents.SendCommand(
+ // "start_game " +
+ // gameId));
+ // } else {
+ // logger.info("{}",
+ // event.message());
+ // }
+ // });
frame.remove(mainMenu);
UIGameBoard ttt = new UIGameBoard(localTicTacToe, this);
localTicTacToe.startThreads();
diff --git a/app/src/main/java/org/toop/tictactoe/LocalTicTacToe.java b/app/src/main/java/org/toop/tictactoe/LocalTicTacToe.java
index 1e7e017..3503334 100644
--- a/app/src/main/java/org/toop/tictactoe/LocalTicTacToe.java
+++ b/app/src/main/java/org/toop/tictactoe/LocalTicTacToe.java
@@ -1,7 +1,6 @@
package org.toop.tictactoe;
import java.util.concurrent.*;
-
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.toop.framework.eventbus.EventFlow;
@@ -10,11 +9,6 @@ import org.toop.game.Game;
import org.toop.game.tictactoe.TicTacToe;
import org.toop.game.tictactoe.TicTacToeAI;
import org.toop.tictactoe.gui.UIGameBoard;
-import org.toop.framework.networking.NetworkingGameClientHandler;
-
-import java.util.function.Supplier;
-
-import static java.lang.Thread.sleep;
/**
* A representation of a local tic-tac-toe game. Calls are made to a server for information about
@@ -71,24 +65,25 @@ public class LocalTicTacToe { // TODO: Implement runnable
* @param port The port of the server to connect to.
*/
private LocalTicTacToe(String ip, int port) {
-// this.receivedMessageListener =
-// GlobalEventBus.subscribe(this::receiveMessageAction);
-// GlobalEventBus.subscribe(this.receivedMessageListener);
-// this.connectionId = this.createConnection(ip, port); TODO: Refactor this
+ // this.receivedMessageListener =
+ // GlobalEventBus.subscribe(this::receiveMessageAction);
+ // GlobalEventBus.subscribe(this.receivedMessageListener);
+ // this.connectionId = this.createConnection(ip, port); TODO: Refactor this
this.createGame("X", "O");
this.isLocal = false;
- //this.executor.submit(this::remoteGameThread);
+ // this.executor.submit(this::remoteGameThread);
}
private LocalTicTacToe(boolean[] aiFlags) {
this.isAiPlayer = aiFlags; // store who is AI
this.isLocal = true;
- //this.executor.submit(this::localGameThread);
+ // this.executor.submit(this::localGameThread);
}
- public void startThreads(){
+
+ public void startThreads() {
if (isLocal) {
this.executor.submit(this::localGameThread);
- }else {
+ } else {
this.executor.submit(this::remoteGameThread);
}
}
@@ -124,10 +119,10 @@ public class LocalTicTacToe { // TODO: Implement runnable
state = this.ticTacToe.play(this.moveQueuePlayerA.take());
} else {
Game.Move bestMove = ai.findBestMove(this.ticTacToe, 9);
- assert bestMove != null;
+ assert bestMove != null;
- state = this.ticTacToe.play(bestMove);
- ui.setCell(bestMove.position(), "X");
+ state = this.ticTacToe.play(bestMove);
+ ui.setCell(bestMove.position(), "X");
}
if (state == Game.State.WIN || state == Game.State.DRAW) {
ui.setState(state, "X");
@@ -138,9 +133,9 @@ public class LocalTicTacToe { // TODO: Implement runnable
state = this.ticTacToe.play(this.moveQueuePlayerB.take());
} else {
Game.Move bestMove = ai.findBestMove(this.ticTacToe, 9);
- assert bestMove != null;
- state = this.ticTacToe.play(bestMove);
- ui.setCell(bestMove.position(), "O");
+ assert bestMove != null;
+ state = this.ticTacToe.play(bestMove);
+ ui.setCell(bestMove.position(), "O");
}
if (state == Game.State.WIN || state == Game.State.DRAW) {
ui.setState(state, "O");
@@ -166,8 +161,8 @@ public class LocalTicTacToe { // TODO: Implement runnable
}
public char[] getCurrentBoard() {
- //return ticTacToe.getGrid();
- return new char[2];
+ // return ticTacToe.getGrid();
+ return new char[2];
}
/** End the current game. */
@@ -206,7 +201,7 @@ public class LocalTicTacToe { // TODO: Implement runnable
private void endTheGame() {
this.sendCommand("end_game", this.gameId);
-// this.endListeners();
+ // this.endListeners();
}
private void receiveMessageAction(NetworkEvents.ReceivedMessage receivedMessage) {
@@ -215,8 +210,7 @@ public class LocalTicTacToe { // TODO: Implement runnable
}
try {
- logger.info(
- "Received message from {}: {}", this.clientId, receivedMessage.message());
+ logger.info("Received message from {}: {}", this.clientId, receivedMessage.message());
this.receivedQueue.put(receivedMessage.message());
} catch (InterruptedException e) {
logger.error("Error waiting for received Message", e);
@@ -224,12 +218,14 @@ public class LocalTicTacToe { // TODO: Implement runnable
}
private void sendCommand(String... args) {
- new EventFlow().addPostEvent(NetworkEvents.SendCommand.class, this.clientId, args).asyncPostEvent();
+ new EventFlow()
+ .addPostEvent(NetworkEvents.SendCommand.class, this.clientId, args)
+ .asyncPostEvent();
}
-// private void endListeners() {
-// GlobalEventBus.unregister(this.receivedMessageListener);
-// } TODO
+ // private void endListeners() {
+ // GlobalEventBus.unregister(this.receivedMessageListener);
+ // } TODO
public void setUIReference(UIGameBoard uiGameBoard) {
this.ui = uiGameBoard;
diff --git a/framework/pom.xml b/framework/pom.xml
index e924481..4356334 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -13,6 +13,12 @@
+
+ com.diffplug.spotless
+ spotless-maven-plugin
+ 2.46.1
+
+
io.nettynetty-all
@@ -123,6 +129,41 @@
+
+ com.diffplug.spotless
+ spotless-maven-plugin
+ 2.46.1
+
+
+ origin/main
+
+
+
+
+
+ .gitattributes
+ .gitignore
+
+
+
+
+
+ true
+ 4
+
+
+
+
+
+
+ 1.28.0
+
+ true
+ true
+
+
+
+
diff --git a/framework/src/main/java/org/toop/framework/SnowflakeGenerator.java b/framework/src/main/java/org/toop/framework/SnowflakeGenerator.java
index 3f6830d..a48a8a7 100644
--- a/framework/src/main/java/org/toop/framework/SnowflakeGenerator.java
+++ b/framework/src/main/java/org/toop/framework/SnowflakeGenerator.java
@@ -42,9 +42,14 @@ public class SnowflakeGenerator {
}
}
+ void setTime(long l) {
+ this.lastTimestamp.set(l);
+ }
+
public SnowflakeGenerator() {
if (machineId < 0 || machineId > MAX_MACHINE_ID) {
- throw new IllegalArgumentException("Machine ID must be between 0 and " + MAX_MACHINE_ID);
+ throw new IllegalArgumentException(
+ "Machine ID must be between 0 and " + MAX_MACHINE_ID);
}
}
@@ -87,4 +92,4 @@ public class SnowflakeGenerator {
private long timestamp() {
return System.currentTimeMillis();
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/main/java/org/toop/framework/eventbus/EventFlow.java b/framework/src/main/java/org/toop/framework/eventbus/EventFlow.java
index 6092fb8..4c4a8de 100644
--- a/framework/src/main/java/org/toop/framework/eventbus/EventFlow.java
+++ b/framework/src/main/java/org/toop/framework/eventbus/EventFlow.java
@@ -1,9 +1,5 @@
package org.toop.framework.eventbus;
-import org.toop.framework.SnowflakeGenerator;
-import org.toop.framework.eventbus.events.EventType;
-import org.toop.framework.eventbus.events.EventWithSnowflake;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -13,20 +9,21 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Supplier;
+import org.toop.framework.SnowflakeGenerator;
+import org.toop.framework.eventbus.events.EventType;
+import org.toop.framework.eventbus.events.EventWithSnowflake;
/**
- * EventFlow is a utility class for creating, posting, and optionally subscribing to events
- * in a type-safe and chainable manner. It is designed to work with the {@link GlobalEventBus}.
+ * EventFlow is a utility class for creating, posting, and optionally subscribing to events in a
+ * type-safe and chainable manner. It is designed to work with the {@link GlobalEventBus}.
*
- *
This class supports automatic UUID assignment for {@link EventWithSnowflake} events,
- * and allows filtering subscribers so they only respond to events with a specific UUID.
- * All subscription methods are chainable, and you can configure automatic unsubscription
- * after an event has been successfully handled.
+ *
This class supports automatic UUID assignment for {@link EventWithSnowflake} events, and
+ * allows filtering subscribers so they only respond to events with a specific UUID. All
+ * subscription methods are chainable, and you can configure automatic unsubscription after an event
+ * has been successfully handled.
*/
public class EventFlow {
-
-
/** Lookup object used for dynamically invoking constructors via MethodHandles. */
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
@@ -65,15 +62,20 @@ public class EventFlow {
try {
boolean isUuidEvent = EventWithSnowflake.class.isAssignableFrom(eventClass);
- MethodHandle ctorHandle = CONSTRUCTOR_CACHE.computeIfAbsent(eventClass, cls -> {
- try {
- Class>[] paramTypes = cls.getDeclaredConstructors()[0].getParameterTypes();
- MethodType mt = MethodType.methodType(void.class, paramTypes);
- return LOOKUP.findConstructor(cls, mt);
- } catch (Exception e) {
- throw new RuntimeException("Failed to find constructor handle for " + cls, e);
- }
- });
+ MethodHandle ctorHandle =
+ CONSTRUCTOR_CACHE.computeIfAbsent(
+ eventClass,
+ cls -> {
+ try {
+ Class>[] paramTypes =
+ cls.getDeclaredConstructors()[0].getParameterTypes();
+ MethodType mt = MethodType.methodType(void.class, paramTypes);
+ return LOOKUP.findConstructor(cls, mt);
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Failed to find constructor handle for " + cls, e);
+ }
+ });
Object[] finalArgs;
int expectedParamCount = ctorHandle.type().parameterCount();
@@ -98,67 +100,69 @@ public class EventFlow {
}
}
-// public EventFlow addSnowflake() {
-// this.eventSnowflake = new SnowflakeGenerator(1).nextId();
-// return this;
-// }
+ // public EventFlow addSnowflake() {
+ // this.eventSnowflake = new SnowflakeGenerator(1).nextId();
+ // return this;
+ // }
- /**
- * Subscribe by ID: only fires if UUID matches this publisher's eventId.
- */
- public EventFlow onResponse(Class eventClass, Consumer action,
- boolean unsubscribeAfterSuccess) {
+ /** Subscribe by ID: only fires if UUID matches this publisher's eventId. */
+ public EventFlow onResponse(
+ Class eventClass, Consumer action, boolean unsubscribeAfterSuccess) {
ListenerHandler[] listenerHolder = new ListenerHandler[1];
- listenerHolder[0] = new ListenerHandler(
- GlobalEventBus.subscribe(eventClass, event -> {
- if (event.eventSnowflake() != this.eventSnowflake) return;
+ listenerHolder[0] =
+ new ListenerHandler(
+ GlobalEventBus.subscribe(
+ eventClass,
+ event -> {
+ if (event.eventSnowflake() != this.eventSnowflake) return;
- action.accept(event);
+ action.accept(event);
- if (unsubscribeAfterSuccess && listenerHolder[0] != null) {
- GlobalEventBus.unsubscribe(listenerHolder[0]);
- this.listeners.remove(listenerHolder[0]);
- }
+ if (unsubscribeAfterSuccess && listenerHolder[0] != null) {
+ GlobalEventBus.unsubscribe(listenerHolder[0]);
+ this.listeners.remove(listenerHolder[0]);
+ }
- this.result = event.result();
- })
- );
+ this.result = event.result();
+ }));
this.listeners.add(listenerHolder[0]);
return this;
}
- /**
- * Subscribe by ID: only fires if UUID matches this publisher's eventId.
- */
- public EventFlow onResponse(Class eventClass, Consumer action) {
+ /** Subscribe by ID: only fires if UUID matches this publisher's eventId. */
+ public EventFlow onResponse(
+ Class eventClass, Consumer action) {
return this.onResponse(eventClass, action, true);
}
- /**
- * Subscribe by ID without explicit class.
- */
+ /** Subscribe by ID without explicit class. */
@SuppressWarnings("unchecked")
- public EventFlow onResponse(Consumer action, boolean unsubscribeAfterSuccess) {
+ public EventFlow onResponse(
+ Consumer action, boolean unsubscribeAfterSuccess) {
ListenerHandler[] listenerHolder = new ListenerHandler[1];
- listenerHolder[0] = new ListenerHandler(
- GlobalEventBus.subscribe(event -> {
- if (!(event instanceof EventWithSnowflake uuidEvent)) return;
- if (uuidEvent.eventSnowflake() == this.eventSnowflake) {
- try {
- TT typedEvent = (TT) uuidEvent;
- action.accept(typedEvent);
- if (unsubscribeAfterSuccess && listenerHolder[0] != null) {
- GlobalEventBus.unsubscribe(listenerHolder[0]);
- this.listeners.remove(listenerHolder[0]);
- }
- this.result = typedEvent.result();
- } catch (ClassCastException _) {
- throw new ClassCastException("Cannot cast " + event.getClass().getName() +
- " to EventWithSnowflake");
- }
- }
- })
- );
+ listenerHolder[0] =
+ new ListenerHandler(
+ GlobalEventBus.subscribe(
+ event -> {
+ if (!(event instanceof EventWithSnowflake uuidEvent)) return;
+ if (uuidEvent.eventSnowflake() == this.eventSnowflake) {
+ try {
+ TT typedEvent = (TT) uuidEvent;
+ action.accept(typedEvent);
+ if (unsubscribeAfterSuccess
+ && listenerHolder[0] != null) {
+ GlobalEventBus.unsubscribe(listenerHolder[0]);
+ this.listeners.remove(listenerHolder[0]);
+ }
+ this.result = typedEvent.result();
+ } catch (ClassCastException _) {
+ throw new ClassCastException(
+ "Cannot cast "
+ + event.getClass().getName()
+ + " to EventWithSnowflake");
+ }
+ }
+ }));
this.listeners.add(listenerHolder[0]);
return this;
}
@@ -167,19 +171,21 @@ public class EventFlow {
return this.onResponse(action, true);
}
- public EventFlow listen(Class eventClass, Consumer action,
- boolean unsubscribeAfterSuccess) {
+ public EventFlow listen(
+ Class eventClass, Consumer action, boolean unsubscribeAfterSuccess) {
ListenerHandler[] listenerHolder = new ListenerHandler[1];
- listenerHolder[0] = new ListenerHandler(
- GlobalEventBus.subscribe(eventClass, event -> {
- action.accept(event);
+ listenerHolder[0] =
+ new ListenerHandler(
+ GlobalEventBus.subscribe(
+ eventClass,
+ event -> {
+ action.accept(event);
- if (unsubscribeAfterSuccess && listenerHolder[0] != null) {
- GlobalEventBus.unsubscribe(listenerHolder[0]);
- this.listeners.remove(listenerHolder[0]);
- }
- })
- );
+ if (unsubscribeAfterSuccess && listenerHolder[0] != null) {
+ GlobalEventBus.unsubscribe(listenerHolder[0]);
+ this.listeners.remove(listenerHolder[0]);
+ }
+ }));
this.listeners.add(listenerHolder[0]);
return this;
}
@@ -189,24 +195,28 @@ public class EventFlow {
}
@SuppressWarnings("unchecked")
- public EventFlow listen(Consumer action, boolean unsubscribeAfterSuccess) {
+ public EventFlow listen(
+ Consumer action, boolean unsubscribeAfterSuccess) {
ListenerHandler[] listenerHolder = new ListenerHandler[1];
- listenerHolder[0] = new ListenerHandler(
- GlobalEventBus.subscribe(event -> {
- if (!(event instanceof EventType nonUuidEvent)) return;
- try {
- TT typedEvent = (TT) nonUuidEvent;
- action.accept(typedEvent);
- if (unsubscribeAfterSuccess && listenerHolder[0] != null) {
- GlobalEventBus.unsubscribe(listenerHolder[0]);
- this.listeners.remove(listenerHolder[0]);
- }
- } catch (ClassCastException _) {
- throw new ClassCastException("Cannot cast " + event.getClass().getName() +
- " to EventWithSnowflake");
- }
- })
- );
+ listenerHolder[0] =
+ new ListenerHandler(
+ GlobalEventBus.subscribe(
+ event -> {
+ if (!(event instanceof EventType nonUuidEvent)) return;
+ try {
+ TT typedEvent = (TT) nonUuidEvent;
+ action.accept(typedEvent);
+ if (unsubscribeAfterSuccess && listenerHolder[0] != null) {
+ GlobalEventBus.unsubscribe(listenerHolder[0]);
+ this.listeners.remove(listenerHolder[0]);
+ }
+ } catch (ClassCastException _) {
+ throw new ClassCastException(
+ "Cannot cast "
+ + event.getClass().getName()
+ + " to EventWithSnowflake");
+ }
+ }));
this.listeners.add(listenerHolder[0]);
return this;
}
diff --git a/framework/src/main/java/org/toop/framework/eventbus/GlobalEventBus.java b/framework/src/main/java/org/toop/framework/eventbus/GlobalEventBus.java
index 44a84f4..41386bf 100644
--- a/framework/src/main/java/org/toop/framework/eventbus/GlobalEventBus.java
+++ b/framework/src/main/java/org/toop/framework/eventbus/GlobalEventBus.java
@@ -3,26 +3,26 @@ package org.toop.framework.eventbus;
import com.lmax.disruptor.*;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
-import org.toop.framework.eventbus.events.EventType;
-import org.toop.framework.eventbus.events.EventWithSnowflake;
-
import java.util.Map;
import java.util.concurrent.*;
import java.util.function.Consumer;
+import org.toop.framework.eventbus.events.EventType;
+import org.toop.framework.eventbus.events.EventWithSnowflake;
/**
- * GlobalEventBus backed by the LMAX Disruptor for ultra-low latency,
- * high-throughput event publishing.
+ * GlobalEventBus backed by the LMAX Disruptor for ultra-low latency, high-throughput event
+ * publishing.
*/
public final class GlobalEventBus {
/** Map of event class to type-specific listeners. */
- private static final Map, CopyOnWriteArrayList>> LISTENERS =
- new ConcurrentHashMap<>();
+ private static final Map, CopyOnWriteArrayList>>
+ LISTENERS = new ConcurrentHashMap<>();
/** Map of event class to Snowflake-ID-specific listeners. */
- private static final Map, ConcurrentHashMap>> UUID_LISTENERS =
- new ConcurrentHashMap<>();
+ private static final Map<
+ Class>, ConcurrentHashMap>>
+ UUID_LISTENERS = new ConcurrentHashMap<>();
/** Disruptor ring buffer size (must be power of two). */
private static final int RING_BUFFER_SIZE = 1024 * 64;
@@ -34,27 +34,29 @@ public final class GlobalEventBus {
private static final RingBuffer RING_BUFFER;
static {
- ThreadFactory threadFactory = r -> {
- Thread t = new Thread(r, "EventBus-Disruptor");
- t.setDaemon(true);
- return t;
- };
+ ThreadFactory threadFactory =
+ r -> {
+ Thread t = new Thread(r, "EventBus-Disruptor");
+ t.setDaemon(true);
+ return t;
+ };
- DISRUPTOR = new Disruptor<>(
- EventHolder::new,
- RING_BUFFER_SIZE,
- threadFactory,
- ProducerType.MULTI,
- new BusySpinWaitStrategy()
- );
+ DISRUPTOR =
+ new Disruptor<>(
+ EventHolder::new,
+ RING_BUFFER_SIZE,
+ threadFactory,
+ ProducerType.MULTI,
+ new BusySpinWaitStrategy());
// Single consumer that dispatches to subscribers
- DISRUPTOR.handleEventsWith((holder, seq, endOfBatch) -> {
- if (holder.event != null) {
- dispatchEvent(holder.event);
- holder.event = null;
- }
- });
+ DISRUPTOR.handleEventsWith(
+ (holder, seq, endOfBatch) -> {
+ if (holder.event != null) {
+ dispatchEvent(holder.event);
+ holder.event = null;
+ }
+ });
DISRUPTOR.start();
RING_BUFFER = DISRUPTOR.getRingBuffer();
@@ -71,17 +73,21 @@ public final class GlobalEventBus {
// ------------------------------------------------------------------------
// Subscription
// ------------------------------------------------------------------------
- public static Consumer subscribe(Class eventClass, Consumer listener) {
+ public static Consumer super EventType> subscribe(
+ Class eventClass, Consumer listener) {
+
CopyOnWriteArrayList> list =
LISTENERS.computeIfAbsent(eventClass, k -> new CopyOnWriteArrayList<>());
- list.add(event -> listener.accept(eventClass.cast(event)));
- return listener;
+
+ Consumer super EventType> wrapper = event -> listener.accept(eventClass.cast(event));
+ list.add(wrapper);
+ return wrapper;
}
- public static Consumer