You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by bd...@apache.org on 2016/07/11 21:04:33 UTC

[06/13] shiro git commit: SHIRO-395: Consolidated Publisher and SubscriberRegistry interfaces into a single EventBus interface. The separate interfaces were causing a lot of unnecessary complexity if you had a component that need to both publish and sub

SHIRO-395: Consolidated Publisher and SubscriberRegistry interfaces into a single EventBus interface.  The separate interfaces were causing a lot of unnecessary complexity if you had a component that need to both publish and subscribe.  The new EventBus interface more easily/cleanly satisfies 3 usage scenarios in a single component (publish, subscribe and publish+subscribe).  All related test cases have 100% class, method and line coverage.

git-svn-id: https://svn.apache.org/repos/asf/shiro/trunk@1426977 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/shiro/repo
Commit: http://git-wip-us.apache.org/repos/asf/shiro/commit/bdecc0ba
Tree: http://git-wip-us.apache.org/repos/asf/shiro/tree/bdecc0ba
Diff: http://git-wip-us.apache.org/repos/asf/shiro/diff/bdecc0ba

Branch: refs/heads/1.3.x
Commit: bdecc0ba3265bfab031f0d10d9b9d3961670c0e3
Parents: 0c7a8b5
Author: Les Hazlewood <lh...@apache.org>
Authored: Sun Dec 30 19:11:17 2012 +0000
Committer: Brian Demers <bd...@apache.org>
Committed: Fri Jul 8 13:49:55 2016 -0400

----------------------------------------------------------------------
 .../java/org/apache/shiro/event/EventBus.java   |  85 ++++++++++
 .../org/apache/shiro/event/EventBusAware.java   |  35 ++++
 .../java/org/apache/shiro/event/Publisher.java  |  34 ----
 .../bus/AnnotationEventListenerResolver.java    |  96 -----------
 .../apache/shiro/event/bus/ClassComparator.java |  73 ---------
 .../apache/shiro/event/bus/DefaultEventBus.java | 161 ------------------
 .../apache/shiro/event/bus/EventListener.java   |  56 -------
 .../event/bus/EventListenerComparator.java      |  68 --------
 .../shiro/event/bus/EventListenerResolver.java  |  50 ------
 .../bus/SingleArgumentMethodEventListener.java  |  74 ---------
 .../shiro/event/bus/SubscriberRegistry.java     |  45 -----
 .../shiro/event/bus/TypedEventListener.java     |  27 ---
 .../AnnotationEventListenerResolver.java        |  96 +++++++++++
 .../shiro/event/support/ClassComparator.java    |  73 +++++++++
 .../shiro/event/support/DefaultEventBus.java    | 161 ++++++++++++++++++
 .../shiro/event/support/EventListener.java      |  56 +++++++
 .../event/support/EventListenerComparator.java  |  68 ++++++++
 .../event/support/EventListenerResolver.java    |  50 ++++++
 .../SingleArgumentMethodEventListener.java      |  74 +++++++++
 .../shiro/event/support/TypedEventListener.java |  27 +++
 .../AnnotationEventListenerResolverTest.groovy  |  45 -----
 .../org/apache/shiro/event/bus/BarEvent.groovy  |  29 ----
 .../org/apache/shiro/event/bus/BazEvent.groovy  |  29 ----
 .../shiro/event/bus/ClassComparatorTest.groovy  |  62 -------
 .../shiro/event/bus/DefaultEventBusTest.groovy  | 163 -------------------
 .../bus/ErroneouslyAnnotatedSubscriber.groovy   |  31 ----
 .../shiro/event/bus/ErrorCausingEvent.groovy    |  25 ---
 .../bus/EventListenerComparatorTest.groovy      |  71 --------
 .../bus/ExceptionThrowingSubscriber.groovy      |  32 ----
 .../org/apache/shiro/event/bus/FooEvent.groovy  |  29 ----
 .../event/bus/NotAnnotatedSubscriber.groovy     |  27 ---
 .../apache/shiro/event/bus/SimpleEvent.groovy   |  25 ---
 .../shiro/event/bus/SimpleSubscriber.groovy     |  38 -----
 ...SingleArgumentMethodEventListenerTest.groovy |  86 ----------
 .../event/bus/SubclassTestSubscriber.groovy     |  49 ------
 .../shiro/event/bus/TestSubscriber.groovy       |  50 ------
 .../AnnotationEventListenerResolverTest.groovy  |  45 +++++
 .../apache/shiro/event/support/BarEvent.groovy  |  29 ++++
 .../apache/shiro/event/support/BazEvent.groovy  |  29 ++++
 .../event/support/ClassComparatorTest.groovy    |  62 +++++++
 .../event/support/DefaultEventBusTest.groovy    | 163 +++++++++++++++++++
 .../ErroneouslyAnnotatedSubscriber.groovy       |  31 ++++
 .../event/support/ErrorCausingEvent.groovy      |  25 +++
 .../support/EventListenerComparatorTest.groovy  |  71 ++++++++
 .../support/ExceptionThrowingSubscriber.groovy  |  32 ++++
 .../apache/shiro/event/support/FooEvent.groovy  |  29 ++++
 .../event/support/NotAnnotatedSubscriber.groovy |  27 +++
 .../shiro/event/support/SimpleEvent.groovy      |  25 +++
 .../shiro/event/support/SimpleSubscriber.groovy |  38 +++++
 ...SingleArgumentMethodEventListenerTest.groovy |  86 ++++++++++
 .../event/support/SubclassTestSubscriber.groovy |  49 ++++++
 .../shiro/event/support/TestSubscriber.groovy   |  50 ++++++
 52 files changed, 1516 insertions(+), 1475 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/EventBus.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/EventBus.java b/core/src/main/java/org/apache/shiro/event/EventBus.java
