Interface EventBus


public interface EventBus
A high-performance, thread-safe event bus system with priority-based handler execution.

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 CommandEvent are 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:

  1. All SYNC subscriptions execute in priority order (highest to lowest)
  2. All ASYNC subscriptions are submitted in priority order (highest to lowest)
  3. post() returns after all SYNC subscriptions complete (ASYNC may still be running)

Exception Handling

When a handler throws an exception:

  1. The configured EventExceptionHandler is invoked with full context
  2. Execution continues to the next subscription (isolation)
  3. 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
See Also:
  • Method Details

    • createDummy

      static EventBus 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

      static EventBus.Builder builder()
      Returns a new EventBus.Builder for 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 with Priority.NORMAL and ExecutionStrategy.SYNC.
      Type Parameters:
      T - the type of event
      Parameters:
      eventType - the exact class of events this handler should receive
      handler - 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 and ExecutionStrategy.SYNC.
      Type Parameters:
      T - the type of event
      Parameters:
      eventType - the exact class of events this handler should receive
      handler - the consumer that will process events
      priority - 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 for CommandEvent.class will NOT receive PlayerJoinEvent instances.

      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 receive
      handler - the consumer that will process events
      priority - the execution priority for this handler
      strategy - 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

      boolean unregister(@NotNull @NotNull UUID subscriptionId)
      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 prior register(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

      <T extends Event> void post(@NotNull T event)
      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

      int getSubscriptionCount(@NotNull @NotNull Class<? extends Event> eventType)
      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 the EventBus.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

      void shutdownAndWait() throws InterruptedException
      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