From 7c08bd02993694b115474f63ba0b3f91f0beeaab Mon Sep 17 00:00:00 2001 From: benjamin Date: Tue, 21 May 2013 18:13:27 +0200 Subject: [PATCH] better support of interfaces in message publication --- .../engio/mbassy/bus/MessagePublication.java | 2 +- .../engio/mbassy/common/ReflectionUtils.java | 2 +- .../listener/MessageHandlerMetadata.java | 12 +++- .../listener/MessageListenerMetadata.java | 31 ++++++++- .../engio/mbassy/listener/MetadataReader.java | 18 ++--- .../mbassy/subscription/Subscription.java | 4 ++ .../subscription/SubscriptionManager.java | 2 +- src/test/java/net/engio/mbassy/AllTests.java | 3 +- .../net/engio/mbassy/MetadataReaderTest.java | 10 +-- .../engio/mbassy/SubscriptionManagerTest.java | 65 +++++++++++++++---- .../java/net/engio/mbassy/SyncBusTest.java | 4 +- 11 files changed, 109 insertions(+), 44 deletions(-) diff --git a/src/main/java/net/engio/mbassy/bus/MessagePublication.java b/src/main/java/net/engio/mbassy/bus/MessagePublication.java index f0d8318..d120c29 100644 --- a/src/main/java/net/engio/mbassy/bus/MessagePublication.java +++ b/src/main/java/net/engio/mbassy/bus/MessagePublication.java @@ -37,7 +37,7 @@ public class MessagePublication { private ISyncMessageBus bus; - public MessagePublication(ISyncMessageBus bus, Collection subscriptions, Object message, State initialState) { + protected MessagePublication(ISyncMessageBus bus, Collection subscriptions, Object message, State initialState) { this.bus = bus; this.subscriptions = subscriptions; this.message = message; diff --git a/src/main/java/net/engio/mbassy/common/ReflectionUtils.java b/src/main/java/net/engio/mbassy/common/ReflectionUtils.java index 2c41827..f7a66cc 100644 --- a/src/main/java/net/engio/mbassy/common/ReflectionUtils.java +++ b/src/main/java/net/engio/mbassy/common/ReflectionUtils.java @@ -64,9 +64,9 @@ public class ReflectionUtils { Collection superclasses = new LinkedList(); while (!from.equals(Object.class) && !from.isInterface()) { superclasses.add(from.getSuperclass()); + collectInterfaces(from, superclasses); from = from.getSuperclass(); } - collectInterfaces(from, superclasses); return superclasses; } diff --git a/src/main/java/net/engio/mbassy/listener/MessageHandlerMetadata.java b/src/main/java/net/engio/mbassy/listener/MessageHandlerMetadata.java index 365df73..673e16b 100644 --- a/src/main/java/net/engio/mbassy/listener/MessageHandlerMetadata.java +++ b/src/main/java/net/engio/mbassy/listener/MessageHandlerMetadata.java @@ -26,12 +26,14 @@ public class MessageHandlerMetadata { private final boolean acceptsSubtypes; - private final Listener listenerConfig; + private final MessageListenerMetadata listenerConfig; private final boolean isSynchronized; + private Class listeningClass; - public MessageHandlerMetadata(Method handler, IMessageFilter[] filter, Handler handlerConfig, Listener listenerConfig) { + + public MessageHandlerMetadata(Method handler, IMessageFilter[] filter, Handler handlerConfig, MessageListenerMetadata listenerConfig) { if(handler == null || handlerConfig == null){ throw new IllegalArgumentException("The message handler configuration may not be null"); } @@ -58,7 +60,11 @@ public class MessageHandlerMetadata { } public boolean useStrongReferences(){ - return listenerConfig != null && listenerConfig.references().equals(References.Strong); + return listenerConfig.useStrongReferences(); + } + + public boolean isFromListener(Object listener){ + return listenerConfig.isFromListener(listener); } public boolean isAsynchronous() { diff --git a/src/main/java/net/engio/mbassy/listener/MessageListenerMetadata.java b/src/main/java/net/engio/mbassy/listener/MessageListenerMetadata.java index bb026a7..65c6f79 100644 --- a/src/main/java/net/engio/mbassy/listener/MessageListenerMetadata.java +++ b/src/main/java/net/engio/mbassy/listener/MessageListenerMetadata.java @@ -2,6 +2,8 @@ package net.engio.mbassy.listener; import net.engio.mbassy.common.IPredicate; +import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -24,16 +26,39 @@ public class MessageListenerMetadata { }; } - private List handlers; + private List handlers = new ArrayList(); private Class listenerDefinition; - public MessageListenerMetadata(List handlers, Class listenerDefinition) { - this.handlers = handlers; + private Listener listenerAnnotation; + + public MessageListenerMetadata(Class listenerDefinition) { this.listenerDefinition = listenerDefinition; + Listener listenerAnnotation = listenerDefinition.getAnnotation(Listener.class); } + public boolean isFromListener(Object listener){ + return listenerDefinition.equals(listener.getClass()); + } + + public boolean useStrongReferences(){ + return listenerAnnotation != null && listenerAnnotation.references().equals(References.Strong); + } + + public MessageListenerMetadata addHandlers(Collection c) { + handlers.addAll(c); + return this; + } + + public boolean addHandler(MessageHandlerMetadata messageHandlerMetadata) { + return handlers.add(messageHandlerMetadata); + } + + public List getHandlers(){ + return handlers; + } + public List getHandlers(IPredicate filter) { List matching = new LinkedList(); for (MessageHandlerMetadata handler : handlers) { diff --git a/src/main/java/net/engio/mbassy/listener/MetadataReader.java b/src/main/java/net/engio/mbassy/listener/MetadataReader.java index 814ad65..3a016ec 100644 --- a/src/main/java/net/engio/mbassy/listener/MetadataReader.java +++ b/src/main/java/net/engio/mbassy/listener/MetadataReader.java @@ -45,7 +45,6 @@ public class MetadataReader { } catch (Exception e) { throw new RuntimeException(e);// propagate as runtime exception } - } filters[i] = filter; i++; @@ -54,13 +53,10 @@ public class MetadataReader { } - - // get all listeners defined by the given class (includes // listeners defined in super classes) - public List getMessageHandlers(Object listener) { - Class target = listener.getClass(); - Listener listenerConfig = target.getAnnotation(Listener.class); + public MessageListenerMetadata getMessageListener(Class target) { + MessageListenerMetadata listenerMetadata = new MessageListenerMetadata(target); // get all handlers (this will include all (inherited) methods directly annotated using @Handler) List allHandlers = ReflectionUtils.getMethods(AllMessageHandlers, target); // retain only those that are at the bottom of their respective class hierarchy (deepest overriding method) @@ -71,7 +67,6 @@ public class MetadataReader { } } - List filteredHandlers = new LinkedList(); // for each handler there will be no overriding method that specifies @Handler annotation // but an overriding method does inherit the listener configuration of the overwritten method for (Method handler : bottomMostHandlers) { @@ -82,17 +77,14 @@ public class MetadataReader { Method overriddenHandler = ReflectionUtils.getOverridingMethod(handler, target); // if a handler is overwritten it inherits the configuration of its parent method MessageHandlerMetadata handlerMetadata = new MessageHandlerMetadata(overriddenHandler == null ? handler : overriddenHandler, - getFilter(handlerConfig), handlerConfig, listenerConfig); - filteredHandlers.add(handlerMetadata); + getFilter(handlerConfig), handlerConfig, listenerMetadata); + listenerMetadata.addHandler(handlerMetadata); } - return filteredHandlers; + return listenerMetadata; } - public MessageListenerMetadata getMessageListener(Object listener) { - return new MessageListenerMetadata(getMessageHandlers(listener), listener.getClass()); - } private boolean isValidMessageHandler(Method handler) { diff --git a/src/main/java/net/engio/mbassy/subscription/Subscription.java b/src/main/java/net/engio/mbassy/subscription/Subscription.java index 3d656a6..9fc53c8 100644 --- a/src/main/java/net/engio/mbassy/subscription/Subscription.java +++ b/src/main/java/net/engio/mbassy/subscription/Subscription.java @@ -27,6 +27,10 @@ public class Subscription { this.listeners = listeners; } + public boolean isFromListener(Object listener){ + return context.getHandlerMetadata().isFromListener(listener); + } + public boolean contains(Object listener){ return listeners.contains(listener); } diff --git a/src/main/java/net/engio/mbassy/subscription/SubscriptionManager.java b/src/main/java/net/engio/mbassy/subscription/SubscriptionManager.java index dc302f7..b5278d2 100644 --- a/src/main/java/net/engio/mbassy/subscription/SubscriptionManager.java +++ b/src/main/java/net/engio/mbassy/subscription/SubscriptionManager.java @@ -82,7 +82,7 @@ public class SubscriptionManager { Collection subscriptionsByListener = getSubscriptionsByListener(listener); // a listener is either subscribed for the first time if (subscriptionsByListener == null) { - List messageHandlers = metadataReader.getMessageHandlers(listener); + List messageHandlers = metadataReader.getMessageListener(listener.getClass()).getHandlers(); if (messageHandlers.isEmpty()) { // remember the class as non listening class if no handlers are found nonListeners.add(listener.getClass()); return; diff --git a/src/test/java/net/engio/mbassy/AllTests.java b/src/test/java/net/engio/mbassy/AllTests.java index fe842ea..f517f9f 100644 --- a/src/test/java/net/engio/mbassy/AllTests.java +++ b/src/test/java/net/engio/mbassy/AllTests.java @@ -22,7 +22,8 @@ import org.junit.runners.Suite; ListenerSubscriptionTest.class, MethodDispatchTest.class, DeadEventTest.class, - SynchronizedHandlerTest.class + SynchronizedHandlerTest.class, + SubscriptionManagerTest.class }) public class AllTests { } diff --git a/src/test/java/net/engio/mbassy/MetadataReaderTest.java b/src/test/java/net/engio/mbassy/MetadataReaderTest.java index 8507c3d..88d7f76 100644 --- a/src/test/java/net/engio/mbassy/MetadataReaderTest.java +++ b/src/test/java/net/engio/mbassy/MetadataReaderTest.java @@ -27,7 +27,7 @@ public class MetadataReaderTest extends UnitTest { @Test public void testListenerWithoutInheritance() { - MessageListenerMetadata listener = reader.getMessageListener(new MessageListener1()); + MessageListenerMetadata listener = reader.getMessageListener(MessageListener1.class); ListenerValidator validator = new ListenerValidator() .expectHandlers(2, String.class) .expectHandlers(2, Object.class) @@ -38,7 +38,7 @@ public class MetadataReaderTest extends UnitTest { @Test public void testListenerWithInheritance() { - MessageListenerMetadata listener = reader.getMessageListener(new MessageListener2()); + MessageListenerMetadata listener = reader.getMessageListener(MessageListener2.class); ListenerValidator validator = new ListenerValidator() .expectHandlers(2, String.class) .expectHandlers(2, Object.class) @@ -48,7 +48,7 @@ public class MetadataReaderTest extends UnitTest { @Test public void testListenerWithInheritanceOverriding() { - MessageListenerMetadata listener = reader.getMessageListener(new MessageListener3()); + MessageListenerMetadata listener = reader.getMessageListener(MessageListener3.class); ListenerValidator validator = new ListenerValidator() .expectHandlers(0, String.class) @@ -59,7 +59,7 @@ public class MetadataReaderTest extends UnitTest { @Test public void testEnveloped() { - MessageListenerMetadata listener = reader.getMessageListener(new EnvelopedListener()); + MessageListenerMetadata listener = reader.getMessageListener(EnvelopedListener.class); ListenerValidator validator = new ListenerValidator() .expectHandlers(1, String.class) .expectHandlers(2, Integer.class) @@ -72,7 +72,7 @@ public class MetadataReaderTest extends UnitTest { @Test public void testEnvelopedSubclass() { - MessageListenerMetadata listener = reader.getMessageListener(new EnvelopedListenerSubclass()); + MessageListenerMetadata listener = reader.getMessageListener(EnvelopedListenerSubclass.class); ListenerValidator validator = new ListenerValidator() .expectHandlers(1, String.class) .expectHandlers(2, Integer.class) diff --git a/src/test/java/net/engio/mbassy/SubscriptionManagerTest.java b/src/test/java/net/engio/mbassy/SubscriptionManagerTest.java index 98437e6..296cf84 100644 --- a/src/test/java/net/engio/mbassy/SubscriptionManagerTest.java +++ b/src/test/java/net/engio/mbassy/SubscriptionManagerTest.java @@ -1,5 +1,6 @@ package net.engio.mbassy; +import net.engio.mbassy.common.ConcurrentExecutor; import net.engio.mbassy.common.UnitTest; import net.engio.mbassy.listener.Handler; import net.engio.mbassy.listener.MetadataReader; @@ -11,6 +12,10 @@ import net.engio.mbassy.subscription.SubscriptionManager; import org.junit.Test; import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * Todo: Add javadoc @@ -22,27 +27,47 @@ public class SubscriptionManagerTest extends UnitTest{ @Test public void testSimpleSynchronousHandler(){ - SubscriptionManager subMan = new SubscriptionManager(new MetadataReader(), new SubscriptionFactory()); - SimpleSynchronousMessageHandler - listener1 = new SimpleSynchronousMessageHandler(), - listener2 = new SimpleSynchronousMessageHandler(); - subMan.subscribe(listener1); - subMan.subscribe(listener2); + final SubscriptionManager subMan = new SubscriptionManager(new MetadataReader(), new SubscriptionFactory()); + final Set listeners = Collections.synchronizedSet(new HashSet()); + final int concurrentUnits = 5; + final int numberOfLoops = 100; + final int numberOfListeners = numberOfLoops * concurrentUnits * 2; + + ConcurrentExecutor.runConcurrent(new Runnable() { + @Override + public void run() { + for(int i = 0 ; i < numberOfLoops ; i++){ + SimpleSynchronousMessageHandler + listener1 = new SimpleSynchronousMessageHandler(); + SimpleSynchronousMessageHandler2 listener2 = new SimpleSynchronousMessageHandler2(); + subMan.subscribe(listener1); + subMan.subscribe(listener2); + listeners.add(listener1); + listeners.add(listener2); + } + + } + }, concurrentUnits); + Collection subscriptions = subMan.getSubscriptionsByMessageType(TestMessage.class); - assertEquals(1, subscriptions.size()); + assertEquals(2, subscriptions.size()); + for(Subscription sub : subscriptions){ - assertEquals(2, sub.size()); - assertTrue(sub.contains(listener1)); - assertTrue(sub.contains(listener2)); + assertEquals(numberOfListeners, sub.size()); + for(Object listener : listeners){ + + if(sub.isFromListener(listener))assertTrue(sub.contains(listener)); + } } subscriptions = subMan.getSubscriptionsByMessageType(ITestMessage.class); - assertEquals(1, subscriptions.size()); + assertEquals(2, subscriptions.size()); for(Subscription sub : subscriptions){ - assertEquals(2, sub.size()); - assertTrue(sub.contains(listener1)); - assertTrue(sub.contains(listener2)); + assertEquals(numberOfListeners, sub.size()); + for(Object listener : listeners){ + if(sub.isFromListener(listener))assertTrue(sub.contains(listener)); + } } } @@ -57,4 +82,16 @@ public class SubscriptionManagerTest extends UnitTest{ public void handle(ITestMessage message) { } } + + + static class SimpleSynchronousMessageHandler2{ + + @Handler + public void handle(TestMessage message) { + } + + @Handler + public void handle(ITestMessage message) { + } + } } diff --git a/src/test/java/net/engio/mbassy/SyncBusTest.java b/src/test/java/net/engio/mbassy/SyncBusTest.java index 0147965..f99056d 100644 --- a/src/test/java/net/engio/mbassy/SyncBusTest.java +++ b/src/test/java/net/engio/mbassy/SyncBusTest.java @@ -4,8 +4,8 @@ import net.engio.mbassy.bus.*; import net.engio.mbassy.common.MessageBusTest; import net.engio.mbassy.common.TestUtil; import net.engio.mbassy.dispatch.HandlerInvocation; -import net.engio.mbassy.events.SubTestMessage; -import net.engio.mbassy.events.TestMessage; +import net.engio.mbassy.messages.SubTestMessage; +import net.engio.mbassy.messages.TestMessage; import net.engio.mbassy.listener.*; import net.engio.mbassy.listeners.*; import net.engio.mbassy.subscription.SubscriptionContext;