new file mode 100644
index 0000000..525240f
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/event/EventBus.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.event;
+
+/**
+ * An event bus can publish events to event subscribers as well as provide a mechanism for registering and unregistering
+ * event subscribers.
+ * <p/>
+ * An event bus enables a publish/subscribe paradigm within Shiro - components can publish or consume events they
+ * find relevant without needing to be tightly coupled to other components.  This affords great
+ * flexibility within Shiro by promoting loose coupling and high cohesion between components and a much safer pluggable
+ * architecture.
+ * <h2>Sending Events</h2>
+ * If a component wishes to publish events to other components:
+ * <pre>
+ *     MyEvent myEvent = createMyEvent();
+ *     eventBus.publish(myEvent);
+ * </pre>
+ * The event bus will determine the type of event and then dispatch the event to components that wish to receive
+ * events of that type.
+ * <h2>Receiving Events</h2>
+ * A component can receive events of interest by doing the following.
+ * <ol>
+ *     <li>For each type of event you wish to consume, create a public method that accepts a single event argument.
+ *     The method argument type indicates the type of event to receive.</li>
+ *     <li>Annotate each of these public methods with the {@link org.apache.shiro.event.Subscribe Subscribe} annotation.</li>
+ *     <li>Register the component with the event bus:
+ *     <pre>
+ *         eventBus.register(myComponent);
+ *     </pre>
+ *     </li>
+ * </ol>
+ * After registering the component, when when an event of a respective type is published, the component's
+ * {@code Subscribe}-annotated method(s) will be invoked as expected.
+ * <p/>
+ * This design (and its constituent helper components) was largely influenced by
+ * Guava's <a href="http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/eventbus/EventBus.html">EventBus</a>
+ * concept, although no code was viewed/copied/imported (even though Guava code is Apache 2.0 licensed and could have
+ * been used).
+ *
+ * @since 1.3
+ */
+public interface EventBus {
+
+    /**
+     * Publishes the specified event to an event subsystem that will deliver events to relevant {@link Subscribe}rs.
+     *
+     * @param event The event object to distribute to relevant subscribers.
+     */
+    void publish(Object event);
+
+    /**
+     * Registers all event handler methods on the specified instance to receive relevant events.  The handler methods
+     * are determined by the {@code EventBus} implementation, typically by using an
+     * {@link org.apache.shiro.event.support.EventListenerResolver EventListenerResolver}
+     * (e.g. {@link org.apache.shiro.event.support.AnnotationEventListenerResolver AnnotationEventListenerResolver}).
+     *
+     * @param subscriber the object whose event handler methods should be registered to receive events.
+     */
+    void register(Object subscriber);
+
+    /**
+     * Unregisters all previously-registered event handler methods on the specified instance.  If the specified object
+     * was not previously registered, calling this method has no effect.
+     *
+     * @param subscriber the previously
+     */
+    void unregister(Object subscriber);
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/EventBusAware.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/EventBusAware.java b/core/src/main/java/org/apache/shiro/event/EventBusAware.java
new file mode 100644
index 0000000..7d26613
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/event/EventBusAware.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.event;
+
+/**
+ * Interface implemented by components that utilize an EventBus for publishing and/or subscribing to/from events
+ * and wish that EventBus to be supplied if one is available.
+ *
+ * @since 1.3
+ */
+public interface EventBusAware {
+
+    /**
+     * Sets the available {@code EventBus} that may be used for publishing and subscribing to/from events.
+     *
+     * @param bus the available {@code EventBus}.
+     */
+    void setEventBus(EventBus bus);
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/Publisher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/Publisher.java b/core/src/main/java/org/apache/shiro/event/Publisher.java
deleted file mode 100644
index 50c1c8d..0000000
--- a/core/src/main/java/org/apache/shiro/event/Publisher.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event;
-
-/**
- * Publishes events to an event subsystem that will deliver events to registered {@link Subscribe}rs.
- *
- * @since 1.3
- */
-public interface Publisher {
-
-    /**
-     * Publishes the specified event to an event subsystem that will deliver events to relevant {@link Subscribe}rs.
-     *
-     * @param event The event object to distribute to relevant subscribers.
-     */
-    void publish(Object event);
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/bus/AnnotationEventListenerResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/bus/AnnotationEventListenerResolver.java b/core/src/main/java/org/apache/shiro/event/bus/AnnotationEventListenerResolver.java
deleted file mode 100644
index 883dbcf..0000000
--- a/core/src/main/java/org/apache/shiro/event/bus/AnnotationEventListenerResolver.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus;
-
-import org.apache.shiro.event.Subscribe;
-import org.apache.shiro.util.ClassUtils;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Inspects an object for annotated methods of interest and creates an {@link EventListener} for each method discovered.
- * An event bus will call the resulting listeners as relevant events arrive.
- * <p/>
- * The default {@link #setAnnotationClass(Class) annotationClass} is {@link Subscribe}, indicating any
- * {@link Subscribe}-annotated method will be represented as an EventListener.
- *
- * @see SingleArgumentMethodEventListener
- * @since 1.3
- */
-public class AnnotationEventListenerResolver implements EventListenerResolver {
-
-    private Class<? extends Annotation> annotationClass;
-
-    public AnnotationEventListenerResolver() {
-        this.annotationClass = Subscribe.class;
-    }
-
-    /**
-     * Returns a new collection of {@link EventListener} instances, each instance corresponding to an annotated
-     * method discovered on the specified {@code instance} argument.
-     *
-     * @param instance the instance to inspect for annotated event handler methods.
-     * @return a new collection of {@link EventListener} instances, each instance corresponding to an annotated
-     *         method discovered on the specified {@code instance} argument.
-     */
-    public List<EventListener> getEventListeners(Object instance) {
-        if (instance == null) {
-            return Collections.emptyList();
-        }
-
-        List<Method> methods = ClassUtils.getAnnotatedMethods(instance.getClass(), getAnnotationClass());
-        if (methods == null || methods.isEmpty()) {
-            return Collections.emptyList();
-        }
-
-        List<EventListener> listeners = new ArrayList<EventListener>(methods.size());
-
-        for (Method m : methods) {
-            listeners.add(new SingleArgumentMethodEventListener(instance, m));
-        }
-
-        return listeners;
-    }
-
-    /**
-     * Returns the type of annotation that indicates a method that should be represented as an {@link EventListener},
-     * defaults to {@link Subscribe}.
-     *
-     * @return the type of annotation that indicates a method that should be represented as an {@link EventListener},
-     *         defaults to {@link Subscribe}.
-     */
-    public Class<? extends Annotation> getAnnotationClass() {
-        return annotationClass;
-    }
-
-    /**
-     * Sets the type of annotation that indicates a method that should be represented as an {@link EventListener}.
-     * The default value is {@link Subscribe}.
-     *
-     * @param annotationClass the type of annotation that indicates a method that should be represented as an
-     *                        {@link EventListener}.  The default value is {@link Subscribe}.
-     */
-    public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
-        this.annotationClass = annotationClass;
-    }
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/bus/ClassComparator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/bus/ClassComparator.java b/core/src/main/java/org/apache/shiro/event/bus/ClassComparator.java
deleted file mode 100644
index 4d1928f..0000000
--- a/core/src/main/java/org/apache/shiro/event/bus/ClassComparator.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus;
-
-import java.util.Comparator;
-
-/**
- * Compares two classes based on their position in a hierarchy.  Classes higher up in a hierarchy are 'greater than'
- * (ordered later) than classes lower in a hierarchy (ordered earlier).  Classes in unrelated hierarchies have the same
- * order priority.
- * <p/>
- * Event bus implementations use this comparator to determine which event listener method to invoke when polymorphic
- * listener methods are defined:
- * <p/>
- * If two event classes exist A and B, where A is the parent class of B (and B is a subclass of A) and an event
- * subscriber listens to both events:
- * <pre>
- * &#64;Subscribe
- * public void onEvent(A a) { ... }
- *
- * &#64;Subscribe
- * public void onEvent(B b) { ... }
- * </pre>
- *
- * The {@code onEvent(B b)} method will be invoked on the subscriber and the
- * {@code onEvent(A a)} method will <em>not</em> be invoked.  This is to prevent multiple dispatching of a single event
- * to the same consumer.
- * <p/>
- * The ClassComparator is used to order listener method priority based on their event argument class - methods handling
- * event subclasses have higher precedence than superclasses.
- *
- * @since 1.3
- */
-public class ClassComparator implements Comparator<Class> {
-
-    public int compare(Class a, Class b) {
-        if (a == null) {
-            if (b == null) {
-                return 0;
-            } else {
-                return -1;
-            }
-        } else if (b == null) {
-            return 1;
-        } else if (a == b || a.equals(b)) {
-            return 0;
-        } else {
-            if (a.isAssignableFrom(b)) {
-                return 1;
-            } else if (b.isAssignableFrom(a)) {
-                return -1;
-            } else {
-                return 0;
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/bus/DefaultEventBus.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/bus/DefaultEventBus.java b/core/src/main/java/org/apache/shiro/event/bus/DefaultEventBus.java
deleted file mode 100644
index 4b74522..0000000
--- a/core/src/main/java/org/apache/shiro/event/bus/DefaultEventBus.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus;
-
-
-import org.apache.shiro.event.Publisher;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * A default event bus implementation that synchronously publishes events to registered listeners.  Listeners can be
- * registered or unregistered for events as necessary.
- * <p/>
- * An event bus enables a publish/subscribe paradigm within Shiro - components can publish or consume events they
- * find relevant without needing to be tightly coupled to other components.  This affords great
- * flexibility within Shiro by promoting loose coupling and high cohesion between components and a much safer pluggable
- * architecture.
- * <h2>Sending Events</h2>
- * If a component wishes to publish events to other components:
- * <pre>
- *     MyEvent myEvent = createMyEvent();
- *     eventBus.publish(myEvent);
- * </pre>
- * The event bus will determine the type of event and then dispatch the event to components that wish to receive
- * events of that type.
- * <h2>Receiving Events</h2>
- * A component can receive events of interest by doing the following.
- * <ol>
- *     <li>For each type of event you wish to consume, create a public method that accepts a single event argument.
- *     The method argument type indicates the type of event to receive.</li>
- *     <li>Annotate each of these public methods with the {@link org.apache.shiro.event.Subscribe Subscribe} annotation.</li>
- *     <li>Register the component with the event bus:
- *     <pre>
- *         eventBus.register(myComponent);
- *     </pre>
- *     </li>
- * </ol>
- * After registering the component, when when an event of a respective type is published, the component's
- * {@code Subscribe}-annotated method(s) will be invoked as expected.
- * <p/>
- * This design (and its constituent helper components) was largely influenced by
- * Guava's <a href="http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/eventbus/EventBus.html">EventBus</a>
- * concept, although no code was shared/imported (even though Guava is Apache 2.0 licensed and could have
- * been used).
- *
- * @since 1.3
- */
-public class DefaultEventBus implements Publisher, SubscriberRegistry {
-
-    private static final Logger log = LoggerFactory.getLogger(DefaultEventBus.class);
-
-    private EventListenerResolver eventListenerResolver;
-
-    private final Map<Object,Subscriber> registry;
-
-    public DefaultEventBus() {
-        this.registry = new ConcurrentHashMap<Object, Subscriber>();
-        this.eventListenerResolver = new AnnotationEventListenerResolver();
-    }
-
-    public EventListenerResolver getEventListenerResolver() {
-        return eventListenerResolver;
-    }
-
-    public void setEventListenerResolver(EventListenerResolver eventListenerResolver) {
-        this.eventListenerResolver = eventListenerResolver;
-    }
-
-    public void publish(Object event) {
-        if (event == null) {
-            log.info("Received null event for publishing.  Ignoring and returning.");
-            return;
-        }
-
-        for( Subscriber subscriber : registry.values() ) {
-            subscriber.onEvent(event);
-        }
-    }
-
-    public void register(Object instance) {
-        if (instance == null) {
-            log.info("Received null instance for registration.  Ignoring registration request.");
-            return;
-        }
-
-        unregister(instance);
-
-        List<EventListener> listeners = getEventListenerResolver().getEventListeners(instance);
-
-        if (listeners == null || listeners.isEmpty()) {
-            log.warn("Unable to resolve any event listeners for the subscriber instance [" + instance +
-                    "].  Ignoring registration request.");
-            return;
-        }
-
-        Subscriber subscriber = new Subscriber(instance, listeners);
-
-        this.registry.put(instance, subscriber);
-    }
-
-    public void unregister(Object instance) {
-        if (instance == null) {
-            return;
-        }
-        this.registry.remove(instance);
-    }
-
-    private class Subscriber {
-
-        private final Object instance;
-        private final List<EventListener> registeredListeners;
-
-        public Subscriber(Object instance, List<EventListener> listeners) {
-            this.instance = instance;
-            List<EventListener> toSort = new ArrayList<EventListener>(listeners);
-            Collections.sort(toSort, new EventListenerComparator());
-            this.registeredListeners = toSort;
-        }
-
-        public void onEvent(Object event) {
-
-            Set<Object> delivered = new HashSet<Object>();
-
-            for(EventListener listener : this.registeredListeners) {
-                Object target = listener;
-                if (listener instanceof SingleArgumentMethodEventListener) {
-                    SingleArgumentMethodEventListener singleArgListener = (SingleArgumentMethodEventListener)listener;
-                    target = singleArgListener.getTarget();
-                }
-                if (listener.accepts(event) && !delivered.contains(target)) {
-                    try {
-                        listener.onEvent(event);
-                        delivered.add(target);
-                    } catch (Throwable t) {
-                        log.warn("Event listener processing failed.  Listeners should generally " +
-                                "handle exceptions directly and not propagate to the event bus.", t);
-                    }
-                }
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/bus/EventListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/bus/EventListener.java b/core/src/main/java/org/apache/shiro/event/bus/EventListener.java
deleted file mode 100644
index a653674..0000000
--- a/core/src/main/java/org/apache/shiro/event/bus/EventListener.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus;
-
-/**
- * An event listener knows how to accept and process events of a particular type (or types).
- * <p/>
- * Note that this interface is in the event bus package (and not the event package directly) because it is a supporting
- * concept for event bus implementations and not something that application
- * developers using Shiro should implement directly.  App developers should instead use the
- * {@link org.apache.shiro.event.Subscribe Subscribe} annotation on methods they wish to receive events.
- * <p/>
- * This interface therefore mainly represents a 'middle man' between the event bus and the actual subscribing
- * component.  As such, event bus implementors (or framework/infrastructural implementors) or those that wish to
- * customize listener/dispatch functionality might find this concept useful.
- * <p/>
- * It is a concept almost always used in conjunction with a {@link EventListenerResolver} implementation.
- *
- * @see SingleArgumentMethodEventListener
- * @see AnnotationEventListenerResolver
- *
- * @since 1.3
- */
-public interface EventListener {
-
-    /**
-     * Returns {@code true} if the listener instance can process the specified event object, {@code false} otherwise.
-     * @param event the event object to test
-     * @return {@code true} if the listener instance can process the specified event object, {@code false} otherwise.
-     */
-    boolean accepts(Object event);
-
-    /**
-     * Handles the specified event.  Again, as this interface is an implementation concept, implementations of this
-     * method will likely dispatch the event to a 'real' processor (e.g. method).
-     *
-     * @param event the event to handle.
-     */
-    void onEvent(Object event);
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/bus/EventListenerComparator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/bus/EventListenerComparator.java b/core/src/main/java/org/apache/shiro/event/bus/EventListenerComparator.java
deleted file mode 100644
index d096591..0000000
--- a/core/src/main/java/org/apache/shiro/event/bus/EventListenerComparator.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus;
-
-import java.util.Comparator;
-
-/**
- * Compares two event listeners to determine the order in which they should be invoked when an event is dispatched.
- * The lower the order, the sooner it will be invoked (the higher its precedence).  The higher the order, the later
- * it will be invoked (the lower its precedence).
- * <p/>
- * TypedEventListeners have a higher precedence (i.e. a lower order) than standard EventListener instances.  Standard
- * EventListener instances have the same order priority.
- * <p/>
- * When both objects being compared are TypedEventListeners, they are ordered according to the rules of the
- * {@link ClassComparator}, using the TypedEventListeners'
- * {@link org.apache.shiro.event.bus.TypedEventListener#getEventType() eventType}.
- *
- * @since 1.3
- */
-public class EventListenerComparator implements Comparator<EventListener> {
-
-    public int compare(EventListener a, EventListener b) {
-        if (a == null) {
-            if (b == null) {
-                return 0;
-            } else {
-                return -1;
-            }
-        } else if (b == null) {
-            return 1;
-        } else if (a == b || a.equals(b)) {
-            return 0;
-        } else {
-            if (a instanceof TypedEventListener) {
-                TypedEventListener ta = (TypedEventListener)a;
-                if (b instanceof TypedEventListener) {
-                    TypedEventListener tb = (TypedEventListener)b;
-                    return new ClassComparator().compare(ta.getEventType(), tb.getEventType());
-                } else {
-                    return -1; //TypedEventListeners are 'less than' (higher priority) than non typed
-                }
-            } else {
-                if (b instanceof TypedEventListener) {
-                    return 1;
-                } else {
-                    return 0;
-                }
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/bus/EventListenerResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/bus/EventListenerResolver.java b/core/src/main/java/org/apache/shiro/event/bus/EventListenerResolver.java
deleted file mode 100644
index b865d89..0000000
--- a/core/src/main/java/org/apache/shiro/event/bus/EventListenerResolver.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus;
-
-import java.util.List;
-
-/**
- * An {@code EventListenerResolver} knows how to resolve (either create or lookup) {@link EventListener} instances
- * as a result of inspecting a subscriber object, mostly likely a
- * {@link org.apache.shiro.event.Subscribe Subscribe}-annotated object instance.
- * <p/>
- * This interface exists primarily as a support concept for the {@link DefaultEventBus} implementation.  Custom
- * implementations of this interface can be configured on a {@link DefaultEventBus} instance to determine exactly
- * how a subscriber receives events.
- * <p/>
- * For example, the {@link AnnotationEventListenerResolver AnnotationEventListenerResolver} will inspect a runtime
- * object for {@link org.apache.shiro.event.Subscribe Subscribe}-annotated methods, and for each method found, return
- * an {@link EventListener} instance representing the method to invoke.
- *
- * @see AnnotationEventListenerResolver
- * @see SingleArgumentMethodEventListener
- * @since 1.3
- */
-public interface EventListenerResolver {
-
-    /**
-     * Returns {@link EventListener} instances as a result of inspecting a subscriber object, mostly likely with
-     * {@link org.apache.shiro.event.Subscribe Subscribe}-annotated methods.
-     *
-     * @param instance the subscriber instance for which EventListener instances should be acquired.
-     * @return {@link EventListener} instances as a result of inspecting a subscriber object.
-     */
-    List<EventListener> getEventListeners(Object instance);
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/bus/SingleArgumentMethodEventListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/bus/SingleArgumentMethodEventListener.java b/core/src/main/java/org/apache/shiro/event/bus/SingleArgumentMethodEventListener.java
deleted file mode 100644
index f5ea9f9..0000000
--- a/core/src/main/java/org/apache/shiro/event/bus/SingleArgumentMethodEventListener.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus;
-
-import java.lang.reflect.Method;
-
-/**
- * A event listener that invokes a target object's method that accepts a single event argument.
- *
- * @since 1.3
- */
-public class SingleArgumentMethodEventListener implements TypedEventListener {
-
-    private final Object target;
-    private final Method method;
-
-    public SingleArgumentMethodEventListener(Object target, Method method) {
-        this.target = target;
-        this.method = method;
-        //assert that the method is defined as expected:
-        getMethodArgumentType(method);
-    }
-
-    public Object getTarget() {
-        return this.target;
-    }
-
-    public Method getMethod() {
-        return this.method;
-    }
-
-    public boolean accepts(Object event) {
-        return event != null && getEventType().isInstance(event);
-    }
-
-    public Class getEventType() {
-        return getMethodArgumentType(getMethod());
-    }
-
-    public void onEvent(Object event) {
-        Method method = getMethod();
-        try {
-            method.invoke(getTarget(), event);
-        } catch (Exception e) {
-            throw new IllegalStateException("Unable to invoke event handler method [" + method + "]", e);
-        }
-    }
-
-    protected Class getMethodArgumentType(Method method) {
-        Class[] paramTypes = method.getParameterTypes();
-        if (paramTypes.length != 1) {
-            //the default implementation expects a single typed argument and nothing more:
-            String msg = "Event handler methods must accept a single argument.";
-            throw new IllegalArgumentException(msg);
-        }
-        return paramTypes[0];
-    }
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/bus/SubscriberRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/bus/SubscriberRegistry.java b/core/src/main/java/org/apache/shiro/event/bus/SubscriberRegistry.java
deleted file mode 100644
index af57d6e..0000000
--- a/core/src/main/java/org/apache/shiro/event/bus/SubscriberRegistry.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus;
-
-/**
- * Allows event subscribers to register or unregister with an event subsystem to receive (or not receive) published
- * events.
- *
- * @since 1.3
- */
-public interface SubscriberRegistry {
-
-    /**
-     * Registers all event handler methods on the specified instance to receive relevant events.  The handler methods
-     * are determined by {@link SubscriberRegistry} implementations, typically by using an
-     * {@link EventListenerResolver} (e.g. {@link AnnotationEventListenerResolver}).
-     *
-     * @param subscriber the object whose event handler methods should be registered to receive events.
-     */
-    void register(Object subscriber);
-
-    /**
-     * Unregisters all previously-registered event handler methods on the specified instance.  If the specified object
-     * was not previously registered, calling this method has no effect.
-     *
-     * @param subscriber the previously
-     */
-    void unregister(Object subscriber);
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/bus/TypedEventListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/bus/TypedEventListener.java b/core/src/main/java/org/apache/shiro/event/bus/TypedEventListener.java
deleted file mode 100644
index 9cb51e0..0000000
--- a/core/src/main/java/org/apache/shiro/event/bus/TypedEventListener.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus;
-
-/**
- * @since 1.3
- */
-public interface TypedEventListener extends EventListener {
-
-    Class getEventType();
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/support/AnnotationEventListenerResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/support/AnnotationEventListenerResolver.java b/core/src/main/java/org/apache/shiro/event/support/AnnotationEventListenerResolver.java
new file mode 100644
index 0000000..a9a94ce
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/event/support/AnnotationEventListenerResolver.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.event.support;
+
+import org.apache.shiro.event.Subscribe;
+import org.apache.shiro.util.ClassUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Inspects an object for annotated methods of interest and creates an {@link EventListener} instance for each method
+ * discovered.  An event bus will call the resulting listeners as relevant events arrive.
+ * <p/>
+ * The default {@link #setAnnotationClass(Class) annotationClass} is {@link Subscribe}, indicating each
+ * {@link Subscribe}-annotated method will be represented as an EventListener.
+ *
+ * @see SingleArgumentMethodEventListener
+ * @since 1.3
+ */
+public class AnnotationEventListenerResolver implements EventListenerResolver {
+
+    private Class<? extends Annotation> annotationClass;
+
+    public AnnotationEventListenerResolver() {
+        this.annotationClass = Subscribe.class;
+    }
+
+    /**
+     * Returns a new collection of {@link EventListener} instances, each instance corresponding to an annotated
+     * method discovered on the specified {@code instance} argument.
+     *
+     * @param instance the instance to inspect for annotated event handler methods.
+     * @return a new collection of {@link EventListener} instances, each instance corresponding to an annotated
+     *         method discovered on the specified {@code instance} argument.
+     */
+    public List<EventListener> getEventListeners(Object instance) {
+        if (instance == null) {
+            return Collections.emptyList();
+        }
+
+        List<Method> methods = ClassUtils.getAnnotatedMethods(instance.getClass(), getAnnotationClass());
+        if (methods == null || methods.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        List<EventListener> listeners = new ArrayList<EventListener>(methods.size());
+
+        for (Method m : methods) {
+            listeners.add(new SingleArgumentMethodEventListener(instance, m));
+        }
+
+        return listeners;
+    }
+
+    /**
+     * Returns the type of annotation that indicates a method that should be represented as an {@link EventListener},
+     * defaults to {@link Subscribe}.
+     *
+     * @return the type of annotation that indicates a method that should be represented as an {@link EventListener},
+     *         defaults to {@link Subscribe}.
+     */
+    public Class<? extends Annotation> getAnnotationClass() {
+        return annotationClass;
+    }
+
+    /**
+     * Sets the type of annotation that indicates a method that should be represented as an {@link EventListener}.
+     * The default value is {@link Subscribe}.
+     *
+     * @param annotationClass the type of annotation that indicates a method that should be represented as an
+     *                        {@link EventListener}.  The default value is {@link Subscribe}.
+     */
+    public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
+        this.annotationClass = annotationClass;
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/support/ClassComparator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/support/ClassComparator.java b/core/src/main/java/org/apache/shiro/event/support/ClassComparator.java
new file mode 100644
index 0000000..21db4ba
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/event/support/ClassComparator.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.event.support;
+
+import java.util.Comparator;
+
+/**
+ * Compares two classes based on their position in a hierarchy.  Classes higher up in a hierarchy are 'greater than'
+ * (ordered later) than classes lower in a hierarchy (ordered earlier).  Classes in unrelated hierarchies have the same
+ * order priority.
+ * <p/>
+ * Event bus implementations use this comparator to determine which event listener method to invoke when polymorphic
+ * listener methods are defined:
+ * <p/>
+ * If two event classes exist A and B, where A is the parent class of B (and B is a subclass of A) and an event
+ * subscriber listens to both events:
+ * <pre>
+ * &#64;Subscribe
+ * public void onEvent(A a) { ... }
+ *
+ * &#64;Subscribe
+ * public void onEvent(B b) { ... }
+ * </pre>
+ *
+ * The {@code onEvent(B b)} method will be invoked on the subscriber and the
+ * {@code onEvent(A a)} method will <em>not</em> be invoked.  This is to prevent multiple dispatching of a single event
+ * to the same consumer.
+ * <p/>
+ * The ClassComparator is used to order listener method priority based on their event argument class - methods handling
+ * event subclasses have higher precedence than superclasses.
+ *
+ * @since 1.3
+ */
+public class ClassComparator implements Comparator<Class> {
+
+    public int compare(Class a, Class b) {
+        if (a == null) {
+            if (b == null) {
+                return 0;
+            } else {
+                return -1;
+            }
+        } else if (b == null) {
+            return 1;
+        } else if (a == b || a.equals(b)) {
+            return 0;
+        } else {
+            if (a.isAssignableFrom(b)) {
+                return 1;
+            } else if (b.isAssignableFrom(a)) {
+                return -1;
+            } else {
+                return 0;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/support/DefaultEventBus.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/support/DefaultEventBus.java b/core/src/main/java/org/apache/shiro/event/support/DefaultEventBus.java
new file mode 100644
index 0000000..e8520db
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/event/support/DefaultEventBus.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.event.support;
+
+import org.apache.shiro.event.EventBus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A default event bus implementation that synchronously publishes events to registered listeners.  Listeners can be
+ * registered or unregistered for events as necessary.
+ * <p/>
+ * An event bus enables a publish/subscribe paradigm within Shiro - components can publish or consume events they
+ * find relevant without needing to be tightly coupled to other components.  This affords great
+ * flexibility within Shiro by promoting loose coupling and high cohesion between components and a much safer
+ * pluggable architecture that is more resilient to change over time.
+ * <h2>Sending Events</h2>
+ * If a component wishes to publish events to other components:
+ * <pre>
+ *     MyEvent myEvent = createMyEvent();
+ *     eventBus.publish(myEvent);
+ * </pre>
+ * The event bus will determine the type of event and then dispatch the event to components that wish to receive
+ * events of that type.
+ * <h2>Receiving Events</h2>
+ * A component can receive events of interest by doing the following.
+ * <ol>
+ *     <li>For each type of event you wish to consume, create a public method that accepts a single event argument.
+ *     The method argument type indicates the type of event to receive.</li>
+ *     <li>Annotate each of these public methods with the {@link org.apache.shiro.event.Subscribe Subscribe} annotation.</li>
+ *     <li>Register the component with the event bus:
+ *     <pre>
+ *         eventBus.register(myComponent);
+ *     </pre>
+ *     </li>
+ * </ol>
+ * After registering the component, when when an event of a respective type is published, the component's
+ * {@code Subscribe}-annotated method(s) will be invoked as expected.
+ * <p/>
+ * This design (and its constituent helper components) was largely influenced by
+ * Guava's <a href="http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/eventbus/EventBus.html">EventBus</a>
+ * concept, although no code was shared/imported (even though Guava is Apache 2.0 licensed and could have
+ * been used).
+ *
+ * @since 1.3
+ */
+public class DefaultEventBus implements EventBus {
+
+    private static final Logger log = LoggerFactory.getLogger(DefaultEventBus.class);
+
+    private EventListenerResolver eventListenerResolver;
+
+    private final Map<Object,Subscriber> registry;
+
+    public DefaultEventBus() {
+        this.registry = new ConcurrentHashMap<Object, Subscriber>();
+        this.eventListenerResolver = new AnnotationEventListenerResolver();
+    }
+
+    public EventListenerResolver getEventListenerResolver() {
+        return eventListenerResolver;
+    }
+
+    public void setEventListenerResolver(EventListenerResolver eventListenerResolver) {
+        this.eventListenerResolver = eventListenerResolver;
+    }
+
+    public void publish(Object event) {
+        if (event == null) {
+            log.info("Received null event for publishing.  Ignoring and returning.");
+            return;
+        }
+
+        for( Subscriber subscriber : registry.values() ) {
+            subscriber.onEvent(event);
+        }
+    }
+
+    public void register(Object instance) {
+        if (instance == null) {
+            log.info("Received null instance for registration.  Ignoring registration request.");
+            return;
+        }
+
+        unregister(instance);
+
+        List<EventListener> listeners = getEventListenerResolver().getEventListeners(instance);
+
+        if (listeners == null || listeners.isEmpty()) {
+            log.warn("Unable to resolve any event listeners for the subscriber instance [" + instance +
+                    "].  Ignoring registration request.");
+            return;
+        }
+
+        Subscriber subscriber = new Subscriber(instance, listeners);
+
+        this.registry.put(instance, subscriber);
+    }
+
+    public void unregister(Object instance) {
+        if (instance == null) {
+            return;
+        }
+        this.registry.remove(instance);
+    }
+
+    private class Subscriber {
+
+        private final Object instance;
+        private final List<EventListener> registeredListeners;
+
+        public Subscriber(Object instance, List<EventListener> listeners) {
+            this.instance = instance;
+            List<EventListener> toSort = new ArrayList<EventListener>(listeners);
+            Collections.sort(toSort, new EventListenerComparator());
+            this.registeredListeners = toSort;
+        }
+
+        public void onEvent(Object event) {
+
+            Set<Object> delivered = new HashSet<Object>();
+
+            for(EventListener listener : this.registeredListeners) {
+                Object target = listener;
+                if (listener instanceof SingleArgumentMethodEventListener) {
+                    SingleArgumentMethodEventListener singleArgListener = (SingleArgumentMethodEventListener)listener;
+                    target = singleArgListener.getTarget();
+                }
+                if (listener.accepts(event) && !delivered.contains(target)) {
+                    try {
+                        listener.onEvent(event);
+                    } catch (Throwable t) {
+                        log.warn("Event listener processing failed.  Listeners should generally " +
+                                "handle exceptions directly and not propagate to the event bus.", t);
+                    } finally {
+                        delivered.add(target);
+                    }
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/support/EventListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/support/EventListener.java b/core/src/main/java/org/apache/shiro/event/support/EventListener.java
new file mode 100644
index 0000000..adf386a
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/event/support/EventListener.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.event.support;
+
+/**
+ * An event listener knows how to accept and process events of a particular type (or types).
+ * <p/>
+ * Note that this interface is in the event implementation support package (and not the event package directly)
+ * because it is a supporting concept for event bus implementations and not something that most application
+ * developers using Shiro should implement directly.  App developers should instead use the
+ * {@link org.apache.shiro.event.Subscribe Subscribe} annotation on methods they wish to receive events.
+ * <p/>
+ * This interface therefore mainly represents a 'middle man' between the event bus and the actual subscribing
+ * component.  As such, event bus implementors (or framework/infrastructural implementors) or those that wish to
+ * customize listener/dispatch functionality might find this concept useful.
+ * <p/>
+ * It is a concept almost always used in conjunction with a {@link EventListenerResolver} implementation.
+ *
+ * @see SingleArgumentMethodEventListener
+ * @see AnnotationEventListenerResolver
+ *
+ * @since 1.3
+ */
+public interface EventListener {
+
+    /**
+     * Returns {@code true} if the listener instance can process the specified event object, {@code false} otherwise.
+     * @param event the event object to test
+     * @return {@code true} if the listener instance can process the specified event object, {@code false} otherwise.
+     */
+    boolean accepts(Object event);
+
+    /**
+     * Handles the specified event.  Again, as this interface is an implementation concept, implementations of this
+     * method will likely dispatch the event to a 'real' processor (e.g. method).
+     *
+     * @param event the event to handle.
+     */
+    void onEvent(Object event);
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/support/EventListenerComparator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/support/EventListenerComparator.java b/core/src/main/java/org/apache/shiro/event/support/EventListenerComparator.java
new file mode 100644
index 0000000..817c805
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/event/support/EventListenerComparator.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.event.support;
+
+import java.util.Comparator;
+
+/**
+ * Compares two event listeners to determine the order in which they should be invoked when an event is dispatched.
+ * The lower the order, the sooner it will be invoked (the higher its precedence).  The higher the order, the later
+ * it will be invoked (the lower its precedence).
+ * <p/>
+ * TypedEventListeners have a higher precedence (i.e. a lower order) than standard EventListener instances.  Standard
+ * EventListener instances have the same order priority.
+ * <p/>
+ * When both objects being compared are TypedEventListeners, they are ordered according to the rules of the
+ * {@link ClassComparator}, using the TypedEventListeners'
+ * {@link TypedEventListener#getEventType() eventType}.
+ *
+ * @since 1.3
+ */
+public class EventListenerComparator implements Comparator<EventListener> {
+
+    public int compare(EventListener a, EventListener b) {
+        if (a == null) {
+            if (b == null) {
+                return 0;
+            } else {
+                return -1;
+            }
+        } else if (b == null) {
+            return 1;
+        } else if (a == b || a.equals(b)) {
+            return 0;
+        } else {
+            if (a instanceof TypedEventListener) {
+                TypedEventListener ta = (TypedEventListener)a;
+                if (b instanceof TypedEventListener) {
+                    TypedEventListener tb = (TypedEventListener)b;
+                    return new ClassComparator().compare(ta.getEventType(), tb.getEventType());
+                } else {
+                    return -1; //TypedEventListeners are 'less than' (higher priority) than non typed
+                }
+            } else {
+                if (b instanceof TypedEventListener) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/support/EventListenerResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/support/EventListenerResolver.java b/core/src/main/java/org/apache/shiro/event/support/EventListenerResolver.java
new file mode 100644
index 0000000..7a8773e
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/event/support/EventListenerResolver.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.event.support;
+
+import java.util.List;
+
+/**
+ * An {@code EventListenerResolver} knows how to resolve (either create or lookup) {@link EventListener} instances
+ * as a result of inspecting a subscriber object, mostly likely a
+ * {@link org.apache.shiro.event.Subscribe Subscribe}-annotated object instance.
+ * <p/>
+ * This interface exists primarily as a support concept for the {@link DefaultEventBus} implementation.  Custom
+ * implementations of this interface can be configured on a {@link DefaultEventBus} instance to determine exactly
+ * how a subscriber receives events.
+ * <p/>
+ * For example, the {@link AnnotationEventListenerResolver AnnotationEventListenerResolver} will inspect a runtime
+ * object for {@link org.apache.shiro.event.Subscribe Subscribe}-annotated methods, and for each method found, return
+ * an {@link EventListener} instance representing the method to invoke.
+ *
+ * @see AnnotationEventListenerResolver
+ * @see SingleArgumentMethodEventListener
+ * @since 1.3
+ */
+public interface EventListenerResolver {
+
+    /**
+     * Returns {@link EventListener} instances as a result of inspecting a subscriber object, mostly likely with
+     * {@link org.apache.shiro.event.Subscribe Subscribe}-annotated methods.
+     *
+     * @param instance the subscriber instance for which EventListener instances should be acquired.
+     * @return {@link EventListener} instances as a result of inspecting a subscriber object.
+     */
+    List<EventListener> getEventListeners(Object instance);
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/support/SingleArgumentMethodEventListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/support/SingleArgumentMethodEventListener.java b/core/src/main/java/org/apache/shiro/event/support/SingleArgumentMethodEventListener.java
new file mode 100644
index 0000000..f30c11a
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/event/support/SingleArgumentMethodEventListener.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.event.support;
+
+import java.lang.reflect.Method;
+
+/**
+ * A event listener that invokes a target object's method that accepts a single event argument.
+ *
+ * @since 1.3
+ */
+public class SingleArgumentMethodEventListener implements TypedEventListener {
+
+    private final Object target;
+    private final Method method;
+
+    public SingleArgumentMethodEventListener(Object target, Method method) {
+        this.target = target;
+        this.method = method;
+        //assert that the method is defined as expected:
+        getMethodArgumentType(method);
+    }
+
+    public Object getTarget() {
+        return this.target;
+    }
+
+    public Method getMethod() {
+        return this.method;
+    }
+
+    public boolean accepts(Object event) {
+        return event != null && getEventType().isInstance(event);
+    }
+
+    public Class getEventType() {
+        return getMethodArgumentType(getMethod());
+    }
+
+    public void onEvent(Object event) {
+        Method method = getMethod();
+        try {
+            method.invoke(getTarget(), event);
+        } catch (Exception e) {
+            throw new IllegalStateException("Unable to invoke event handler method [" + method + "]", e);
+        }
+    }
+
+    protected Class getMethodArgumentType(Method method) {
+        Class[] paramTypes = method.getParameterTypes();
+        if (paramTypes.length != 1) {
+            //the default implementation expects a single typed argument and nothing more:
+            String msg = "Event handler methods must accept a single argument.";
+            throw new IllegalArgumentException(msg);
+        }
+        return paramTypes[0];
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/main/java/org/apache/shiro/event/support/TypedEventListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/event/support/TypedEventListener.java b/core/src/main/java/org/apache/shiro/event/support/TypedEventListener.java
new file mode 100644
index 0000000..f266bf3
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/event/support/TypedEventListener.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.event.support;
+
+/**
+ * @since 1.3
+ */
+public interface TypedEventListener extends EventListener {
+
+    Class getEventType();
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/test/groovy/org/apache/shiro/event/bus/AnnotationEventListenerResolverTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/groovy/org/apache/shiro/event/bus/AnnotationEventListenerResolverTest.groovy b/core/src/test/groovy/org/apache/shiro/event/bus/AnnotationEventListenerResolverTest.groovy
deleted file mode 100644
index de32bca..0000000
--- a/core/src/test/groovy/org/apache/shiro/event/bus/AnnotationEventListenerResolverTest.groovy
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus
-
-/**
- * @since 1.3
- */
-class AnnotationEventListenerResolverTest extends GroovyTestCase {
-
-    void testSetGetAnnotationClass() {
-        def resolver = new AnnotationEventListenerResolver();
-        resolver.setAnnotationClass(Override.class) //any old annotation will do for the test
-        assertSame Override.class, resolver.getAnnotationClass()
-    }
-
-    void testNullInstanceArgument() {
-        def resolver = new AnnotationEventListenerResolver()
-        def collection = resolver.getEventListeners(null)
-        assertNotNull collection
-        assertTrue collection.isEmpty()
-    }
-
-    void testNoAnnotationsArgument() {
-        def resolver = new AnnotationEventListenerResolver()
-        def collection = resolver.getEventListeners(new NotAnnotatedSubscriber())
-        assertNotNull collection
-        assertTrue collection.isEmpty()
-    }
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/test/groovy/org/apache/shiro/event/bus/BarEvent.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/groovy/org/apache/shiro/event/bus/BarEvent.groovy b/core/src/test/groovy/org/apache/shiro/event/bus/BarEvent.groovy
deleted file mode 100644
index 7123bec..0000000
--- a/core/src/test/groovy/org/apache/shiro/event/bus/BarEvent.groovy
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus
-
-/**
- * @since 1.3
- */
-class BarEvent extends FooEvent {
-
-    BarEvent(Object o) {
-        super(o)
-    }
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/test/groovy/org/apache/shiro/event/bus/BazEvent.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/groovy/org/apache/shiro/event/bus/BazEvent.groovy b/core/src/test/groovy/org/apache/shiro/event/bus/BazEvent.groovy
deleted file mode 100644
index 60a90ca..0000000
--- a/core/src/test/groovy/org/apache/shiro/event/bus/BazEvent.groovy
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus
-
-/**
- * @since 1.3
- */
-class BazEvent extends BarEvent {
-
-    BazEvent(Object o) {
-        super(o)
-    }
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/test/groovy/org/apache/shiro/event/bus/ClassComparatorTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/groovy/org/apache/shiro/event/bus/ClassComparatorTest.groovy b/core/src/test/groovy/org/apache/shiro/event/bus/ClassComparatorTest.groovy
deleted file mode 100644
index 6302d98..0000000
--- a/core/src/test/groovy/org/apache/shiro/event/bus/ClassComparatorTest.groovy
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus
-
-/**
- * @since 1.3
- */
-class ClassComparatorTest extends GroovyTestCase {
-
-    ClassComparator comparator
-
-    @Override
-    protected void setUp() {
-        comparator = new ClassComparator()
-    }
-
-    void testANull() {
-        def result = comparator.compare(null, Object)
-        assertEquals(-1, result)
-    }
-
-    void testBNull() {
-        def result = comparator.compare(Object, null)
-        assertEquals 1, result
-    }
-
-    void testBothNull() {
-        assertEquals 0, comparator.compare(null, null)
-    }
-
-    void testBothSame() {
-        assertEquals 0, comparator.compare(Object, Object)
-    }
-
-    void testAParentOfB() {
-        assertEquals 1, comparator.compare(Number, Integer)
-    }
-
-    void testBParentOfA() {
-        assertEquals(-1, comparator.compare(Integer, Number))
-    }
-
-    void testUnrelated() {
-        assertEquals(0, comparator.compare(Integer, Boolean))
-    }
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/test/groovy/org/apache/shiro/event/bus/DefaultEventBusTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/groovy/org/apache/shiro/event/bus/DefaultEventBusTest.groovy b/core/src/test/groovy/org/apache/shiro/event/bus/DefaultEventBusTest.groovy
deleted file mode 100644
index c29b69d..0000000
--- a/core/src/test/groovy/org/apache/shiro/event/bus/DefaultEventBusTest.groovy
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus
-
-import static org.easymock.EasyMock.*
-
-/**
- * @since 1.3
- */
-class DefaultEventBusTest extends GroovyTestCase {
-
-    DefaultEventBus bus;
-
-    @Override
-    protected void setUp() {
-        bus = new DefaultEventBus()
-    }
-
-    void testSetEventListenerResolver() {
-        def resolver = new EventListenerResolver() {
-            List<EventListener> getEventListeners(Object instance) {
-                return null //dummy implementation
-            }
-        }
-        bus.setEventListenerResolver(resolver)
-        assertSame resolver, bus.getEventListenerResolver()
-    }
-
-    void testSimpleSubscribe() {
-        def subscriber = new TestSubscriber();
-
-        bus.register(subscriber);
-
-        def event = new FooEvent(this)
-
-        bus.publish(event)
-
-        assertEquals 1, subscriber.fooCount
-        assertEquals 1, subscriber.count
-        assertSame event, subscriber.lastEvent
-    }
-
-    void testPublishNullEvent() {
-        def subscriber = new TestSubscriber();
-        bus.register(subscriber)
-
-        bus.publish(null)
-
-        assertEquals 0, subscriber.count
-    }
-
-    void testSubscribeNullInstance() {
-        def resolver = createStrictMock(EventListenerResolver)  //assert no methods are called on this
-        bus.eventListenerResolver = resolver
-
-        replay(resolver)
-
-        bus.register(null)
-
-        verify(resolver)
-    }
-
-    void testSubscribeWithoutAnnotations() {
-        def subscriber = new NotAnnotatedSubscriber()
-        bus.register(subscriber)
-
-        bus.publish(new FooEvent(this))
-
-        assertEquals 0, bus.registry.size()
-    }
-
-    void testUnsubscribeNullInstance() {
-        bus.unregister(null)
-    }
-
-    void testUnsubscribe() {
-        def subscriber = new TestSubscriber()
-        bus.register(subscriber)
-        assertEquals 1, bus.registry.size()
-
-        def event = new FooEvent(this)
-
-        bus.publish(event)
-
-        assertSame event, subscriber.lastEvent
-        assertEquals 1, subscriber.fooCount
-        assertEquals 1, subscriber.count
-
-        bus.unregister(subscriber)
-
-        assertEquals 0, bus.registry.size()
-    }
-
-    void testPolymorphicSubscribeMethodsOnlyOneInvoked() {
-        def subscriber = new TestSubscriber()
-        bus.register(subscriber)
-
-        def event = new BarEvent(this)
-
-        bus.publish(event)
-
-        assertSame event, subscriber.lastEvent
-        assertEquals 0, subscriber.fooCount
-        assertEquals 1, subscriber.barCount
-        assertEquals 1, subscriber.count
-    }
-
-    void testPolymorphicSubscribeMethodsOnlyOneInvokedWithListenerSubclass() {
-        def subscriber = new SubclassTestSubscriber()
-        bus.register(subscriber)
-
-        def event = new BazEvent(this)
-
-        bus.publish(event)
-
-        assertSame event, subscriber.lastEvent
-        assertEquals 1, subscriber.count
-        assertEquals 1, subscriber.bazCount
-        assertEquals 0, subscriber.fooCount
-        assertEquals 0, subscriber.barCount
-    }
-
-    void testSubscribeWithErroneousAnnotation() {
-        def subscriber = new ErroneouslyAnnotatedSubscriber()
-        //noinspection GroovyUnusedCatchParameter
-        try {
-            bus.register(subscriber)
-            fail("exception expected")
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-
-    void testContinueThroughListenerExceptions() {
-        def ok = new SimpleSubscriber()
-        def error = new ExceptionThrowingSubscriber()
-
-        bus.register(ok)
-        bus.register(error)
-
-        bus.publish(new ErrorCausingEvent())
-        bus.publish(new SimpleEvent())
-
-        assertEquals 1, ok.count
-        assertEquals 0, error.count
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/test/groovy/org/apache/shiro/event/bus/ErroneouslyAnnotatedSubscriber.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/groovy/org/apache/shiro/event/bus/ErroneouslyAnnotatedSubscriber.groovy b/core/src/test/groovy/org/apache/shiro/event/bus/ErroneouslyAnnotatedSubscriber.groovy
deleted file mode 100644
index 82546a6..0000000
--- a/core/src/test/groovy/org/apache/shiro/event/bus/ErroneouslyAnnotatedSubscriber.groovy
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus
-
-import org.apache.shiro.event.Subscribe
-
-/**
- * @since 1.3
- */
-class ErroneouslyAnnotatedSubscriber {
-
-    @Subscribe
-    void onEvent(FooEvent event, Object someOtherArg) {
-    }
-}

http://git-wip-us.apache.org/repos/asf/shiro/blob/bdecc0ba/core/src/test/groovy/org/apache/shiro/event/bus/ErrorCausingEvent.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/groovy/org/apache/shiro/event/bus/ErrorCausingEvent.groovy b/core/src/test/groovy/org/apache/shiro/event/bus/ErrorCausingEvent.groovy
deleted file mode 100644
index 897399f..0000000
--- a/core/src/test/groovy/org/apache/shiro/event/bus/ErrorCausingEvent.groovy
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.event.bus
-
-/**
- * @since 1.3
- */
-class ErrorCausingEvent {
-}