Interface EventBus
The EventBus allows registration of type-safe event handlers that are invoked when events are posted. Handlers can execute synchronously or asynchronously, with configurable priority levels determining execution order.
Key Features
- Type Safety: Only events implementing
CommandEventare allowed - Strict Type Matching: Handlers receive only exact event type matches (no inheritance)
- Thread Safety: Fully concurrent for handler registration and event posting
- Priority-Based Execution: Handlers execute in priority order (highest first)
- Sync/Async Execution: Per-handler control over execution strategy
- Exception Isolation: Handler failures don't stop other handlers
- Event Cancellation: Support for
CancellableEvent - Handler Unregistration: Remove subscriptions by UUID
Basic Usage
EventBus eventBus = EventBus.create();
UUID handlerId = eventBus.register(
PlayerJoinEvent.class,
event -> System.out.println("Player joined: " + event.getPlayer())
);
eventBus.post(new PlayerJoinEvent(player));
eventBus.unregister(handlerId);
Advanced Usage
EventBus eventBus = EventBus.builder()
.exceptionHandler((event, exception, handlerId) ->
logger.error("Handler {} failed", handlerId, exception))
.executorService(customExecutor)
.build();
eventBus.register(
PlayerChatEvent.class,
event -> {
if (!event.isCancelled()) broadcastMessage(event.getMessage());
},
Priority.HIGH,
ExecutionStrategy.ASYNC
);
Execution Order
When an event is posted:
- All SYNC subscriptions execute in priority order (highest to lowest)
- All ASYNC subscriptions are submitted in priority order (highest to lowest)
- post() returns after all SYNC subscriptions complete (ASYNC may still be running)
Exception Handling
When a handler throws an exception:
- The configured
EventExceptionHandleris invoked with full context - Execution continues to the next subscription (isolation)
- Other subscriptions are not affected by the failure
Thread Safety
- Multiple threads can post events concurrently
- Subscriptions can be registered/unregistered while events are being posted
- Internal state uses concurrent data structures
-
Nested Class Summary
Nested ClassesModifier and TypeInterfaceDescriptionstatic final classBuilder for creating configuredEventBusinstances. -
Method Summary
Modifier and TypeMethodDescriptionstatic EventBus.Builderbuilder()Returns a newEventBus.Builderfor configuring an EventBus.static EventBusCreates a new EventBus with default configuration.intgetSubscriptionCount(@NotNull Class<? extends Event> eventType) Returns the number of active subscriptions for the given exact event type.intReturns the total number of active subscriptions across all event types.booleanChecks if this instance of event bus has no executor and no exception handler configured.<T extends Event>
voidpost(T event) Posts an event to all subscriptions registered for its exact runtime type.<T extends Event>
EventSubscription<T>register(@NotNull Class<T> eventType, @NotNull EventListenerConsumer<T> handler) Registers an event handler withPriority.NORMALandExecutionStrategy.SYNC.<T extends Event>
EventSubscription<T>register(@NotNull Class<T> eventType, @NotNull EventListenerConsumer<T> handler, @NotNull Priority priority) Registers an event handler with the specified priority andExecutionStrategy.SYNC.<T extends Event>
EventSubscription<T>register(@NotNull Class<T> eventType, @NotNull EventListenerConsumer<T> handler, @NotNull Priority priority, @NotNull ExecutionStrategy strategy) Registers an event handler with full configuration.voidshutdown()Shuts down the event bus, releasing resources.voidShuts down the event bus and blocks until all async handlers finish executing.booleanunregister(@NotNull UUID subscriptionId) Unregisters a subscription by its unique identifier.
-
Method Details
-
createDummy
Creates a new EventBus with default configuration.Default configuration:
- No exception handler (exceptions are silently ignored)
- Default daemon cached thread pool for async handlers
- Returns:
- a new EventBus instance
-
builder
Returns a newEventBus.Builderfor configuring an EventBus.- Returns:
- a new Builder instance
-
register
<T extends Event> EventSubscription<T> register(@NotNull @NotNull Class<T> eventType, @NotNull @NotNull EventListenerConsumer<T> handler) Registers an event handler withPriority.NORMALandExecutionStrategy.SYNC.- Type Parameters:
T- the type of event- Parameters:
eventType- the exact class of events this handler should receivehandler- the consumer that will process events- Returns:
- the unique identifier of this subscription, usable with
unregister(UUID) - Throws:
IllegalArgumentException- if any parameter is null
-
register
<T extends Event> EventSubscription<T> register(@NotNull @NotNull Class<T> eventType, @NotNull @NotNull EventListenerConsumer<T> handler, @NotNull @NotNull Priority priority) Registers an event handler with the specified priority andExecutionStrategy.SYNC.- Type Parameters:
T- the type of event- Parameters:
eventType- the exact class of events this handler should receivehandler- the consumer that will process eventspriority- the execution priority for this handler- Returns:
- the unique identifier of this subscription, usable with
unregister(UUID) - Throws:
IllegalArgumentException- if any parameter is null
-
register
<T extends Event> EventSubscription<T> register(@NotNull @NotNull Class<T> eventType, @NotNull @NotNull EventListenerConsumer<T> handler, @NotNull @NotNull Priority priority, @NotNull @NotNull ExecutionStrategy strategy) Registers an event handler with full configuration.Handlers are invoked only for events whose runtime type exactly matches
eventType. Inheritance is not considered — a handler forCommandEvent.classwill NOT receivePlayerJoinEventinstances.Handlers with equal priority execute in registration order (FIFO).
- Type Parameters:
T- the type of event- Parameters:
eventType- the exact class of events this handler should receivehandler- the consumer that will process eventspriority- the execution priority for this handlerstrategy- whether to execute synchronously or asynchronously- Returns:
- the unique identifier of this subscription, usable with
unregister(UUID) - Throws:
IllegalArgumentException- if any parameter is null
-
unregister
Unregisters a subscription by its unique identifier.If the handler is currently executing, this does not interrupt it. The subscription will simply not receive any future events.
- Parameters:
subscriptionId- the ID returned from a priorregister(java.lang.Class<T>, studio.mevera.imperat.events.EventListenerConsumer<T>)call- Returns:
- true if the subscription was found and removed, false if not found
-
post
Posts an event to all subscriptions registered for its exact runtime type.SYNC subscriptions execute in the calling thread in priority order before this method returns. ASYNC subscriptions are submitted to the internal executor and may still be running after this method returns.
- Type Parameters:
T- the type of event- Parameters:
event- the event to post- Throws:
IllegalArgumentException- if event is null
-
getSubscriptionCount
Returns the number of active subscriptions for the given exact event type.- Parameters:
eventType- the event type to query- Returns:
- the subscription count, or 0 if none are registered
-
getTotalSubscriptionCount
int getTotalSubscriptionCount()Returns the total number of active subscriptions across all event types.- Returns:
- the total subscription count
-
shutdown
void shutdown()Shuts down the event bus, releasing resources.If the EventBus owns its
ExecutorService(default), it will be shut down. If a custom one was supplied via theEventBus.Builder, it will NOT be shut down — the caller is responsible for its lifecycle.This method does not block. Use
shutdownAndWait()to wait for all currently running async handlers to finish before returning. -
shutdownAndWait
Shuts down the event bus and blocks until all async handlers finish executing.- Throws:
InterruptedException- if the calling thread is interrupted while waiting
-
isDummyBus
boolean isDummyBus()Checks if this instance of event bus has no executor and no exception handler configured.- Returns:
- true if this is a dummy bus, false otherwise
-