Class BlockchainEventBus
The event bus decouples blockchain internals from observer code. Any component
may publish an event; any number of BlockchainEventListener implementations
can react without the publisher knowing about them (FR-EVENT-01, FR-EVENT-02).
Delivery guarantees
- Events are dispatched to all registered listeners on a dedicated single-thread executor so that the calling thread (e.g., the miner that just sealed a block) is never blocked by slow listeners (FR-EVENT-03).
- Listener exceptions are caught and logged at
WARNINGlevel; they do not propagate back to the publisher or affect other listeners. - Listener registration uses
CopyOnWriteArrayList, which means registration/unregistration never blocks concurrent event publications. - Events submitted before shutdown are delivered before the executor terminates.
Wiring (Milestone 8 — T-066)
The event bus is wired into three core subsystems:
Blockchain.addBlock()— publishesBlockchainEvent.BlockAddedEventTransactionMempool.submit()— publishesBlockchainEvent.TransactionSubmittedEventPeerManager.connect()/disconnect()— publishesBlockchainEvent.PeerConnectedEvent/BlockchainEvent.PeerDisconnectedEvent
Lifecycle
Call shutdown() when the owning BlockchainNode stops to
drain pending events and terminate the delivery thread cleanly. The bus
supports awaitQuiescence(long, TimeUnit) for test synchronization.
Usage
BlockchainEventBus bus = new BlockchainEventBus();
bus.register(event -> {
if (event instanceof BlockchainEvent.BlockAddedEvent e) {
log.info("Block #{} added", e.getBlock().getIndex());
}
});
bus.publish(new BlockchainEvent.BlockAddedEvent(block));
bus.shutdown();
- Since:
- 1.0.0
- See Also:
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionbooleanBlocks the caller until all pending events are delivered, using a 2000L ms default timeout.booleanawaitQuiescence(long timeout, TimeUnit unit) Blocks the caller until all events published before this call have been delivered, or until the timeout elapses.booleanisRegistered(BlockchainEventListener listener) Returnstrueif the given listener is currently registered.booleanReturnstrueif the event bus has been shut down.intReturns the number of currently registered listeners.voidpublish(BlockchainEvent event) Publishes an event to all currently registered listeners asynchronously.voidregister(BlockchainEventListener listener) Registers a listener to receive future events.voidshutdown()Shuts down the event delivery executor gracefully.voidunregister(BlockchainEventListener listener) Unregisters a previously registered listener.
-
Constructor Details
-
BlockchainEventBus
public BlockchainEventBus()
-
-
Method Details
-
register
Registers a listener to receive future events.A listener may be registered multiple times; each registration results in one additional delivery per event. To avoid duplicate delivery, callers should check
isRegistered(BlockchainEventListener)first or use a single shared reference.- Parameters:
listener- the listener to register (non-null)- Throws:
NullPointerException- if listener is null
-
unregister
Unregisters a previously registered listener.If the listener was registered multiple times, only the first occurrence is removed per call. If the listener is not registered, this method is a no-op.
- Parameters:
listener- the listener to unregister (non-null)- Throws:
NullPointerException- if listener is null
-
isRegistered
Returnstrueif the given listener is currently registered.- Parameters:
listener- the listener to check (non-null)- Returns:
trueif registered at least once- Throws:
NullPointerException- if listener is null
-
listenerCount
public int listenerCount()Returns the number of currently registered listeners.- Returns:
- listener count (≥ 0)
-
publish
Publishes an event to all currently registered listeners asynchronously.This method returns immediately after submitting the delivery task to the internal executor. Listeners are notified on the event-bus delivery thread, not on the caller's thread. Delivery order among listeners for a single event matches registration order (FR-EVENT-03).
If the delivery executor has been shut down (after
shutdown()), the event is silently dropped and a warning is logged.- Parameters:
event- the event to publish (non-null)- Throws:
NullPointerException- if event is null
-
awaitQuiescence
Blocks the caller until all events published before this call have been delivered, or until the timeout elapses.This method is intended for test synchronization only. Production code should not need it — the event bus is explicitly asynchronous by design.
Implementation: submits a sentinel no-op task and waits for its completion. Because the executor is single-threaded, completing the sentinel guarantees all previously submitted tasks have also completed.
- Parameters:
timeout- maximum time to waitunit- time unit of the timeout- Returns:
trueif all pending deliveries completed within the timeout;falseif the timeout elapsed first- Throws:
InterruptedException- if the calling thread is interrupted while waiting
-
awaitQuiescence
Blocks the caller until all pending events are delivered, using a 2000L ms default timeout.- Returns:
trueif quiescent within the default timeout- Throws:
InterruptedException- if interrupted while waiting
-
shutdown
public void shutdown()Shuts down the event delivery executor gracefully.Events already submitted to the executor are delivered before shutdown completes (orderly drain). No new events are accepted after this call. This method does not block; the drain happens asynchronously on the delivery thread itself. Call
awaitQuiescence(long, java.util.concurrent.TimeUnit)first if synchronous completion is required.Typically called from
BlockchainNode.stop(). -
isShutdown
public boolean isShutdown()Returnstrueif the event bus has been shut down.- Returns:
trueaftershutdown()has been called
-