Compare commits
	
		
			13 Commits
		
	
	
		
			0.0.2
			...
			ec73be9046
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ec73be9046 | |||
| 659bd7888f | |||
| 8aefb43823 | |||
| 9d1707de5b | |||
| 1d2102d729 | |||
| dbb816c6cb | |||
| 603a838640 | |||
| b6b73d335a | |||
| 8cf51441ad | |||
| 001c0eea7e | |||
| ba06b49368 | |||
| 7a3debe444 | |||
| 5f88ad6095 | 
							
								
								
									
										70
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								README.md
									
									
									
									
									
								
							| @@ -12,6 +12,7 @@ In addition, a singleton instance of the event bus is provided by the `EventBus# | ||||
|  | ||||
| To listen to events, register event handling methods using the `Event` annotation. | ||||
| For this to work, the method must have a return type of `void` and declare a single parameter of the desired event type. | ||||
| Alternatively, a parameter-less event handler can be declared as shown [below](#parameter-less-event-handlers). | ||||
| Additionally, the class containing the method must implement the `EventListener` interface. | ||||
|  | ||||
| ## A Simple Example | ||||
| @@ -47,7 +48,72 @@ public class SimpleEventListener implements EventListener { | ||||
| } | ||||
| ``` | ||||
|  | ||||
| In this case, an event bus is created and used locally. In a more sophisticated example the class would acquire an external event bus that is used by multiple classes. | ||||
| In this case, an event bus is created and used locally. | ||||
| In a more sophisticated example the class would acquire an external event bus that is used by multiple classes. | ||||
|  | ||||
| ## Event handlers for subtypes | ||||
|  | ||||
| On certain occasions its practical for an event handler to accept both events of the specified type, as well as subclasses of that event. | ||||
| To include subtypes for an event handler, use the `includeSubtypes` parameter as follows: | ||||
|  | ||||
| ```java | ||||
| @Event(includeSubtypes = true) | ||||
| ``` | ||||
|  | ||||
| ## Event handler execution order | ||||
|  | ||||
| Sometimes when using multiple handlers for one event, it might be useful to know in which order they will be executed. | ||||
| Event Bus provides a mechanism to ensure the correct propagation of events: the `priority`. | ||||
|  | ||||
| Priority can be set on the `@Event` annotation like that: | ||||
| ```java | ||||
| @Event(priority=100) | ||||
| ``` | ||||
|  | ||||
| The default priority for events is `100`. | ||||
|  | ||||
| **Important:** | ||||
| Events are dispatched top-down, meaning the event handler with the highest priority will be executed first. | ||||
|  | ||||
| If no priority is set or multiple handlers have the same priority, the order of execution is undefined. | ||||
|  | ||||
| ## Parameter-less event handlers | ||||
|  | ||||
| In some cases an event handler is not interested in the dispatched event instance. | ||||
| To avoid declaring a useless parameter just to specify the event type of the handler, there is an alternative: | ||||
|  | ||||
| ```java | ||||
| @Event(eventType = SimpleEvent.class) | ||||
| private void onSimpleEvent() { | ||||
| 	System.out.println("SimpleEvent received!"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Make sure that you **do not** declare both a parameter and the `eventType` value of the annotation, as this would be ambiguous. | ||||
|  | ||||
| ## Event consumption | ||||
|  | ||||
| There are cases when it would be useful to stop event propagation after a certain condition has been fulfilled. | ||||
| Event Bus provides a mechanism to consume events: | ||||
|  | ||||
| ```java | ||||
| @Event(eventType = SimpleEvent.class, priority=1000) | ||||
| private void onSimpleEvent() { | ||||
| 	EventBus.getInstance().cancel(); | ||||
| } | ||||
|  | ||||
| @Event(eventType = SimpleEvent.class, priority=900) | ||||
| private void onSimpleEvent2() { | ||||
| 	System.out.println("Will not be printed!"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| In this example, the second method will not be executed as the event will no longer be forwarded. | ||||
| Any event handler with a lower priority than the one canceling it will not get executed. | ||||
|  | ||||
| **Important:** | ||||
| Please avoid cancelling events when (multiple) event handlers have the same priority as the one cancelling it: | ||||
| It is undefined whether those will be executed or not. | ||||
|  | ||||
| ## Installation | ||||
|  | ||||
| @@ -66,7 +132,7 @@ To include it inside your project, just add the Maven repository and the depende | ||||
|     <dependency> | ||||
|         <groupId>dev.kske</groupId> | ||||
|         <artifactId>event-bus</artifactId> | ||||
|         <version>0.0.2</version> | ||||
|         <version>0.1.0</version> | ||||
|     </dependency> | ||||
| </dependencies> | ||||
| ``` | ||||
|   | ||||
							
								
								
									
										17
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -5,7 +5,7 @@ | ||||
|  | ||||
| 	<groupId>dev.kske</groupId> | ||||
| 	<artifactId>event-bus</artifactId> | ||||
| 	<version>0.0.2</version> | ||||
| 	<version>0.1.0</version> | ||||
|  | ||||
| 	<name>Event Bus</name> | ||||
| 	<description>An event handling framework for Java utilizing annotations.</description> | ||||
| @@ -45,12 +45,25 @@ | ||||
| 	</properties> | ||||
|  | ||||
| 	<build> | ||||
|  | ||||
| 		<!-- Disable resource folders --> | ||||
| 		<resources /> | ||||
| 		<testResources /> | ||||
|  | ||||
| 		<plugins> | ||||
|  | ||||
| 			<!-- Support Java 9 modules --> | ||||
| 			<plugin> | ||||
| 				<groupId>org.apache.maven.plugins</groupId> | ||||
| 				<artifactId>maven-compiler-plugin</artifactId> | ||||
| 				<version>3.8.1</version> | ||||
| 			</plugin> | ||||
|  | ||||
| 			<!-- Attach sources and Javadoc to JAR --> | ||||
| 			<plugin> | ||||
| 				<groupId>org.apache.maven.plugins</groupId> | ||||
| 				<artifactId>maven-source-plugin</artifactId> | ||||
| 				<version>3.2.1</version> | ||||
| 				<executions> | ||||
| 					<execution> | ||||
| 						<id>attach-sources</id> | ||||
| @@ -63,6 +76,7 @@ | ||||
| 			<plugin> | ||||
| 				<groupId>org.apache.maven.plugins</groupId> | ||||
| 				<artifactId>maven-javadoc-plugin</artifactId> | ||||
| 				<version>3.2.0</version> | ||||
| 				<executions> | ||||
| 					<execution> | ||||
| 						<id>attach-javadocs</id> | ||||
| @@ -72,6 +86,7 @@ | ||||
| 					</execution> | ||||
| 				</executions> | ||||
| 			</plugin> | ||||
|  | ||||
| 		</plugins> | ||||
| 	</build> | ||||
|  | ||||
|   | ||||
| @@ -10,7 +10,12 @@ import java.lang.annotation.*; | ||||
|  * comply with the following specifications: | ||||
|  * <ul> | ||||
|  * <li>Declared inside a class that implements {@link EventListener}</li> | ||||
|  * <li>One parameter of a type that implements {@link IEvent}</li> | ||||
|  * <li>Specifying an event type by either | ||||
|  * <ul> | ||||
|  * <li>Declaring one parameter of a type that implements {@link IEvent}</li> | ||||
|  * <li>Defining the class of the event using the {@link Event#eventType()} value</li> | ||||
|  * </ul> | ||||
|  * </li> | ||||
|  * <li>Return type of {@code void}</li> | ||||
|  * </ul> | ||||
|  * | ||||
| @@ -28,7 +33,35 @@ public @interface Event { | ||||
| 	 * <p> | ||||
| 	 * The execution order of handlers with the same priority is undefined. | ||||
| 	 * | ||||
| 	 * @return the priority of the event handler | ||||
| 	 * @since 0.0.1 | ||||
| 	 */ | ||||
| 	int priority() default 100; | ||||
|  | ||||
| 	/** | ||||
| 	 * Defines whether instances of subtypes of the event type are dispatched to the event handler. | ||||
| 	 * | ||||
| 	 * @return whether the event handler includes subtypes | ||||
| 	 * @since 0.0.4 | ||||
| 	 */ | ||||
| 	boolean includeSubtypes() default false; | ||||
|  | ||||
| 	/** | ||||
| 	 * Defines the event type the handler listens to. If this value is set, the handler is not | ||||
| 	 * allowed to declare parameters. | ||||
| 	 * <p> | ||||
| 	 * This is useful when the event handler does not utilize the event instance. | ||||
| 	 * | ||||
| 	 * @return the event type accepted by the handler | ||||
| 	 * @since 0.0.3 | ||||
| 	 */ | ||||
| 	Class<? extends IEvent> eventType() default USE_PARAMETER.class; | ||||
|  | ||||
| 	/** | ||||
| 	 * Signifies that the event type the handler listens to is determined by the type of its only | ||||
| 	 * parameter. | ||||
| 	 * | ||||
| 	 * @since 0.0.3 | ||||
| 	 */ | ||||
| 	static final class USE_PARAMETER implements IEvent {} | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| package dev.kske.eventbus; | ||||
|  | ||||
| import java.lang.System.Logger; | ||||
| import java.lang.System.Logger.Level; | ||||
| import java.util.*; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
|  | ||||
| @@ -17,7 +19,19 @@ import java.util.concurrent.ConcurrentHashMap; | ||||
|  */ | ||||
| public final class EventBus { | ||||
|  | ||||
| 	private static EventBus singletonInstance; | ||||
| 	/** | ||||
| 	 * Holds the state of the dispatching process on one thread. | ||||
| 	 * | ||||
| 	 * @since 0.1.0 | ||||
| 	 */ | ||||
| 	private static final class DispatchState { | ||||
|  | ||||
| 		boolean isDispatching, isCancelled; | ||||
| 	} | ||||
|  | ||||
| 	private static volatile EventBus singletonInstance; | ||||
|  | ||||
| 	private static final Logger logger = System.getLogger(EventBus.class.getName()); | ||||
|  | ||||
| 	/** | ||||
| 	 * Produces a singleton instance of the event bus. It is lazily initialized on the first call. | ||||
| @@ -26,14 +40,22 @@ public final class EventBus { | ||||
| 	 * @since 0.0.2 | ||||
| 	 */ | ||||
| 	public static EventBus getInstance() { | ||||
| 		if (singletonInstance == null) | ||||
| 			singletonInstance = new EventBus(); | ||||
| 		return singletonInstance; | ||||
| 		EventBus instance = singletonInstance; | ||||
| 		if (instance == null) | ||||
| 			synchronized (EventBus.class) { | ||||
| 				if ((instance = singletonInstance) == null) { | ||||
| 					logger.log(Level.DEBUG, "Initializing singleton event bus instance"); | ||||
| 					instance = singletonInstance = new EventBus(); | ||||
| 				} | ||||
| 			} | ||||
| 		return instance; | ||||
| 	} | ||||
|  | ||||
| 	private final Map<Class<? extends IEvent>, Collection<EventHandler>> bindings | ||||
| 	private final Map<Class<? extends IEvent>, TreeSet<EventHandler>> bindings | ||||
| 		= new ConcurrentHashMap<>(); | ||||
| 	private final Set<EventListener> registeredListeners = ConcurrentHashMap.newKeySet(); | ||||
| 	private final ThreadLocal<DispatchState> dispatchState | ||||
| 		= ThreadLocal.withInitial(DispatchState::new); | ||||
|  | ||||
| 	/** | ||||
| 	 * Dispatches an event to all event handlers registered for it in descending order of their | ||||
| @@ -43,7 +65,26 @@ public final class EventBus { | ||||
| 	 * @since 0.0.1 | ||||
| 	 */ | ||||
| 	public void dispatch(IEvent event) { | ||||
| 		getHandlersFor(event.getClass()).forEach(handler -> handler.execute(event)); | ||||
| 		Objects.requireNonNull(event); | ||||
| 		logger.log(Level.INFO, "Dispatching event {0}", event); | ||||
|  | ||||
| 		// Set dispatch state | ||||
| 		var state = dispatchState.get(); | ||||
| 		state.isDispatching = true; | ||||
|  | ||||
| 		for (var handler : getHandlersFor(event.getClass())) | ||||
| 			if (state.isCancelled) { | ||||
| 				logger.log(Level.INFO, "Cancelled dispatching event {0}", event); | ||||
| 				state.isCancelled = false; | ||||
| 				break; | ||||
| 			} else { | ||||
| 				handler.execute(event); | ||||
| 			} | ||||
|  | ||||
| 		// Reset dispatch state | ||||
| 		state.isDispatching = false; | ||||
|  | ||||
| 		logger.log(Level.DEBUG, "Finished dispatching event {0}", event); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -54,8 +95,34 @@ public final class EventBus { | ||||
| 	 * @since 0.0.1 | ||||
| 	 */ | ||||
| 	private List<EventHandler> getHandlersFor(Class<? extends IEvent> eventClass) { | ||||
| 		return bindings.containsKey(eventClass) ? new ArrayList<>(bindings.get(eventClass)) | ||||
| 			: new ArrayList<>(); | ||||
|  | ||||
| 		// Get handlers defined for the event class | ||||
| 		Set<EventHandler> handlers | ||||
| 			= bindings.containsKey(eventClass) ? bindings.get(eventClass) | ||||
| 				: new TreeSet<>(); | ||||
|  | ||||
| 		// Get subtype handlers | ||||
| 		for (var binding : bindings.entrySet()) | ||||
| 			if (binding.getKey().isAssignableFrom(eventClass)) | ||||
| 				for (var handler : binding.getValue()) | ||||
| 					if (handler.includeSubtypes()) | ||||
| 						handlers.add(handler); | ||||
|  | ||||
| 		return new ArrayList<>(handlers); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Cancels an event that is currently dispatched from inside an event handler. | ||||
| 	 * | ||||
| 	 * @throws EventBusException if the calling thread is not an active dispatching thread | ||||
| 	 * @since 0.1.0 | ||||
| 	 */ | ||||
| 	public void cancel() { | ||||
| 		var state = dispatchState.get(); | ||||
| 		if (state.isDispatching && !state.isCancelled) | ||||
| 			state.isCancelled = true; | ||||
| 		else | ||||
| 			throw new EventBusException("Calling thread not an active dispatching thread!"); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -63,13 +130,16 @@ public final class EventBus { | ||||
| 	 * | ||||
| 	 * @param listener the listener to register | ||||
| 	 * @throws EventBusException if the listener is already registered or a declared event handler | ||||
| 	 *                           does not comply to the specification | ||||
| 	 *                           does not comply with the specification | ||||
| 	 * @since 0.0.1 | ||||
| 	 * @see Event | ||||
| 	 */ | ||||
| 	public void registerListener(EventListener listener) throws EventBusException { | ||||
| 		Objects.requireNonNull(listener); | ||||
| 		if (registeredListeners.contains(listener)) | ||||
| 			throw new EventBusException(listener + " already registered!"); | ||||
| 		logger.log(Level.INFO, "Registering event listener {0}", listener.getClass().getName()); | ||||
| 		boolean handlerBound = false; | ||||
|  | ||||
| 		registeredListeners.add(listener); | ||||
| 		for (var method : listener.getClass().getDeclaredMethods()) { | ||||
| @@ -79,24 +149,22 @@ public final class EventBus { | ||||
| 			if (annotation == null) | ||||
| 				continue; | ||||
|  | ||||
| 			// Check for correct method signature and return type | ||||
| 			if (method.getParameterCount() != 1) | ||||
| 				throw new EventBusException(method + " does not have an argument count of 1!"); | ||||
|  | ||||
| 			if (!method.getReturnType().equals(void.class)) | ||||
| 				throw new EventBusException(method + " does not have a return type of void!"); | ||||
|  | ||||
| 			var param = method.getParameterTypes()[0]; | ||||
| 			if (!IEvent.class.isAssignableFrom(param)) | ||||
| 				throw new EventBusException(param + " is not of type IEvent!"); | ||||
|  | ||||
| 			@SuppressWarnings("unchecked") | ||||
| 			var realParam = (Class<? extends IEvent>) param; | ||||
| 			if (!bindings.containsKey(realParam)) | ||||
| 				bindings.put(realParam, new TreeSet<>()); | ||||
|  | ||||
| 			bindings.get(realParam).add(new EventHandler(listener, method, annotation)); | ||||
| 			// Initialize and bind the handler | ||||
| 			var handler = new EventHandler(listener, method, annotation); | ||||
| 			if (!bindings.containsKey(handler.getEventType())) | ||||
| 				bindings.put(handler.getEventType(), new TreeSet<>()); | ||||
| 			logger.log(Level.DEBUG, "Binding event handler {0}", handler); | ||||
| 			bindings.get(handler.getEventType()) | ||||
| 				.add(handler); | ||||
| 			handlerBound = true; | ||||
| 		} | ||||
|  | ||||
| 		if(!handlerBound) | ||||
| 			logger.log( | ||||
| 				Level.WARNING, | ||||
| 				"No event handlers bound for event listener {0}", | ||||
| 				listener.getClass().getName() | ||||
| 			); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -106,11 +174,18 @@ public final class EventBus { | ||||
| 	 * @since 0.0.1 | ||||
| 	 */ | ||||
| 	public void removeListener(EventListener listener) { | ||||
| 		Objects.requireNonNull(listener); | ||||
| 		logger.log(Level.INFO, "Removing event listener {0}", listener.getClass().getName()); | ||||
|  | ||||
| 		for (var binding : bindings.values()) { | ||||
| 			var it = binding.iterator(); | ||||
| 			while (it.hasNext()) | ||||
| 				if (it.next().getListener() == listener) | ||||
| 			while (it.hasNext()) { | ||||
| 				var handler = it.next(); | ||||
| 				if (handler.getListener() == listener) { | ||||
| 					logger.log(Level.DEBUG, "Unbinding event handler {0}", handler); | ||||
| 					it.remove(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		registeredListeners.remove(listener); | ||||
| 	} | ||||
| @@ -121,6 +196,7 @@ public final class EventBus { | ||||
| 	 * @since 0.0.1 | ||||
| 	 */ | ||||
| 	public void clearListeners() { | ||||
| 		logger.log(Level.INFO, "Clearing event listeners"); | ||||
| 		bindings.clear(); | ||||
| 		registeredListeners.clear(); | ||||
| 	} | ||||
|   | ||||
| @@ -1,8 +1,9 @@ | ||||
| package dev.kske.eventbus; | ||||
|  | ||||
| /** | ||||
|  * This runtime exception is thrown when an event bus error occurs. This can either occur while | ||||
|  * registering event listeners with invalid handlers, or when an event handler throws an exception. | ||||
|  * This runtime exception is thrown when an event bus error occurs. This can | ||||
|  * either occur while registering event listeners with invalid handlers, or when | ||||
|  * an event handler throws an exception. | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since 0.0.1 | ||||
| @@ -11,10 +12,21 @@ public class EventBusException extends RuntimeException { | ||||
|  | ||||
| 	private static final long serialVersionUID = 1L; | ||||
|  | ||||
| 	/** | ||||
| 	 * Creates a new event bus exception. | ||||
| 	 * | ||||
| 	 * @param message the message to display | ||||
| 	 * @param cause   the cause of this exception | ||||
| 	 */ | ||||
| 	public EventBusException(String message, Throwable cause) { | ||||
| 		super(message, cause); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Creates a new event bus exception. | ||||
| 	 * | ||||
| 	 * @param message the message to display | ||||
| 	 */ | ||||
| 	public EventBusException(String message) { | ||||
| 		super(message); | ||||
| 	} | ||||
|   | ||||
| @@ -2,6 +2,8 @@ package dev.kske.eventbus; | ||||
|  | ||||
| import java.lang.reflect.*; | ||||
|  | ||||
| import dev.kske.eventbus.Event.USE_PARAMETER; | ||||
|  | ||||
| /** | ||||
|  * Internal representation of an event handling method. | ||||
|  * | ||||
| @@ -14,6 +16,7 @@ final class EventHandler implements Comparable<EventHandler> { | ||||
| 	private final EventListener listener; | ||||
| 	private final Method method; | ||||
| 	private final Event annotation; | ||||
| 	private final Class<? extends IEvent> eventType; | ||||
|  | ||||
| 	/** | ||||
| 	 * Constructs an event handler. | ||||
| @@ -21,12 +24,40 @@ final class EventHandler implements Comparable<EventHandler> { | ||||
| 	 * @param listener   the listener containing the handler | ||||
| 	 * @param method     the handler method | ||||
| 	 * @param annotation the event annotation | ||||
| 	 * @throws EventBusException if the method or the annotation do not comply with the | ||||
| 	 *                           specification | ||||
| 	 * @since 0.0.1 | ||||
| 	 */ | ||||
| 	EventHandler(EventListener listener, Method method, Event annotation) { | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	EventHandler(EventListener listener, Method method, Event annotation) throws EventBusException { | ||||
| 		this.listener = listener; | ||||
| 		this.method = method; | ||||
| 		this.annotation = annotation; | ||||
|  | ||||
| 		// Check for correct method signature and return type | ||||
| 		if (method.getParameterCount() == 0 && annotation.eventType().equals(USE_PARAMETER.class)) | ||||
| 			throw new EventBusException(method + " does not define an event type!"); | ||||
|  | ||||
| 		if (method.getParameterCount() == 1 && !annotation.eventType().equals(USE_PARAMETER.class)) | ||||
| 			throw new EventBusException(method + " defines an ambiguous event type!"); | ||||
|  | ||||
| 		if (method.getParameterCount() > 1) | ||||
| 			throw new EventBusException(method + " defines more than one parameter!"); | ||||
|  | ||||
| 		if (!method.getReturnType().equals(void.class)) | ||||
| 			throw new EventBusException(method + " does not have a return type of void!"); | ||||
|  | ||||
| 		// Determine the event type | ||||
| 		Class<? extends IEvent> eventType = annotation.eventType(); | ||||
| 		if (eventType.equals(USE_PARAMETER.class)) { | ||||
| 			var param = method.getParameterTypes()[0]; | ||||
| 			if (!IEvent.class.isAssignableFrom(param)) | ||||
| 				throw new EventBusException(param + " is not of type IEvent!"); | ||||
| 			eventType = (Class<? extends IEvent>) param; | ||||
| 		} | ||||
| 		this.eventType = eventType; | ||||
|  | ||||
| 		// Allow access if the method is non-public | ||||
| 		method.setAccessible(true); | ||||
| 	} | ||||
|  | ||||
| @@ -46,6 +77,11 @@ final class EventHandler implements Comparable<EventHandler> { | ||||
| 		return priority == 0 ? hashCode() - other.hashCode() : priority; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public String toString() { | ||||
| 		return String.format("EventHandler[method=%s, annotation=%s]", method, annotation); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Executes the event handler. | ||||
| 	 * | ||||
| @@ -55,7 +91,10 @@ final class EventHandler implements Comparable<EventHandler> { | ||||
| 	 */ | ||||
| 	void execute(IEvent event) throws EventBusException { | ||||
| 		try { | ||||
| 			method.invoke(listener, event); | ||||
| 			if (annotation.eventType().equals(USE_PARAMETER.class)) | ||||
| 				method.invoke(listener, event); | ||||
| 			else | ||||
| 				method.invoke(listener); | ||||
| 		} catch ( | ||||
| 			IllegalAccessException | ||||
| 			| IllegalArgumentException | ||||
| @@ -82,4 +121,16 @@ final class EventHandler implements Comparable<EventHandler> { | ||||
| 	 * @since 0.0.1 | ||||
| 	 */ | ||||
| 	int getPriority() { return annotation.priority(); } | ||||
|  | ||||
| 	/** | ||||
| 	 * @return whether this handler includes subtypes | ||||
| 	 * @since 0.0.4 | ||||
| 	 */ | ||||
| 	boolean includeSubtypes() { return annotation.includeSubtypes(); } | ||||
|  | ||||
| 	/** | ||||
| 	 * @return the event type this handler listens to | ||||
| 	 * @since 0.0.3 | ||||
| 	 */ | ||||
| 	Class<? extends IEvent> getEventType() { return eventType; } | ||||
| } | ||||
|   | ||||
							
								
								
									
										12
									
								
								src/main/java/module-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/main/java/module-info.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| /** | ||||
|  * Contains the public API and implementation of the event bus library. | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since 0.0.3 | ||||
|  * @see dev.kske.eventbus.Event | ||||
|  * @see dev.kske.eventbus.EventBus | ||||
|  */ | ||||
| module dev.kske.eventbus { | ||||
|  | ||||
| 	exports dev.kske.eventbus; | ||||
| } | ||||
							
								
								
									
										52
									
								
								src/test/java/dev/kske/eventbus/CancelTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/test/java/dev/kske/eventbus/CancelTest.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| package dev.kske.eventbus; | ||||
|  | ||||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
|  | ||||
| import org.junit.jupiter.api.*; | ||||
|  | ||||
| /** | ||||
|  * Tests the event cancellation mechanism of the event bus. | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @author Leon Hofmeister | ||||
|  * @since 0.1.0 | ||||
|  */ | ||||
| class CancelTest implements EventListener { | ||||
|  | ||||
| 	EventBus	bus; | ||||
| 	int			hits; | ||||
|  | ||||
| 	/** | ||||
| 	 * Constructs an event bus and registers this test instance as an event listener. | ||||
| 	 * | ||||
| 	 * @since 0.1.0 | ||||
| 	 */ | ||||
| 	@BeforeEach | ||||
| 	void registerListener() { | ||||
| 		bus = new EventBus(); | ||||
| 		bus.registerListener(this); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Tests {@link EventBus#cancel()} with two event handlers, of which the first cancels the | ||||
| 	 * event. | ||||
| 	 * | ||||
| 	 * @since 0.1.0 | ||||
| 	 */ | ||||
| 	@Test | ||||
| 	void testCancellation() { | ||||
| 		bus.dispatch(new SimpleEvent()); | ||||
| 		assertEquals(1, hits); | ||||
| 	} | ||||
|  | ||||
| 	@Event(eventType = SimpleEvent.class, priority = 100) | ||||
| 	void onSimpleFirst() { | ||||
| 		++hits; | ||||
| 		bus.cancel(); | ||||
| 	} | ||||
|  | ||||
| 	@Event(eventType = SimpleEvent.class, priority = 50) | ||||
| 	void onSimpleSecond() { | ||||
| 		++hits; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										58
									
								
								src/test/java/dev/kske/eventbus/DispatchTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/test/java/dev/kske/eventbus/DispatchTest.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| package dev.kske.eventbus; | ||||
|  | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
|  | ||||
| import org.junit.jupiter.api.*; | ||||
|  | ||||
| /** | ||||
|  * Tests the dispatching mechanism of the event bus. | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since 0.0.1 | ||||
|  */ | ||||
| class DispatchTest implements EventListener { | ||||
|  | ||||
| 	EventBus	bus; | ||||
| 	static int	hits; | ||||
|  | ||||
| 	/** | ||||
| 	 * Constructs an event bus and registers this test instance as an event listener. | ||||
| 	 * | ||||
| 	 * @since 0.0.1 | ||||
| 	 */ | ||||
| 	@BeforeEach | ||||
| 	void registerListener() { | ||||
| 		bus = new EventBus(); | ||||
| 		bus.registerListener(this); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Tests {@link EventBus#dispatch(IEvent)} with multiple handler priorities, a subtype handler | ||||
| 	 * and a static handler. | ||||
| 	 * | ||||
| 	 * @since 0.0.1 | ||||
| 	 */ | ||||
| 	@Test | ||||
| 	void testDispatch() { | ||||
| 		bus.dispatch(new SimpleEventSub()); | ||||
| 		bus.dispatch(new SimpleEvent()); | ||||
| 	} | ||||
|  | ||||
| 	@Event(eventType = SimpleEvent.class, includeSubtypes = true, priority = 200) | ||||
| 	void onSimpleEventFirst() { | ||||
| 		++hits; | ||||
| 		assertTrue(hits == 1 || hits == 2); | ||||
| 	} | ||||
|  | ||||
| 	@Event(eventType = SimpleEvent.class, priority = 150) | ||||
| 	static void onSimpleEventSecond() { | ||||
| 		++hits; | ||||
| 		assertEquals(3, hits); | ||||
| 	} | ||||
|  | ||||
| 	@Event(priority = 100) | ||||
| 	void onSimpleEventThird(SimpleEvent event) { | ||||
| 		++hits; | ||||
| 		assertEquals(4, hits); | ||||
| 	} | ||||
| } | ||||
| @@ -1,38 +0,0 @@ | ||||
| package dev.kske.eventbus; | ||||
|  | ||||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
|  | ||||
| import org.junit.jupiter.api.*; | ||||
|  | ||||
| /** | ||||
|  * Tests the of the event bus library. | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since 0.0.1 | ||||
|  */ | ||||
| class EventBusTest implements EventListener { | ||||
|  | ||||
| 	int hits; | ||||
|  | ||||
| 	@BeforeEach | ||||
| 	public void registerListener() { | ||||
| 		EventBus.getInstance().registerListener(this); | ||||
| 	} | ||||
|  | ||||
| 	@Test | ||||
| 	void testDispatch() { | ||||
| 		EventBus.getInstance().dispatch(new SimpleEvent()); | ||||
| 	} | ||||
|  | ||||
| 	@Event(priority = 50) | ||||
| 	private void onSimpleEventSecond(SimpleEvent event) { | ||||
| 		++hits; | ||||
| 		assertEquals(2, hits); | ||||
| 	} | ||||
|  | ||||
| 	@Event(priority = 150) | ||||
| 	private void onSimpleEventFirst(SimpleEvent event) { | ||||
| 		++hits; | ||||
| 		assertEquals(1, hits); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/test/java/dev/kske/eventbus/SimpleEventSub.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/test/java/dev/kske/eventbus/SimpleEventSub.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| package dev.kske.eventbus; | ||||
|  | ||||
| /** | ||||
|  * Subclass of {@link SimpleEvent} for testing purposes. | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since 0.0.4 | ||||
|  */ | ||||
| public class SimpleEventSub extends SimpleEvent {} | ||||
		Reference in New Issue
	
	Block a user