Added EventMeta data, EventRegistry

This commit is contained in:
lieght
2025-09-10 20:09:50 +02:00
parent 349c12a778
commit 843ad3b3bd
7 changed files with 208 additions and 16 deletions

View File

@@ -1,5 +1,6 @@
package org.toop; package org.toop;
import org.toop.eventbus.EventRegistry;
import org.toop.eventbus.Events; import org.toop.eventbus.Events;
import org.toop.eventbus.GlobalEventBus; import org.toop.eventbus.GlobalEventBus;
import org.toop.server.Server; import org.toop.server.Server;
@@ -7,6 +8,18 @@ import org.toop.server.Server;
public class Main { public class Main {
public static void main(String[] args) { 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 server = new Server(Server.ServerBackend.LOCAL, "127.0.0.1", "5000");
server.setBackend(Server.ServerBackend.REMOTE); server.setBackend(Server.ServerBackend.REMOTE);
@@ -17,15 +30,17 @@ public class Main {
else if (e.command() == Server.Command.HELP) { else if (e.command() == Server.Command.HELP) {
System.out.println("HELP command -> " + String.join(" ", e.args())); System.out.println("HELP command -> " + String.join(" ", e.args()));
} }
}); else {
System.out.println(e.command().toString());
GlobalEventBus.subscribeAndRegister(Events.ServerEvents.OnChangingServerBackend.class, e -> { }
System.out.println("Server backend has changed to -> " + e.backend());
}); });
Server.Message msg = server.sendCommand(Server.Command.LOGIN, "move"); Server.Message msg = server.sendCommand(Server.Command.LOGIN, "move");
server.sendCommand(Server.Command.HELP, "test", "test2"); 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); server.setBackend(Server.ServerBackend.REMOTE);
System.out.println(msg); System.out.println(msg);

View File

@@ -0,0 +1,41 @@
package org.toop.eventbus;
/**
* Wraps an event with its type and a ready flag.
*/
public class EventMeta<T> {
private final Class<T> type;
private final Object event;
private boolean ready;
public EventMeta(Class<T> type, Object event) {
this.type = type;
this.event = event;
this.ready = false; // default not ready
}
public Class<T> 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 +
'}';
}
}

View File

@@ -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<Class<?>, CopyOnWriteArrayList<EventEntry<?>>> eventHistory =
new ConcurrentHashMap<>();
private static final Map<Class<?>, Boolean> readyStates = new ConcurrentHashMap<>();
/**
* Stores an event in the registry. Safe for concurrent use.
*/
public static <T> void storeEvent(EventMeta<T> eventMeta) {
eventHistory
.computeIfAbsent(eventMeta.getType(), k -> new CopyOnWriteArrayList<>())
.add(new EventEntry<>(eventMeta));
}
/**
* Marks a specific event type as ready (safe to post).
*/
public static <T> void markReady(Class<T> type) {
readyStates.put(type, true);
}
/**
* Marks a specific event type as not ready (posting will fail).
*/
public static <T> void markNotReady(Class<T> type) {
readyStates.put(type, false);
}
/**
* Returns true if this event type is marked ready.
*/
public static <T> boolean isReady(Class<T> type) {
return readyStates.getOrDefault(type, false);
}
/**
* Gets all stored events of a given type.
*/
@SuppressWarnings("unchecked")
public static <T> List<EventEntry<T>> getEvents(Class<T> type) {
return (List<EventEntry<T>>) (List<?>) eventHistory
.getOrDefault(type, new CopyOnWriteArrayList<>());
}
/**
* Gets the most recent event of a given type, or null if none exist.
*/
@SuppressWarnings("unchecked")
public static <T> EventEntry<T> getLastEvent(Class<T> type) {
List<EventEntry<?>> entries = eventHistory.get(type);
if (entries == null || entries.isEmpty()) {
return null;
}
return (EventEntry<T>) entries.get(entries.size() - 1);
}
/**
* Clears the stored events for a given type.
*/
public static <T> void clearEvents(Class<T> 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<T> {
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 +
'}';
}
}
}

View File

@@ -5,7 +5,7 @@ import org.toop.server.Server;
/** /**
* Events that are used in the GlobalEventBus class. * Events that are used in the GlobalEventBus class.
*/ */
public class Events { public class Events implements IEvents {
public static class ServerEvents { public static class ServerEvents {
/** /**

View File

@@ -30,12 +30,13 @@ public enum GlobalEventBus {
/** /**
* Wraps a Consumer into a Guava @Subscribe-compatible listener. * Wraps a Consumer into a Guava @Subscribe-compatible listener.
* TODO
* *
* @param type The event to be used. (e.g. Events.ServerCommand.class) * @param type The event to be used. (e.g. Events.ServerCommand.class)
* @param action The function, or lambda to run when fired. * @param action The function, or lambda to run when fired.
* @return Object to be used for registering an event. * @return Object to be used for registering an event.
*/ */
public static <T> Object subscribe(Class<T> type, Consumer<T> action) { private static <T> Object subscribe(Class<T> type, Consumer<T> action) {
return new Object() { return new Object() {
@Subscribe @Subscribe
public void handle(T event) { public void handle(T event) {
@@ -51,7 +52,7 @@ public enum GlobalEventBus {
* @param action The function, or lambda to run when fired. * @param action The function, or lambda to run when fired.
* @return Object to be used for registering an event. * @return Object to be used for registering an event.
*/ */
public static <T> Object subscribeAndRegister(Class<T> type, Consumer<T> action) { public static <T> EventMeta subscribeAndRegister(Class<T> type, Consumer<T> action) {
Object listener = new Object() { Object listener = new Object() {
@Subscribe @Subscribe
public void handle(Object event) { public void handle(Object event) {
@@ -60,30 +61,46 @@ public enum GlobalEventBus {
} }
} }
}; };
register(listener); var re = new EventMeta<>(type, listener);
return listener; register(re);
return re;
} }
/** /**
* Wrapper for registering a listener. * 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) { public static <T> void register(EventMeta<T> event) {
GlobalEventBus.INSTANCE.get().register(listener); GlobalEventBus.INSTANCE.get().register(event.getEvent());
event.setReady(true);
EventRegistry.markReady(event.getType());
} }
/** /**
* Wrapper for unregistering a listener. * 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) { public static <T> void unregister(EventMeta<T> event) {
GlobalEventBus.INSTANCE.get().unregister(listener); EventRegistry.markNotReady(event.getType());
event.setReady(false);
GlobalEventBus.INSTANCE.get().unregister(event.getEvent());
} }
public static void post(Object event) { public static <T> void post(T event) {
Class<T> type = (Class<T>) event.getClass();
if (!EventRegistry.isReady(type)) {
throw new IllegalStateException("Event type not ready: " + type.getSimpleName());
}
// store in registry
EventMeta<T> eventMeta = new EventMeta<>(type, event);
EventRegistry.storeEvent(eventMeta);
// post to Guava EventBus
GlobalEventBus.INSTANCE.get().post(event); GlobalEventBus.INSTANCE.get().post(event);
} }

View File

@@ -0,0 +1,3 @@
package org.toop.eventbus;
public interface IEvents {}

View File

@@ -1,5 +1,6 @@
package org.toop.server; package org.toop.server;
import org.toop.eventbus.EventRegistry;
import org.toop.eventbus.Events; import org.toop.eventbus.Events;
import org.toop.eventbus.GlobalEventBus; import org.toop.eventbus.GlobalEventBus;
import org.toop.server.backend.*; import org.toop.server.backend.*;