mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 19:04:49 +00:00
Renamed EventPublisher to EventFlow because of change in what it does.
This commit is contained in:
@@ -48,8 +48,8 @@ public class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void registerEvents() {
|
private static void registerEvents() {
|
||||||
new EventPublisher<>(Events.WindowEvents.OnQuitRequested.class, _ -> quit());
|
new EventPublisher().onEvent(Events.WindowEvents.OnQuitRequested.class).perform(_ -> quit());
|
||||||
new EventPublisher<>(Events.WindowEvents.OnMouseMove.class, _ -> {});
|
new EventPublisher().onEvent(Events.WindowEvents.OnMouseMove.class).perform(_ -> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void quit() {
|
private static void quit() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.toop;
|
package org.toop;
|
||||||
|
|
||||||
import org.toop.eventbus.EventPublisher;
|
import org.toop.eventbus.EventFlow;
|
||||||
import org.toop.eventbus.GlobalEventBus;
|
import org.toop.eventbus.GlobalEventBus;
|
||||||
import org.toop.eventbus.events.NetworkEvents;
|
import org.toop.eventbus.events.NetworkEvents;
|
||||||
import org.toop.frontend.networking.NetworkingGameClientHandler;
|
import org.toop.frontend.networking.NetworkingGameClientHandler;
|
||||||
@@ -9,12 +9,13 @@ import java.util.function.Supplier;
|
|||||||
|
|
||||||
public class MainTest {
|
public class MainTest {
|
||||||
MainTest() {
|
MainTest() {
|
||||||
var a = new EventPublisher<>(
|
var a = new EventFlow()
|
||||||
NetworkEvents.StartClient.class,
|
.addPostEvent(NetworkEvents.StartClient.class,
|
||||||
(Supplier<NetworkingGameClientHandler>) NetworkingGameClientHandler::new,
|
(Supplier<NetworkingGameClientHandler>) NetworkingGameClientHandler::new,
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
5001
|
5001)
|
||||||
).onEventById(NetworkEvents.StartClientSuccess.class, this::handleStartClientSuccess)
|
.onResponse(NetworkEvents.StartClientSuccess.class)
|
||||||
|
.perform(this::handleStartClientSuccess)
|
||||||
.unsubscribeAfterSuccess().asyncPostEvent();
|
.unsubscribeAfterSuccess().asyncPostEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
221
src/main/java/org/toop/eventbus/EventFlow.java
Normal file
221
src/main/java/org/toop/eventbus/EventFlow.java
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
package org.toop.eventbus;
|
||||||
|
|
||||||
|
import org.toop.eventbus.events.EventWithUuid;
|
||||||
|
import org.toop.eventbus.events.IEvent;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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}.
|
||||||
|
*
|
||||||
|
* <p>This class supports automatic UUID assignment for {@link EventWithUuid} 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.</p>
|
||||||
|
*/
|
||||||
|
public class EventFlow {
|
||||||
|
|
||||||
|
/** Lookup object used for dynamically invoking constructors via MethodHandles. */
|
||||||
|
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
||||||
|
|
||||||
|
/** Cache of constructor handles for event classes to avoid repeated reflection lookups. */
|
||||||
|
private static final Map<Class<?>, MethodHandle> CONSTRUCTOR_CACHE = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/** Automatically assigned UUID for {@link EventWithUuid} events. */
|
||||||
|
private String eventId = null;
|
||||||
|
|
||||||
|
/** The event instance created by this publisher. */
|
||||||
|
private IEvent event = null;
|
||||||
|
|
||||||
|
/** The listener returned by GlobalEventBus subscription. Used for unsubscription. */
|
||||||
|
private Object listener;
|
||||||
|
|
||||||
|
/** Flag indicating whether to automatically unsubscribe the listener after success. */
|
||||||
|
private boolean unsubscribeAfterSuccess = false;
|
||||||
|
|
||||||
|
/** Holds the results returned from the subscribed event, if any. */
|
||||||
|
private Map<String, Object> result = null;
|
||||||
|
|
||||||
|
/** Empty constructor (event must be added via {@link #addPostEvent}). */
|
||||||
|
public EventFlow() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate an event of the given class and store it in this publisher.
|
||||||
|
*/
|
||||||
|
public <T extends IEvent> EventFlow addPostEvent(Class<T> eventClass, Object... args) {
|
||||||
|
try {
|
||||||
|
boolean isUuidEvent = EventWithUuid.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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object[] finalArgs;
|
||||||
|
int expectedParamCount = ctorHandle.type().parameterCount();
|
||||||
|
|
||||||
|
if (isUuidEvent && args.length < expectedParamCount) {
|
||||||
|
this.eventId = UUID.randomUUID().toString();
|
||||||
|
finalArgs = new Object[args.length + 1];
|
||||||
|
System.arraycopy(args, 0, finalArgs, 0, args.length);
|
||||||
|
finalArgs[args.length] = this.eventId;
|
||||||
|
} else if (isUuidEvent) {
|
||||||
|
this.eventId = (String) args[args.length - 1];
|
||||||
|
finalArgs = args;
|
||||||
|
} else {
|
||||||
|
finalArgs = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.event = (IEvent) ctorHandle.invokeWithArguments(finalArgs);
|
||||||
|
return this;
|
||||||
|
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException("Failed to instantiate event", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start listening for a response event type, chainable with perform().
|
||||||
|
*/
|
||||||
|
public <TT extends IEvent> ResponseBuilder<TT> onResponse(Class<TT> eventClass) {
|
||||||
|
return new ResponseBuilder<>(this, eventClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ResponseBuilder<R extends IEvent> {
|
||||||
|
private final EventFlow parent;
|
||||||
|
private final Class<R> responseClass;
|
||||||
|
|
||||||
|
ResponseBuilder(EventFlow parent, Class<R> responseClass) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.responseClass = responseClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Finalize the subscription */
|
||||||
|
public EventFlow perform(Consumer<R> action) {
|
||||||
|
parent.listener = GlobalEventBus.subscribe(responseClass, event -> {
|
||||||
|
action.accept(responseClass.cast(event));
|
||||||
|
if (parent.unsubscribeAfterSuccess && parent.listener != null) {
|
||||||
|
GlobalEventBus.unsubscribe(parent.listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe by ID: only fires if UUID matches this publisher's eventId.
|
||||||
|
*/
|
||||||
|
public <TT extends EventWithUuid> EventFlow onResponse(Class<TT> eventClass, Consumer<TT> action) {
|
||||||
|
this.listener = GlobalEventBus.subscribe(eventClass, event -> {
|
||||||
|
if (event.eventId().equals(this.eventId)) {
|
||||||
|
action.accept(event);
|
||||||
|
if (unsubscribeAfterSuccess && listener != null) {
|
||||||
|
GlobalEventBus.unsubscribe(listener);
|
||||||
|
}
|
||||||
|
this.result = event.result();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe by ID without explicit class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <TT extends EventWithUuid> EventFlow onResponse(Consumer<TT> action) {
|
||||||
|
this.listener = GlobalEventBus.subscribe(event -> {
|
||||||
|
if (event instanceof EventWithUuid uuidEvent) {
|
||||||
|
if (uuidEvent.eventId().equals(this.eventId)) {
|
||||||
|
try {
|
||||||
|
TT typedEvent = (TT) uuidEvent;
|
||||||
|
action.accept(typedEvent);
|
||||||
|
if (unsubscribeAfterSuccess && listener != null) {
|
||||||
|
GlobalEventBus.unsubscribe(listener);
|
||||||
|
}
|
||||||
|
this.result = typedEvent.result();
|
||||||
|
} catch (ClassCastException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// choose event type
|
||||||
|
public <TT extends IEvent> EventSubscriberBuilder<TT> onEvent(Class<TT> eventClass) {
|
||||||
|
return new EventSubscriberBuilder<>(this, eventClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// One-liner shorthand
|
||||||
|
public <TT extends IEvent> EventFlow listen(Class<TT> eventClass, Consumer<TT> action) {
|
||||||
|
return this.onEvent(eventClass).perform(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Builder for chaining .onEvent(...).perform(...)
|
||||||
|
public static class EventSubscriberBuilder<TT extends IEvent> {
|
||||||
|
private final EventFlow publisher;
|
||||||
|
private final Class<TT> eventClass;
|
||||||
|
|
||||||
|
EventSubscriberBuilder(EventFlow publisher, Class<TT> eventClass) {
|
||||||
|
this.publisher = publisher;
|
||||||
|
this.eventClass = eventClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventFlow perform(Consumer<TT> action) {
|
||||||
|
publisher.listener = GlobalEventBus.subscribe(eventClass, event -> {
|
||||||
|
action.accept(eventClass.cast(event));
|
||||||
|
if (publisher.unsubscribeAfterSuccess && publisher.listener != null) {
|
||||||
|
GlobalEventBus.unsubscribe(publisher.listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return publisher;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Post synchronously */
|
||||||
|
public EventFlow postEvent() {
|
||||||
|
GlobalEventBus.post(event);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Post asynchronously */
|
||||||
|
public EventFlow asyncPostEvent() {
|
||||||
|
GlobalEventBus.postAsync(event);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventFlow unsubscribeAfterSuccess() {
|
||||||
|
this.unsubscribeAfterSuccess = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventFlow unsubscribeNow() {
|
||||||
|
if (unsubscribeAfterSuccess && listener != null) {
|
||||||
|
GlobalEventBus.unsubscribe(listener);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> getResult() {
|
||||||
|
return this.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEvent getEvent() {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEventId() {
|
||||||
|
return eventId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,316 +0,0 @@
|
|||||||
package org.toop.eventbus;
|
|
||||||
|
|
||||||
import org.toop.eventbus.events.EventWithUuid;
|
|
||||||
import org.toop.eventbus.events.IEvent;
|
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EventPublisher 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}.
|
|
||||||
*
|
|
||||||
* <p>This class supports automatic UUID assignment for {@link EventWithUuid} 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.</p>
|
|
||||||
*
|
|
||||||
* <p><strong>Usage patterns:</strong></p>
|
|
||||||
*
|
|
||||||
* <p><strong>1. Publish an event with optional subscription by UUID:</strong></p>
|
|
||||||
* <pre>{@code
|
|
||||||
* new EventPublisher<>(StartClient.class, handlerFactory, "127.0.0.1", 5001)
|
|
||||||
* .onEventById(ClientReady.class, clientReadyEvent -> logger.info(clientReadyEvent))
|
|
||||||
* .unsubscribeAfterSuccess()
|
|
||||||
* .postEvent();
|
|
||||||
* }</pre>
|
|
||||||
*
|
|
||||||
* <p><strong>2. Subscribe to a specific event type without UUID filtering:</strong></p>
|
|
||||||
* <pre>{@code
|
|
||||||
* new EventPublisher<>(MyEvent.class)
|
|
||||||
* .onEvent(MyEvent.class, e -> logger.info("Received: " + e))
|
|
||||||
* .postEvent();
|
|
||||||
* }</pre>
|
|
||||||
*
|
|
||||||
* <p><strong>3. Subscribe with runtime type inference:</strong></p>
|
|
||||||
* <pre>{@code
|
|
||||||
* new EventPublisher<>((MyEvent e) -> logger.info("Received: " + e))
|
|
||||||
* .postEvent();
|
|
||||||
* }</pre>
|
|
||||||
*
|
|
||||||
* <p><strong>Notes:</strong></p>
|
|
||||||
* <ul>
|
|
||||||
* <li>For events extending {@link EventWithUuid}, a UUID is automatically generated
|
|
||||||
* and passed to the event constructor if none is provided.</li>
|
|
||||||
* <li>Listeners registered via {@code onEventById} will only be triggered
|
|
||||||
* if the event's UUID matches this publisher's UUID.</li>
|
|
||||||
* <li>Listeners can be unsubscribed automatically after the first successful trigger
|
|
||||||
* using {@link #unsubscribeAfterSuccess()}.</li>
|
|
||||||
* <li>All subscription and posting methods are chainable for fluent API usage.</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param <T> the type of event to publish; must implement {@link IEvent}
|
|
||||||
*/
|
|
||||||
public class EventPublisher<T extends IEvent> {
|
|
||||||
|
|
||||||
|
|
||||||
/** Lookup object used for dynamically invoking constructors via MethodHandles. */
|
|
||||||
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
|
||||||
|
|
||||||
/** Cache of constructor handles for event classes to avoid repeated reflection lookups. */
|
|
||||||
private static final Map<Class<?>, MethodHandle> CONSTRUCTOR_CACHE = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/** Automatically assigned UUID for {@link EventWithUuid} events. */
|
|
||||||
private String eventId = null;
|
|
||||||
|
|
||||||
/** The event instance created by this publisher. */
|
|
||||||
private T event = null;
|
|
||||||
|
|
||||||
/** The listener returned by GlobalEventBus subscription. Used for unsubscription. */
|
|
||||||
private Object listener;
|
|
||||||
|
|
||||||
/** Flag indicating whether to automatically unsubscribe the listener after success. */
|
|
||||||
private boolean unsubscribeAfterSuccess = false;
|
|
||||||
|
|
||||||
/** Holds the results returned from the subscribed event, if any. */
|
|
||||||
private Map<String, Object> result = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new EventPublisher by instantiating the given event class.
|
|
||||||
* For {@link EventWithUuid} events, a UUID is automatically generated and passed as
|
|
||||||
* the last constructor argument if not explicitly provided.
|
|
||||||
*
|
|
||||||
* @param postEventClass the class of the event to instantiate
|
|
||||||
* @param args constructor arguments for the event (UUID may be excluded)
|
|
||||||
* @throws RuntimeException if instantiation fails
|
|
||||||
*/
|
|
||||||
public EventPublisher(Class<T> postEventClass, Object... args) {
|
|
||||||
try {
|
|
||||||
boolean isUuidEvent = EventWithUuid.class.isAssignableFrom(postEventClass);
|
|
||||||
|
|
||||||
MethodHandle ctorHandle = CONSTRUCTOR_CACHE.computeIfAbsent(postEventClass, 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();
|
|
||||||
if (isUuidEvent && args.length < expectedParamCount) {
|
|
||||||
this.eventId = UUID.randomUUID().toString();
|
|
||||||
finalArgs = new Object[args.length + 1];
|
|
||||||
System.arraycopy(args, 0, finalArgs, 0, args.length);
|
|
||||||
finalArgs[args.length] = this.eventId;
|
|
||||||
} else if (isUuidEvent) {
|
|
||||||
this.eventId = (String) args[args.length - 1];
|
|
||||||
finalArgs = args;
|
|
||||||
} else {
|
|
||||||
finalArgs = args;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
T instance = (T) ctorHandle.invokeWithArguments(finalArgs);
|
|
||||||
this.event = instance;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new RuntimeException("Failed to instantiate event", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new EventPublisher and immediately subscribes a listener for the event class.
|
|
||||||
*
|
|
||||||
* @param eventClass the class of the event to subscribe to
|
|
||||||
* @param action the action to execute when an event of the given class is received
|
|
||||||
*/
|
|
||||||
public EventPublisher(Class<T> eventClass, Consumer<T> action) {
|
|
||||||
this.onEvent(eventClass, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new EventPublisher and immediately subscribes a listener using runtime type inference.
|
|
||||||
* The event type is inferred at runtime. Wrong type casts are ignored silently.
|
|
||||||
*
|
|
||||||
* @param action the action to execute when a matching event is received
|
|
||||||
*/
|
|
||||||
public EventPublisher(Consumer<T> action) {
|
|
||||||
this.onEvent(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribes a listener for a specific {@link EventWithUuid} event type.
|
|
||||||
* The listener is only triggered if the event UUID matches this publisher's UUID.
|
|
||||||
*
|
|
||||||
* @param eventClass the class of the event to subscribe to
|
|
||||||
* @param action the action to execute on a matching event
|
|
||||||
* @param <TT> type of event; must extend EventWithUuid
|
|
||||||
* @return this EventPublisher for chainable calls
|
|
||||||
*/
|
|
||||||
public <TT extends EventWithUuid> EventPublisher<T> onEventById(
|
|
||||||
Class<TT> eventClass, Consumer<TT> action) {
|
|
||||||
|
|
||||||
this.listener = GlobalEventBus.subscribe(eventClass, event -> {
|
|
||||||
if (event.eventId().equals(this.eventId)) {
|
|
||||||
action.accept(event);
|
|
||||||
|
|
||||||
if (unsubscribeAfterSuccess && listener != null) {
|
|
||||||
GlobalEventBus.unsubscribe(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.result = event.result();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribes a listener for {@link EventWithUuid} events without specifying class explicitly.
|
|
||||||
* Only triggers for events whose UUID matches this publisher's UUID.
|
|
||||||
*
|
|
||||||
* @param action the action to execute on a matching event
|
|
||||||
* @param <TT> type of event; must extend EventWithUuid
|
|
||||||
* @return this EventPublisher for chainable calls
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <TT extends EventWithUuid> EventPublisher<T> onEventById(Consumer<TT> action) {
|
|
||||||
|
|
||||||
this.listener = GlobalEventBus.subscribe(event -> {
|
|
||||||
if (event instanceof EventWithUuid uuidEvent) {
|
|
||||||
if (uuidEvent.eventId().equals(this.eventId)) {
|
|
||||||
try {
|
|
||||||
TT typedEvent = (TT) uuidEvent;
|
|
||||||
action.accept(typedEvent);
|
|
||||||
|
|
||||||
if (unsubscribeAfterSuccess && listener != null) {
|
|
||||||
GlobalEventBus.unsubscribe(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.result = typedEvent.result();
|
|
||||||
} catch (ClassCastException ignored) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribes a listener for a specific event type without UUID filtering.
|
|
||||||
*
|
|
||||||
* @param eventClass the class of the event to subscribe to
|
|
||||||
* @param action the action to execute on the event
|
|
||||||
* @param <TT> type of event; must implement IEvent
|
|
||||||
* @return this EventPublisher for chainable calls
|
|
||||||
*/
|
|
||||||
public <TT extends IEvent> EventPublisher<T> onEvent(Class<TT> eventClass, Consumer<TT> action) {
|
|
||||||
this.listener = GlobalEventBus.subscribe(eventClass, event -> {
|
|
||||||
action.accept(eventClass.cast(event));
|
|
||||||
|
|
||||||
if (unsubscribeAfterSuccess && listener != null) {
|
|
||||||
GlobalEventBus.unsubscribe(listener);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribes a listener using runtime type inference. Wrong type casts are ignored silently.
|
|
||||||
*
|
|
||||||
* @param action the action to execute when a matching event is received
|
|
||||||
* @param <TT> type of event (inferred at runtime)
|
|
||||||
* @return this EventPublisher for chainable calls
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <TT> EventPublisher<T> onEvent(Consumer<TT> action) {
|
|
||||||
this.listener = GlobalEventBus.subscribe(event -> {
|
|
||||||
try {
|
|
||||||
TT typedEvent = (TT) event;
|
|
||||||
action.accept(typedEvent);
|
|
||||||
|
|
||||||
if (unsubscribeAfterSuccess && listener != null) {
|
|
||||||
GlobalEventBus.unsubscribe(listener);
|
|
||||||
}
|
|
||||||
} catch (ClassCastException ignored) {}
|
|
||||||
});
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Posts the event synchronously to {@link GlobalEventBus}.
|
|
||||||
*
|
|
||||||
* @return this EventPublisher for chainable calls
|
|
||||||
*/
|
|
||||||
public EventPublisher<T> postEvent() {
|
|
||||||
GlobalEventBus.post(event);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Posts the event asynchronously to {@link GlobalEventBus}.
|
|
||||||
*
|
|
||||||
* @return this EventPublisher for chainable calls
|
|
||||||
*/
|
|
||||||
public EventPublisher<T> asyncPostEvent() {
|
|
||||||
GlobalEventBus.postAsync(event);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures automatic unsubscription for listeners registered via onEventById
|
|
||||||
* after a successful trigger.
|
|
||||||
*
|
|
||||||
* @return this EventPublisher for chainable calls
|
|
||||||
*/
|
|
||||||
public EventPublisher<T> unsubscribeAfterSuccess() {
|
|
||||||
this.unsubscribeAfterSuccess = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Immediately unsubscribes the listener, if set.
|
|
||||||
*
|
|
||||||
* @return this EventPublisher for chainable calls
|
|
||||||
*/
|
|
||||||
public EventPublisher<T> unsubscribeNow() {
|
|
||||||
if (unsubscribeAfterSuccess && listener != null) {
|
|
||||||
GlobalEventBus.unsubscribe(listener);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the results provided by the triggered event, if any.
|
|
||||||
*
|
|
||||||
* @return map of results, or null if none
|
|
||||||
*/
|
|
||||||
public Map<String, Object> getResult() {
|
|
||||||
return this.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the event instance created by this publisher.
|
|
||||||
*
|
|
||||||
* @return the event instance
|
|
||||||
*/
|
|
||||||
public T getEvent() {
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the automatically assigned UUID for {@link EventWithUuid} events.
|
|
||||||
*
|
|
||||||
* @return the UUID string, or null for non-UUID events
|
|
||||||
*/
|
|
||||||
public String getEventId() {
|
|
||||||
return eventId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user