Compare commits
	
		
			4 Commits
		
	
	
		
			b758f4cef1
			...
			b915a5c490
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						b915a5c490
	
				 | 
					
					
						|||
| 
						
						
							
						
						205a183db7
	
				 | 
					
					
						|||
| 
						
						
							
						
						74447dea59
	
				 | 
					
					
						|||
| 
						
						
							
						
						6eebd3c121
	
				 | 
					
					
						
@@ -27,7 +27,21 @@ public final class EventBus {
 | 
			
		||||
	 */
 | 
			
		||||
	private static final class DispatchState {
 | 
			
		||||
 | 
			
		||||
		boolean isDispatching, isCancelled;
 | 
			
		||||
		/**
 | 
			
		||||
		 * Indicates that the last event handler invoked has called {@link EventBus#cancel}. In that
 | 
			
		||||
		 * case, the event is not dispatched further.
 | 
			
		||||
		 *
 | 
			
		||||
		 * @since 0.1.0
 | 
			
		||||
		 */
 | 
			
		||||
		boolean isCancelled;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Is incremented when {@link EventBus#dispatch(Object)} is invoked and decremented when it
 | 
			
		||||
		 * finishes. This allows keeping track of nested dispatches.
 | 
			
		||||
		 *
 | 
			
		||||
		 * @since 1.2.0
 | 
			
		||||
		 */
 | 
			
		||||
		int nestingCount;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -79,9 +93,11 @@ public final class EventBus {
 | 
			
		||||
		Objects.requireNonNull(event);
 | 
			
		||||
		logger.log(Level.INFO, "Dispatching event {0}", event);
 | 
			
		||||
 | 
			
		||||
		// Set dispatch state
 | 
			
		||||
		// Look up dispatch state
 | 
			
		||||
		var state = dispatchState.get();
 | 
			
		||||
		state.isDispatching = true;
 | 
			
		||||
 | 
			
		||||
		// Increment nesting count (becomes > 1 during nested dispatches)
 | 
			
		||||
		++state.nestingCount;
 | 
			
		||||
 | 
			
		||||
		Iterator<EventHandler> handlers = getHandlersFor(event.getClass());
 | 
			
		||||
		if (handlers.hasNext()) {
 | 
			
		||||
@@ -94,14 +110,14 @@ public final class EventBus {
 | 
			
		||||
					try {
 | 
			
		||||
						handlers.next().execute(event);
 | 
			
		||||
					} catch (InvocationTargetException e) {
 | 
			
		||||
						if (event instanceof DeadEvent || event instanceof ExceptionEvent)
 | 
			
		||||
 | 
			
		||||
							// Warn about system event not being handled
 | 
			
		||||
							logger.log(Level.WARNING, event + " not handled due to exception", e);
 | 
			
		||||
						else if (e.getCause() instanceof Error)
 | 
			
		||||
						if (e.getCause() instanceof Error)
 | 
			
		||||
 | 
			
		||||
							// Transparently pass error to the caller
 | 
			
		||||
							throw (Error) e.getCause();
 | 
			
		||||
						else if (event instanceof DeadEvent || event instanceof ExceptionEvent)
 | 
			
		||||
 | 
			
		||||
							// Warn about system event not being handled
 | 
			
		||||
							logger.log(Level.WARNING, event + " not handled due to exception", e);
 | 
			
		||||
						else
 | 
			
		||||
 | 
			
		||||
							// Dispatch exception event
 | 
			
		||||
@@ -118,8 +134,8 @@ public final class EventBus {
 | 
			
		||||
			dispatch(new DeadEvent(this, event));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Reset dispatch state
 | 
			
		||||
		state.isDispatching = false;
 | 
			
		||||
		// Decrement nesting count (becomes 0 when all dispatches on the thread are finished)
 | 
			
		||||
		--state.nestingCount;
 | 
			
		||||
 | 
			
		||||
		logger.log(Level.DEBUG, "Finished dispatching event {0}", event);
 | 
			
		||||
	}
 | 
			
		||||
@@ -155,7 +171,7 @@ public final class EventBus {
 | 
			
		||||
	 */
 | 
			
		||||
	public void cancel() {
 | 
			
		||||
		var state = dispatchState.get();
 | 
			
		||||
		if (state.isDispatching && !state.isCancelled)
 | 
			
		||||
		if (state.nestingCount > 0 && !state.isCancelled)
 | 
			
		||||
			state.isCancelled = true;
 | 
			
		||||
		else
 | 
			
		||||
			throw new EventBusException("Calling thread not an active dispatching thread!");
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,73 @@
 | 
			
		||||
package dev.kske.eventbus.core;
 | 
			
		||||
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.*;
 | 
			
		||||
 | 
			
		||||
import org.junit.jupiter.api.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests nested event dispatches.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 * @since 1.2.0
 | 
			
		||||
 */
 | 
			
		||||
class NestedTest {
 | 
			
		||||
 | 
			
		||||
	EventBus	bus;
 | 
			
		||||
	boolean		nestedHit;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Constructs an event bus and registers this test instance as an event listener.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @since 1.2.0
 | 
			
		||||
	 */
 | 
			
		||||
	@BeforeEach
 | 
			
		||||
	void registerListener() {
 | 
			
		||||
		bus = new EventBus();
 | 
			
		||||
		bus.registerListener(this);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Dispatches a simple event, which should in turn cause a string to be dispatched as a nested
 | 
			
		||||
	 * event. If the corresponding handler sets {@link #nestedHit} to {@code true}, the test is
 | 
			
		||||
	 * successful.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @since 1.2.0
 | 
			
		||||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	void testNestedDispatch() {
 | 
			
		||||
		bus.dispatch(new SimpleEvent());
 | 
			
		||||
		assertTrue(nestedHit);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Dispatches a string as a nested event and cancels the current dispatch afterwards.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @since 1.2.0
 | 
			
		||||
	 */
 | 
			
		||||
	@Event(SimpleEvent.class)
 | 
			
		||||
	void onSimpleEvent() {
 | 
			
		||||
		bus.dispatch("Nested event");
 | 
			
		||||
		bus.cancel();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Sets {@link #nestedHit} to {@code true} indicating that nested dispatches work.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @since 1.2.0
 | 
			
		||||
	 */
 | 
			
		||||
	@Event(String.class)
 | 
			
		||||
	void onString() {
 | 
			
		||||
		nestedHit = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Fails the test if an exception is caused during the dispatch.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param e the event containing the exception
 | 
			
		||||
	 * @since 1.2.0
 | 
			
		||||
	 */
 | 
			
		||||
	@Event
 | 
			
		||||
	void onException(ExceptionEvent e) {
 | 
			
		||||
		fail("Exception during dispatch", e.getCause());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user