Merge pull request #1 from bennidi/master

better support of interfaces in message publication
This commit is contained in:
durron597 2013-05-21 09:28:04 -07:00
commit eceba9ef09
10 changed files with 107 additions and 41 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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() {

View File

@ -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) {

View File

@ -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) {

View File

@ -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);
}

View File

@ -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;

View File

@ -22,7 +22,8 @@ import org.junit.runners.Suite;
ListenerSubscriptionTest.class,
MethodDispatchTest.class,
DeadEventTest.class,
SynchronizedHandlerTest.class
SynchronizedHandlerTest.class,
SubscriptionManagerTest.class
})
public class AllTests {
}

View File

@ -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)

View File

@ -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<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) {
}
}
}