001    package org.bukkit.plugin;
002    
003    import org.bukkit.event.Event;
004    import org.bukkit.event.EventException;
005    import org.bukkit.event.EventPriority;
006    import org.bukkit.event.Listener;
007    
008    /**
009     * Extends RegisteredListener to include timing information
010     */
011    public class TimedRegisteredListener extends RegisteredListener {
012        private int count;
013        private long totalTime;
014        private Class<? extends Event> eventClass;
015        private boolean multiple = false;
016    
017        public TimedRegisteredListener(final Listener pluginListener, final EventExecutor eventExecutor, final EventPriority eventPriority, final Plugin registeredPlugin, final boolean listenCancelled) {
018            super(pluginListener, eventExecutor, eventPriority, registeredPlugin, listenCancelled);
019        }
020    
021        @Override
022        public void callEvent(Event event) throws EventException {
023            if (event.isAsynchronous()) {
024                super.callEvent(event);
025                return;
026            }
027            count++;
028            Class<? extends Event> newEventClass = event.getClass();
029            if (this.eventClass == null) {
030                this.eventClass = newEventClass;
031            } else if (!this.eventClass.equals(newEventClass)) {
032                multiple = true;
033                this.eventClass = getCommonSuperclass(newEventClass, this.eventClass).asSubclass(Event.class);
034            }
035            long start = System.nanoTime();
036            super.callEvent(event);
037            totalTime += System.nanoTime() - start;
038        }
039    
040        private static Class<?> getCommonSuperclass(Class<?> class1, Class<?> class2) {
041            while (!class1.isAssignableFrom(class2)) {
042                class1 = class1.getSuperclass();
043            }
044            return class1;
045        }
046    
047        /**
048         * Resets the call count and total time for this listener
049         */
050        public void reset() {
051            count = 0;
052            totalTime = 0;
053        }
054    
055        /**
056         * Gets the total times this listener has been called
057         *
058         * @return Times this listener has been called
059         */
060        public int getCount() {
061            return count;
062        }
063    
064        /**
065         * Gets the total time calls to this listener have taken
066         *
067         * @return Total time for all calls of this listener
068         */
069        public long getTotalTime() {
070            return totalTime;
071        }
072    
073        /**
074         * Gets the class of the events this listener handled. If it handled
075         * multiple classes of event, the closest shared superclass will be
076         * returned, such that for any event this listener has handled,
077         * <code>this.getEventClass().isAssignableFrom(event.getClass())</code>
078         * and no class <code>this.getEventClass().isAssignableFrom(clazz)
079         * && this.getEventClass() != clazz &&
080         * event.getClass().isAssignableFrom(clazz)</code> for all handled events.
081         *
082         * @return the event class handled by this RegisteredListener
083         */
084        public Class<? extends Event> getEventClass() {
085            return eventClass;
086        }
087    
088        /**
089         * Gets whether this listener has handled multiple events, such that for
090         * some two events, <code>eventA.getClass() != eventB.getClass()</code>.
091         *
092         * @return true if this listener has handled multiple events
093         */
094        public boolean hasMultiple() {
095            return multiple;
096        }
097    }