diff --git a/event/src/main/java/net/md_5/bungee/event/EventBus.java b/event/src/main/java/net/md_5/bungee/event/EventBus.java index a6455d03..6df5870f 100644 --- a/event/src/main/java/net/md_5/bungee/event/EventBus.java +++ b/event/src/main/java/net/md_5/bungee/event/EventBus.java @@ -3,8 +3,10 @@ package net.md_5.bungee.event; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; @@ -15,7 +17,8 @@ import java.util.logging.Logger; public class EventBus { - private final Map, Map>> eventToHandler = new HashMap<>(); + private final Map, Map>> byListenerAndPriority = new HashMap<>(); + private final Map, EventHandlerMethod[]> byEventBaked = new HashMap<>(); private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final Logger logger; @@ -34,33 +37,27 @@ public class EventBus lock.readLock().lock(); try { - Map> handlersByPriority = eventToHandler.get( event.getClass() ); - for ( EventPriority value : EventPriority.values() ) + EventHandlerMethod[] handlers = byEventBaked.get( event.getClass() ); + if ( handlers != null ) { - Map handlers = handlersByPriority.get( value ); - if ( handlers != null ) + for ( EventHandlerMethod method : handlers ) { - for ( Map.Entry handler : handlers.entrySet() ) + try { - for ( Method method : handler.getValue() ) - { - try - { - method.invoke( handler.getKey(), event ); - } catch ( IllegalAccessException ex ) - { - throw new Error( "Method became inaccessible: " + event, ex ); - } catch ( IllegalArgumentException ex ) - { - throw new Error( "Method rejected target/argument: " + event, ex ); - } catch ( InvocationTargetException ex ) - { - logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, handler.getKey() ), ex.getCause() ); - } - } + method.invoke( event ); + } catch ( IllegalAccessException ex ) + { + throw new Error( "Method became inaccessible: " + event, ex ); + } catch ( IllegalArgumentException ex ) + { + throw new Error( "Method rejected target/argument: " + event, ex ); + } catch ( InvocationTargetException ex ) + { + logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, method.getListener() ), ex.getCause() ); } } } + } finally { lock.readLock().unlock(); @@ -110,11 +107,11 @@ public class EventBus { for ( Map.Entry, Map>> e : handler.entrySet() ) { - Map> prioritiesMap = eventToHandler.get( e.getKey() ); + Map> prioritiesMap = byListenerAndPriority.get( e.getKey() ); if ( prioritiesMap == null ) { prioritiesMap = new HashMap<>(); - eventToHandler.put( e.getKey(), prioritiesMap ); + byListenerAndPriority.put( e.getKey(), prioritiesMap ); } for ( Map.Entry> entry : e.getValue().entrySet() ) { @@ -127,6 +124,7 @@ public class EventBus Method[] baked = new Method[ entry.getValue().size() ]; currentPriorityMap.put( listener, entry.getValue().toArray( baked ) ); } + bakeHandlers( e.getKey() ); } } finally { @@ -142,7 +140,7 @@ public class EventBus { for ( Map.Entry, Map>> e : handler.entrySet() ) { - Map> prioritiesMap = eventToHandler.get( e.getKey() ); + Map> prioritiesMap = byListenerAndPriority.get( e.getKey() ); if ( prioritiesMap != null ) { for ( EventPriority priority : e.getValue().keySet() ) @@ -159,13 +157,41 @@ public class EventBus } if ( prioritiesMap.isEmpty() ) { - eventToHandler.remove( e.getKey() ); + byListenerAndPriority.remove( e.getKey() ); } } + bakeHandlers( e.getKey() ); } } finally { lock.writeLock().unlock(); } } + + /** + * Shouldn't be called without first locking the writeLock; intended for use + * only inside {@link #register(java.lang.Object) register(Object)} or + * {@link #unregister(java.lang.Object) unregister(Object)}. + */ + private void bakeHandlers(Class eventClass) + { + Map> handlersByPriority = byListenerAndPriority.get( eventClass ); + List handlersList = new ArrayList<>( handlersByPriority.size() * 2 ); + for ( EventPriority value : EventPriority.values() ) + { + Map handlersByListener = handlersByPriority.get( value ); + if ( handlersByListener != null ) + { + for ( Map.Entry listenerHandlers : handlersByListener.entrySet() ) + { + for ( Method method : listenerHandlers.getValue() ) + { + EventHandlerMethod ehm = new EventHandlerMethod( listenerHandlers.getKey(), method ); + handlersList.add( ehm ); + } + } + } + } + byEventBaked.put( eventClass, handlersList.toArray( new EventHandlerMethod[ handlersList.size() ] ) ); + } }