From 843ad3b3bdce4913daa2b030f3338d92243718ce Mon Sep 17 00:00:00 2001 From: lieght Date: Wed, 10 Sep 2025 20:09:50 +0200 Subject: [PATCH] Added EventMeta data, EventRegistry --- src/main/java/org/toop/Main.java | 23 +++- .../java/org/toop/eventbus/EventMeta.java | 41 +++++++ .../java/org/toop/eventbus/EventRegistry.java | 115 ++++++++++++++++++ src/main/java/org/toop/eventbus/Events.java | 2 +- .../org/toop/eventbus/GlobalEventBus.java | 39 ++++-- src/main/java/org/toop/eventbus/IEvents.java | 3 + src/main/java/org/toop/server/Server.java | 1 + 7 files changed, 208 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/toop/eventbus/EventMeta.java create mode 100644 src/main/java/org/toop/eventbus/EventRegistry.java create mode 100644 src/main/java/org/toop/eventbus/IEvents.java diff --git a/src/main/java/org/toop/Main.java b/src/main/java/org/toop/Main.java index 95a91b8..520a608 100644 --- a/src/main/java/org/toop/Main.java +++ b/src/main/java/org/toop/Main.java @@ -1,5 +1,6 @@ package org.toop; +import org.toop.eventbus.EventRegistry; import org.toop.eventbus.Events; import org.toop.eventbus.GlobalEventBus; import org.toop.server.Server; @@ -7,6 +8,18 @@ import org.toop.server.Server; public class Main { public static void main(String[] args) { + GlobalEventBus.subscribeAndRegister(Events.ServerEvents.OnChangingServerBackend.class, e -> { + System.out.println("Server backend has changed to -> " + e.backend()); + }); + + GlobalEventBus.subscribeAndRegister(Events.ServerEvents.OnChangingServerIp.class, e -> { + System.out.println("Server ip has changed to -> " + e.ip()); + }); + + GlobalEventBus.subscribeAndRegister(Events.ServerEvents.OnChangingServerPort.class, e -> { + System.out.println("Server port has changed to -> " + e.port()); + }); + Server server = new Server(Server.ServerBackend.LOCAL, "127.0.0.1", "5000"); server.setBackend(Server.ServerBackend.REMOTE); @@ -17,15 +30,17 @@ public class Main { else if (e.command() == Server.Command.HELP) { System.out.println("HELP command -> " + String.join(" ", e.args())); } - }); - - GlobalEventBus.subscribeAndRegister(Events.ServerEvents.OnChangingServerBackend.class, e -> { - System.out.println("Server backend has changed to -> " + e.backend()); + else { + System.out.println(e.command().toString()); + } }); Server.Message msg = server.sendCommand(Server.Command.LOGIN, "move"); server.sendCommand(Server.Command.HELP, "test", "test2"); + server.sendCommand(Server.Command.BYE); + GlobalEventBus.post(new Events.ServerEvents.changeServerIp("127.1.1.1")); + GlobalEventBus.post(new Events.ServerEvents.changeServerPort("5003")); server.setBackend(Server.ServerBackend.REMOTE); System.out.println(msg); diff --git a/src/main/java/org/toop/eventbus/EventMeta.java b/src/main/java/org/toop/eventbus/EventMeta.java new file mode 100644 index 0000000..4b28640 --- /dev/null +++ b/src/main/java/org/toop/eventbus/EventMeta.java @@ -0,0 +1,41 @@ +package org.toop.eventbus; + +/** + * Wraps an event with its type and a ready flag. + */ +public class EventMeta { + private final Class type; + private final Object event; + private boolean ready; + + public EventMeta(Class type, Object event) { + this.type = type; + this.event = event; + this.ready = false; // default not ready + } + + public Class getType() { + return type; + } + + public Object getEvent() { + return event; + } + + public boolean isReady() { + return ready; + } + + public void setReady(boolean ready) { + this.ready = ready; + } + + @Override + public String toString() { + return "ReadyEvent{" + + "type=" + type.getSimpleName() + + ", event=" + event + + ", ready=" + ready + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/org/toop/eventbus/EventRegistry.java b/src/main/java/org/toop/eventbus/EventRegistry.java new file mode 100644 index 0000000..d613137 --- /dev/null +++ b/src/main/java/org/toop/eventbus/EventRegistry.java @@ -0,0 +1,115 @@ +package org.toop.eventbus; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Thread-safe registry for storing events and tracking readiness of event types. + */ +public class EventRegistry { + + private static final Map, CopyOnWriteArrayList>> eventHistory = + new ConcurrentHashMap<>(); + + private static final Map, Boolean> readyStates = new ConcurrentHashMap<>(); + + /** + * Stores an event in the registry. Safe for concurrent use. + */ + public static void storeEvent(EventMeta eventMeta) { + eventHistory + .computeIfAbsent(eventMeta.getType(), k -> new CopyOnWriteArrayList<>()) + .add(new EventEntry<>(eventMeta)); + } + + /** + * Marks a specific event type as ready (safe to post). + */ + public static void markReady(Class type) { + readyStates.put(type, true); + } + + /** + * Marks a specific event type as not ready (posting will fail). + */ + public static void markNotReady(Class type) { + readyStates.put(type, false); + } + + /** + * Returns true if this event type is marked ready. + */ + public static boolean isReady(Class type) { + return readyStates.getOrDefault(type, false); + } + + /** + * Gets all stored events of a given type. + */ + @SuppressWarnings("unchecked") + public static List> getEvents(Class type) { + return (List>) (List) eventHistory + .getOrDefault(type, new CopyOnWriteArrayList<>()); + } + + /** + * Gets the most recent event of a given type, or null if none exist. + */ + @SuppressWarnings("unchecked") + public static EventEntry getLastEvent(Class type) { + List> entries = eventHistory.get(type); + if (entries == null || entries.isEmpty()) { + return null; + } + return (EventEntry) entries.get(entries.size() - 1); + } + + /** + * Clears the stored events for a given type. + */ + public static void clearEvents(Class type) { + eventHistory.remove(type); + } + + /** + * Clears all events and resets readiness. + */ + public static void reset() { + eventHistory.clear(); + readyStates.clear(); + } + + /** + * Wrapper for stored events, with a ready flag for per-event state. + */ + public static class EventEntry { + private final T event; + private volatile boolean ready = false; + + public EventEntry(T event) { + this.event = event; + } + + public T getEvent() { + return event; + } + + public boolean isReady() { + return ready; + } + + public void setReady(boolean ready) { + this.ready = ready; + } + + @Override + public String toString() { + return "EventEntry{" + + "event=" + event + + ", ready=" + ready + + '}'; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/toop/eventbus/Events.java b/src/main/java/org/toop/eventbus/Events.java index 6aff0e8..9468810 100644 --- a/src/main/java/org/toop/eventbus/Events.java +++ b/src/main/java/org/toop/eventbus/Events.java @@ -5,7 +5,7 @@ import org.toop.server.Server; /** * Events that are used in the GlobalEventBus class. */ -public class Events { +public class Events implements IEvents { public static class ServerEvents { /** diff --git a/src/main/java/org/toop/eventbus/GlobalEventBus.java b/src/main/java/org/toop/eventbus/GlobalEventBus.java index 6c17dac..01a805b 100644 --- a/src/main/java/org/toop/eventbus/GlobalEventBus.java +++ b/src/main/java/org/toop/eventbus/GlobalEventBus.java @@ -30,12 +30,13 @@ public enum GlobalEventBus { /** * Wraps a Consumer into a Guava @Subscribe-compatible listener. + * TODO * * @param type The event to be used. (e.g. Events.ServerCommand.class) * @param action The function, or lambda to run when fired. * @return Object to be used for registering an event. */ - public static Object subscribe(Class type, Consumer action) { + private static Object subscribe(Class type, Consumer action) { return new Object() { @Subscribe public void handle(T event) { @@ -51,7 +52,7 @@ public enum GlobalEventBus { * @param action The function, or lambda to run when fired. * @return Object to be used for registering an event. */ - public static Object subscribeAndRegister(Class type, Consumer action) { + public static EventMeta subscribeAndRegister(Class type, Consumer action) { Object listener = new Object() { @Subscribe public void handle(Object event) { @@ -60,30 +61,46 @@ public enum GlobalEventBus { } } }; - register(listener); - return listener; + var re = new EventMeta<>(type, listener); + register(re); + return re; } /** * Wrapper for registering a listener. * - * @param listener The event listener to register. + * @param event The ready event to add to register. */ - public static void register(Object listener) { - GlobalEventBus.INSTANCE.get().register(listener); + public static void register(EventMeta event) { + GlobalEventBus.INSTANCE.get().register(event.getEvent()); + event.setReady(true); + EventRegistry.markReady(event.getType()); } /** * Wrapper for unregistering a listener. * - * @param listener The event listener to unregister. + * @param event The ready event to unregister. */ - public static void unregister(Object listener) { - GlobalEventBus.INSTANCE.get().unregister(listener); + public static void unregister(EventMeta event) { + EventRegistry.markNotReady(event.getType()); + event.setReady(false); + GlobalEventBus.INSTANCE.get().unregister(event.getEvent()); } - public static void post(Object event) { + public static void post(T event) { + Class type = (Class) event.getClass(); + + if (!EventRegistry.isReady(type)) { + throw new IllegalStateException("Event type not ready: " + type.getSimpleName()); + } + + // store in registry + EventMeta eventMeta = new EventMeta<>(type, event); + EventRegistry.storeEvent(eventMeta); + + // post to Guava EventBus GlobalEventBus.INSTANCE.get().post(event); } diff --git a/src/main/java/org/toop/eventbus/IEvents.java b/src/main/java/org/toop/eventbus/IEvents.java new file mode 100644 index 0000000..15fbb63 --- /dev/null +++ b/src/main/java/org/toop/eventbus/IEvents.java @@ -0,0 +1,3 @@ +package org.toop.eventbus; + +public interface IEvents {} diff --git a/src/main/java/org/toop/server/Server.java b/src/main/java/org/toop/server/Server.java index 850d536..9ef6ef6 100644 --- a/src/main/java/org/toop/server/Server.java +++ b/src/main/java/org/toop/server/Server.java @@ -1,5 +1,6 @@ package org.toop.server; +import org.toop.eventbus.EventRegistry; import org.toop.eventbus.Events; import org.toop.eventbus.GlobalEventBus; import org.toop.server.backend.*;