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>
- * @Subscribe
- * public void onEvent(A a) { ... }
- *
- * @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>
+ * @Subscribe
+ * public void onEvent(A a) { ... }
+ *
+ * @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 {
-}