Handler Caching #37
@@ -90,6 +90,16 @@ public final class EventBus {
 | 
			
		||||
	 */
 | 
			
		||||
	private final Map<Class<?>, TreeSet<EventHandler>> bindings = new ConcurrentHashMap<>();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * A cache mapping an event class to all handlers the event should be dispatched to. This
 | 
			
		||||
	 * includes polymorphic handlers that don't reference the event class explicitly. If an event
 | 
			
		||||
	 * class is not contained inside this cache, the {@link #bindings} have to be traversed manually
 | 
			
		||||
	 * in search of applicable handlers.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @since 1.3.0
 | 
			
		||||
	 */
 | 
			
		||||
	private final Map<Class<?>, TreeSet<EventHandler>> bindingCache = new ConcurrentHashMap<>();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Stores all registered event listeners (which declare event handlers) and prevents them from
 | 
			
		||||
	 * being garbage collected.
 | 
			
		||||
@@ -175,11 +185,17 @@ public final class EventBus {
 | 
			
		||||
	 * Searches for the event handlers bound to an event class. This includes polymorphic handlers
 | 
			
		||||
	 * that are bound to a supertype of the event class.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @implNote If the given event type was requested in the past, the handlers are retrieved from
 | 
			
		||||
	 *           the {@link #bindingCache}. If not, the entire {@link #bindings} are traversed in
 | 
			
		||||
	 *           search of polymorphic handlers compatible with the event type.
 | 
			
		||||
	 * @param eventType the event type to use for the search
 | 
			
		||||
	 * @return a navigable set containing the applicable handlers in descending order of priority
 | 
			
		||||
	 * @since 1.2.0
 | 
			
		||||
	 */
 | 
			
		||||
	private NavigableSet<EventHandler> getHandlersFor(Class<?> eventType) {
 | 
			
		||||
		if (bindingCache.containsKey(eventType)) {
 | 
			
		||||
			return bindingCache.get(eventType);
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			// Get handlers defined for the event class
 | 
			
		||||
			TreeSet<EventHandler> handlers =
 | 
			
		||||
@@ -192,8 +208,10 @@ public final class EventBus {
 | 
			
		||||
						if (handler.isPolymorphic())
 | 
			
		||||
							handlers.add(handler);
 | 
			
		||||
 | 
			
		||||
			bindingCache.put(eventType, handlers);
 | 
			
		||||
			return handlers;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Cancels an event that is currently dispatched from inside an event handler.
 | 
			
		||||
@@ -369,15 +387,28 @@ public final class EventBus {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Inserts a new handler into the {@link #bindings} map.
 | 
			
		||||
	 * Inserts a new handler into the {@link #bindings} map. Additionally, the handler is placed
 | 
			
		||||
	 * inside the {@link #bindingCache} where applicable.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param handler the handler to bind
 | 
			
		||||
	 * @since 1.2.0
 | 
			
		||||
	 */
 | 
			
		||||
	private void bindHandler(EventHandler handler) {
 | 
			
		||||
 | 
			
		||||
		// Bind handler
 | 
			
		||||
		bindings.putIfAbsent(handler.getEventType(), new TreeSet<>(byPriority));
 | 
			
		||||
		logger.log(Level.DEBUG, "Binding event handler {0}", handler);
 | 
			
		||||
		bindings.get(handler.getEventType()).add(handler);
 | 
			
		||||
 | 
			
		||||
		// Insert handler into cache
 | 
			
		||||
		bindingCache.putIfAbsent(handler.getEventType(), new TreeSet<>(byPriority));
 | 
			
		||||
		bindingCache.get(handler.getEventType()).add(handler);
 | 
			
		||||
 | 
			
		||||
		// Handler is polymorphic => insert where applicable
 | 
			
		||||
		if (handler.isPolymorphic())
 | 
			
		||||
			for (var binding : bindingCache.entrySet())
 | 
			
		||||
				if (binding.getKey().isAssignableFrom(handler.getEventType()))
 | 
			
		||||
					binding.getValue().add(handler);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -402,6 +433,18 @@ public final class EventBus {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Remove bindings from cache
 | 
			
		||||
		for (var binding : bindingCache.values()) {
 | 
			
		||||
			var it = binding.iterator();
 | 
			
		||||
			while (it.hasNext()) {
 | 
			
		||||
				var handler = it.next();
 | 
			
		||||
				if (handler.getListener() == listener) {
 | 
			
		||||
					logger.log(Level.TRACE, "Removing event handler {0} from cache", handler);
 | 
			
		||||
					it.remove();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Remove the listener itself
 | 
			
		||||
		registeredListeners.remove(listener);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user