Merge pull request #1 from bennidi/master
better support of interfaces in message publication
This commit is contained in:
commit
eceba9ef09
@ -37,7 +37,7 @@ public class MessagePublication {
|
||||
|
||||
private ISyncMessageBus bus;
|
||||
|
||||
public MessagePublication(ISyncMessageBus bus, Collection<Subscription> subscriptions, Object message, State initialState) {
|
||||
protected MessagePublication(ISyncMessageBus bus, Collection<Subscription> subscriptions, Object message, State initialState) {
|
||||
this.bus = bus;
|
||||
this.subscriptions = subscriptions;
|
||||
this.message = message;
|
||||
|
@ -66,6 +66,7 @@ public class ReflectionUtils {
|
||||
collectInterfaces(from, superclasses);
|
||||
while (!from.equals(Object.class) && !from.isInterface()) {
|
||||
superclasses.add(from.getSuperclass());
|
||||
collectInterfaces(from, superclasses);
|
||||
from = from.getSuperclass();
|
||||
}
|
||||
return superclasses;
|
||||
|
@ -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() {
|
||||
|
@ -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<T> {
|
||||
};
|
||||
}
|
||||
|
||||
private List<MessageHandlerMetadata> handlers;
|
||||
private List<MessageHandlerMetadata> handlers = new ArrayList<MessageHandlerMetadata>();
|
||||
|
||||
private Class<T> listenerDefinition;
|
||||
|
||||
public MessageListenerMetadata(List<MessageHandlerMetadata> handlers, Class<T> listenerDefinition) {
|
||||
this.handlers = handlers;
|
||||
private Listener listenerAnnotation;
|
||||
|
||||
public MessageListenerMetadata(Class<T> 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<? extends MessageHandlerMetadata> c) {
|
||||
handlers.addAll(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean addHandler(MessageHandlerMetadata messageHandlerMetadata) {
|
||||
return handlers.add(messageHandlerMetadata);
|
||||
}
|
||||
|
||||
public List<MessageHandlerMetadata> getHandlers(){
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public List<MessageHandlerMetadata> getHandlers(IPredicate<MessageHandlerMetadata> filter) {
|
||||
List<MessageHandlerMetadata> matching = new LinkedList<MessageHandlerMetadata>();
|
||||
for (MessageHandlerMetadata handler : handlers) {
|
||||
|
@ -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<MessageHandlerMetadata> 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<Method> 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<MessageHandlerMetadata> filteredHandlers = new LinkedList<MessageHandlerMetadata>();
|
||||
// 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 <T> MessageListenerMetadata<T> getMessageListener(Object listener) {
|
||||
return new MessageListenerMetadata(getMessageHandlers(listener), listener.getClass());
|
||||
}
|
||||
|
||||
|
||||
private boolean isValidMessageHandler(Method handler) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ public class SubscriptionManager {
|
||||
Collection<Subscription> subscriptionsByListener = getSubscriptionsByListener(listener);
|
||||
// a listener is either subscribed for the first time
|
||||
if (subscriptionsByListener == null) {
|
||||
List<MessageHandlerMetadata> messageHandlers = metadataReader.getMessageHandlers(listener);
|
||||
List<MessageHandlerMetadata> 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;
|
||||
|
@ -22,7 +22,8 @@ import org.junit.runners.Suite;
|
||||
ListenerSubscriptionTest.class,
|
||||
MethodDispatchTest.class,
|
||||
DeadEventTest.class,
|
||||
SynchronizedHandlerTest.class
|
||||
SynchronizedHandlerTest.class,
|
||||
SubscriptionManagerTest.class
|
||||
})
|
||||
public class AllTests {
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public class MetadataReaderTest extends UnitTest {
|
||||
|
||||
@Test
|
||||
public void testListenerWithoutInheritance() {
|
||||
MessageListenerMetadata<MessageListener1> listener = reader.getMessageListener(new MessageListener1());
|
||||
MessageListenerMetadata<MessageListener1> 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<MessageListener2> listener = reader.getMessageListener(new MessageListener2());
|
||||
MessageListenerMetadata<MessageListener2> 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<MessageListener3> listener = reader.getMessageListener(new MessageListener3());
|
||||
MessageListenerMetadata<MessageListener3> 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<EnvelopedListener> listener = reader.getMessageListener(new EnvelopedListener());
|
||||
MessageListenerMetadata<EnvelopedListener> 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<EnvelopedListenerSubclass> listener = reader.getMessageListener(new EnvelopedListenerSubclass());
|
||||
MessageListenerMetadata<EnvelopedListenerSubclass> listener = reader.getMessageListener(EnvelopedListenerSubclass.class);
|
||||
ListenerValidator validator = new ListenerValidator()
|
||||
.expectHandlers(1, String.class)
|
||||
.expectHandlers(2, Integer.class)
|
||||
|
@ -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());
|
||||
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(),
|
||||
listener2 = new SimpleSynchronousMessageHandler();
|
||||
listener1 = new SimpleSynchronousMessageHandler();
|
||||
SimpleSynchronousMessageHandler2 listener2 = new SimpleSynchronousMessageHandler2();
|
||||
subMan.subscribe(listener1);
|
||||
subMan.subscribe(listener2);
|
||||
listeners.add(listener1);
|
||||
listeners.add(listener2);
|
||||
}
|
||||
|
||||
}
|
||||
}, concurrentUnits);
|
||||
|
||||
|
||||
Collection<Subscription> 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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user