Simplifying/pruning mbassador functionality and complexity
This commit is contained in:
parent
f509bfe57f
commit
d17183d592
@ -34,7 +34,5 @@ public interface IMessagePublication {
|
|||||||
|
|
||||||
public boolean isDeadEvent();
|
public boolean isDeadEvent();
|
||||||
|
|
||||||
public boolean isFilteredEvent();
|
|
||||||
|
|
||||||
public Object getMessage();
|
public Object getMessage();
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
package net.engio.mbassy.bus;
|
package net.engio.mbassy.bus;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.common.DeadMessage;
|
|
||||||
import net.engio.mbassy.bus.common.FilteredMessage;
|
|
||||||
import net.engio.mbassy.subscription.Subscription;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import net.engio.mbassy.bus.common.DeadMessage;
|
||||||
|
import net.engio.mbassy.subscription.Subscription;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message publication is created for each asynchronous message dispatch. It reflects the state
|
* A message publication is created for each asynchronous message dispatch. It reflects the state
|
||||||
* of the corresponding message publication process, i.e. provides information whether the
|
* of the corresponding message publication process, i.e. provides information whether the
|
||||||
@ -33,64 +32,66 @@ public class MessagePublication implements IMessagePublication {
|
|||||||
this.state = initialState;
|
this.state = initialState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean add(Subscription subscription) {
|
public boolean add(Subscription subscription) {
|
||||||
return subscriptions.add(subscription);
|
return this.subscriptions.add(subscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: document state transitions
|
TODO: document state transitions
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
state = State.Running;
|
this.state = State.Running;
|
||||||
for (Subscription sub : subscriptions) {
|
for (Subscription sub : this.subscriptions) {
|
||||||
sub.publish(this, message);
|
sub.publish(this, this.message);
|
||||||
}
|
}
|
||||||
state = State.Finished;
|
this.state = State.Finished;
|
||||||
// if the message has not been marked delivered by the dispatcher
|
// if the message has not been marked delivered by the dispatcher
|
||||||
if (!delivered) {
|
if (!this.delivered) {
|
||||||
if (!isFilteredEvent() && !isDeadEvent()) {
|
if (!isDeadEvent()) {
|
||||||
runtime.getProvider().publish(new FilteredMessage(message));
|
this.runtime.getProvider().publish(new DeadMessage(this.message));
|
||||||
} else if (!isDeadEvent()) {
|
|
||||||
runtime.getProvider().publish(new DeadMessage(message));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isFinished() {
|
public boolean isFinished() {
|
||||||
return state.equals(State.Finished);
|
return this.state.equals(State.Finished);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return state.equals(State.Running);
|
return this.state.equals(State.Running);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isScheduled() {
|
public boolean isScheduled() {
|
||||||
return state.equals(State.Scheduled);
|
return this.state.equals(State.Scheduled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void markDelivered() {
|
public void markDelivered() {
|
||||||
delivered = true;
|
this.delivered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public MessagePublication markScheduled() {
|
public MessagePublication markScheduled() {
|
||||||
if (state.equals(State.Initial)) {
|
if (this.state.equals(State.Initial)) {
|
||||||
state = State.Scheduled;
|
this.state = State.Scheduled;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isDeadEvent() {
|
public boolean isDeadEvent() {
|
||||||
return DeadMessage.class.equals(message.getClass());
|
return DeadMessage.class.equals(this.message.getClass());
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFilteredEvent() {
|
|
||||||
return FilteredMessage.class.equals(message.getClass());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Object getMessage() {
|
public Object getMessage() {
|
||||||
return message;
|
return this.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum State {
|
private enum State {
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package net.engio.mbassy.bus.common;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A filtered message event is published when there have been matching subscriptions for a given
|
|
||||||
* message publication but configured filters prevented the message from being delivered to
|
|
||||||
* any of the handlers.
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 3/1/13
|
|
||||||
*/
|
|
||||||
public final class FilteredMessage extends PublicationEvent {
|
|
||||||
|
|
||||||
|
|
||||||
public FilteredMessage(Object event) {
|
|
||||||
super(event);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package net.engio.mbassy.common;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created with IntelliJ IDEA.
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 10/22/12
|
|
||||||
* Time: 9:33 AM
|
|
||||||
* To change this template use File | Settings | File Templates.
|
|
||||||
*/
|
|
||||||
public interface IPredicate<T> {
|
|
||||||
|
|
||||||
boolean apply(T target);
|
|
||||||
}
|
|
@ -8,6 +8,8 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import net.engio.mbassy.listener.Handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 2/16/12
|
* Date: 2/16/12
|
||||||
@ -16,20 +18,20 @@ import java.util.Set;
|
|||||||
public class ReflectionUtils
|
public class ReflectionUtils
|
||||||
{
|
{
|
||||||
|
|
||||||
public static List<Method> getMethods( IPredicate<Method> condition, Class<?> target ) {
|
// modified by dorkbox, llc 2015
|
||||||
|
public static List<Method> getMethods(Class<?> target) {
|
||||||
List<Method> methods = new LinkedList<Method>();
|
List<Method> methods = new LinkedList<Method>();
|
||||||
try {
|
try {
|
||||||
for (Method method : target.getDeclaredMethods()) {
|
for (Method method : target.getDeclaredMethods()) {
|
||||||
if ( condition.apply( method ) ) {
|
if (getAnnotation(method, Handler.class) != null) {
|
||||||
methods.add(method);
|
methods.add(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
catch ( Exception e ) {
|
|
||||||
//nop
|
|
||||||
}
|
|
||||||
if (!target.equals(Object.class)) {
|
if (!target.equals(Object.class)) {
|
||||||
methods.addAll( getMethods( condition, target.getSuperclass() ) );
|
methods.addAll(getMethods(target.getSuperclass()));
|
||||||
}
|
}
|
||||||
return methods;
|
return methods;
|
||||||
}
|
}
|
||||||
@ -43,8 +45,8 @@ public class ReflectionUtils
|
|||||||
* @param subclass
|
* @param subclass
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static Method getOverridingMethod( final Method overridingMethod, final Class subclass ) {
|
public static Method getOverridingMethod( final Method overridingMethod, final Class<?> subclass ) {
|
||||||
Class current = subclass;
|
Class<?> current = subclass;
|
||||||
while ( !current.equals( overridingMethod.getDeclaringClass() ) ) {
|
while ( !current.equals( overridingMethod.getDeclaringClass() ) ) {
|
||||||
try {
|
try {
|
||||||
return current.getDeclaredMethod( overridingMethod.getName(), overridingMethod.getParameterTypes() );
|
return current.getDeclaredMethod( overridingMethod.getName(), overridingMethod.getParameterTypes() );
|
||||||
@ -63,8 +65,8 @@ public class ReflectionUtils
|
|||||||
* @param from The root class to start with
|
* @param from The root class to start with
|
||||||
* @return A set of classes, each representing a super type of the root class
|
* @return A set of classes, each representing a super type of the root class
|
||||||
*/
|
*/
|
||||||
public static Set<Class> getSuperTypes(Class from) {
|
public static Set<Class<?>> getSuperTypes(Class<?> from) {
|
||||||
Set<Class> superclasses = new HashSet<Class>();
|
Set<Class<?>> superclasses = new HashSet<Class<?>>();
|
||||||
collectInterfaces( from, superclasses );
|
collectInterfaces( from, superclasses );
|
||||||
while ( !from.equals( Object.class ) && !from.isInterface() ) {
|
while ( !from.equals( Object.class ) && !from.isInterface() ) {
|
||||||
superclasses.add( from.getSuperclass() );
|
superclasses.add( from.getSuperclass() );
|
||||||
@ -74,13 +76,14 @@ public class ReflectionUtils
|
|||||||
return superclasses;
|
return superclasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void collectInterfaces( Class from, Set<Class> accumulator ) {
|
public static void collectInterfaces( Class<?> from, Set<Class<?>> accumulator ) {
|
||||||
for ( Class intface : from.getInterfaces() ) {
|
for ( Class<?> intface : from.getInterfaces() ) {
|
||||||
accumulator.add( intface );
|
accumulator.add( intface );
|
||||||
collectInterfaces( intface, accumulator );
|
collectInterfaces( intface, accumulator );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
public static boolean containsOverridingMethod(final List<Method> allMethods, final Method methodToCheck) {
|
public static boolean containsOverridingMethod(final List<Method> allMethods, final Method methodToCheck) {
|
||||||
for (Method method : allMethods) {
|
for (Method method : allMethods) {
|
||||||
if (isOverriddenBy(methodToCheck, method)) {
|
if (isOverriddenBy(methodToCheck, method)) {
|
||||||
@ -101,10 +104,14 @@ public class ReflectionUtils
|
|||||||
* @return Annotation instance or null
|
* @return Annotation instance or null
|
||||||
*/
|
*/
|
||||||
private static <A extends Annotation> A getAnnotation( AnnotatedElement from, Class<A> annotationType, Set<AnnotatedElement> visited) {
|
private static <A extends Annotation> A getAnnotation( AnnotatedElement from, Class<A> annotationType, Set<AnnotatedElement> visited) {
|
||||||
if( visited.contains(from) ) return null;
|
if( visited.contains(from) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
visited.add(from);
|
visited.add(from);
|
||||||
A ann = from.getAnnotation( annotationType );
|
A ann = from.getAnnotation( annotationType );
|
||||||
if( ann != null) return ann;
|
if( ann != null) {
|
||||||
|
return ann;
|
||||||
|
}
|
||||||
for ( Annotation metaAnn : from.getAnnotations() ) {
|
for ( Annotation metaAnn : from.getAnnotations() ) {
|
||||||
ann = getAnnotation(metaAnn.annotationType(), annotationType, visited);
|
ann = getAnnotation(metaAnn.annotationType(), annotationType, visited);
|
||||||
if ( ann != null ) {
|
if ( ann != null ) {
|
||||||
@ -118,6 +125,7 @@ public class ReflectionUtils
|
|||||||
return getAnnotation(from, annotationType, new HashSet<AnnotatedElement>());
|
return getAnnotation(from, annotationType, new HashSet<AnnotatedElement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
private static boolean isOverriddenBy( Method superclassMethod, Method subclassMethod ) {
|
private static boolean isOverriddenBy( Method superclassMethod, Method subclassMethod ) {
|
||||||
// if the declaring classes are the same or the subclass method is not defined in the subclass
|
// if the declaring classes are the same or the subclass method is not defined in the subclass
|
||||||
// hierarchy of the given superclass method or the method names are not the same then
|
// hierarchy of the given superclass method or the method names are not the same then
|
||||||
@ -128,8 +136,9 @@ public class ReflectionUtils
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Class[] superClassMethodParameters = superclassMethod.getParameterTypes();
|
Class<?>[] superClassMethodParameters = superclassMethod.getParameterTypes();
|
||||||
Class[] subClassMethodParameters = subclassMethod.getParameterTypes();
|
Class<?>[] subClassMethodParameters = subclassMethod.getParameterTypes();
|
||||||
|
|
||||||
// method must specify the same number of parameters
|
// method must specify the same number of parameters
|
||||||
//the parameters must occur in the exact same order
|
//the parameters must occur in the exact same order
|
||||||
for ( int i = 0; i < subClassMethodParameters.length; i++ ) {
|
for ( int i = 0; i < subClassMethodParameters.length; i++ ) {
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
package net.engio.mbassy.common;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation uses strong references to the elements.
|
|
||||||
* <p/>
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 2/12/12
|
|
||||||
*/
|
|
||||||
public class StrongConcurrentSet<T> extends AbstractConcurrentSet<T>{
|
|
||||||
|
|
||||||
|
|
||||||
public StrongConcurrentSet() {
|
|
||||||
super(new HashMap<T, ISetEntry<T>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterator<T> iterator() {
|
|
||||||
return new Iterator<T>() {
|
|
||||||
|
|
||||||
private ISetEntry<T> current = head;
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
return current != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T next() {
|
|
||||||
if (current == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
T value = current.getValue();
|
|
||||||
current = current.next();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
if (current == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ISetEntry<T> newCurrent = current.next();
|
|
||||||
StrongConcurrentSet.this.remove(current.getValue());
|
|
||||||
current = newCurrent;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Entry<T> createEntry(T value, Entry<T> next) {
|
|
||||||
return next != null ? new StrongEntry<T>(value, next) : new StrongEntry<T>(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class StrongEntry<T> extends Entry<T> {
|
|
||||||
|
|
||||||
private T value;
|
|
||||||
|
|
||||||
private StrongEntry(T value, Entry<T> next) {
|
|
||||||
super(next);
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private StrongEntry(T value) {
|
|
||||||
super();
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
|
||||||
|
|
||||||
import net.engio.mbassy.bus.BusRuntime;
|
|
||||||
import net.engio.mbassy.subscription.AbstractSubscriptionContextAware;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This invocation will schedule the wrapped (decorated) invocation to be executed asynchronously
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 11/23/12
|
|
||||||
*/
|
|
||||||
public class AsynchronousHandlerInvocation extends AbstractSubscriptionContextAware implements IHandlerInvocation {
|
|
||||||
|
|
||||||
private final IHandlerInvocation delegate;
|
|
||||||
|
|
||||||
private final ExecutorService executor;
|
|
||||||
|
|
||||||
public AsynchronousHandlerInvocation(IHandlerInvocation delegate) {
|
|
||||||
super(delegate.getContext());
|
|
||||||
this.delegate = delegate;
|
|
||||||
this.executor = delegate.getContext().getRuntime().get(BusRuntime.Properties.AsynchronousHandlerExecutor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void invoke(final Object listener, final Object message){
|
|
||||||
executor.execute(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
delegate.invoke(listener, message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
|
||||||
|
|
||||||
import net.engio.mbassy.bus.IMessagePublication;
|
|
||||||
import net.engio.mbassy.subscription.MessageEnvelope;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The enveloped dispatcher will wrap published messages in an envelope before
|
|
||||||
* passing them to their configured dispatcher.
|
|
||||||
* <p/>
|
|
||||||
* All enveloped message handlers will have this dispatcher in their chain
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 12/12/12
|
|
||||||
*/
|
|
||||||
public class EnvelopedMessageDispatcher extends DelegatingMessageDispatcher {
|
|
||||||
|
|
||||||
|
|
||||||
public EnvelopedMessageDispatcher(IMessageDispatcher dispatcher) {
|
|
||||||
super(dispatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispatch(IMessagePublication publication, Object message, Iterable listeners){
|
|
||||||
getDelegate().dispatch(publication, new MessageEnvelope(message), listeners);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
|
||||||
|
|
||||||
import net.engio.mbassy.bus.IMessagePublication;
|
|
||||||
import net.engio.mbassy.listener.IMessageFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A dispatcher that implements message filtering based on the filter configuration
|
|
||||||
* of the associated message handler. It will delegate message delivery to another
|
|
||||||
* message dispatcher after having performed the filtering logic.
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 11/23/12
|
|
||||||
*/
|
|
||||||
public final class FilteredMessageDispatcher extends DelegatingMessageDispatcher {
|
|
||||||
|
|
||||||
private final IMessageFilter[] filter;
|
|
||||||
|
|
||||||
public FilteredMessageDispatcher(IMessageDispatcher dispatcher) {
|
|
||||||
super(dispatcher);
|
|
||||||
this.filter = dispatcher.getContext().getHandlerMetadata().getFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean passesFilter(Object message) {
|
|
||||||
|
|
||||||
if (filter == null) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
for (IMessageFilter aFilter : filter) {
|
|
||||||
if (!aFilter.accepts(message, getContext().getHandlerMetadata())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispatch(IMessagePublication publication, Object message, Iterable listeners){
|
|
||||||
if (passesFilter(message)) {
|
|
||||||
getDelegate().dispatch(publication, message, listeners);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
package net.engio.mbassy.dispatch.el;
|
|
||||||
|
|
||||||
import net.engio.mbassy.listener.IMessageFilter;
|
|
||||||
import net.engio.mbassy.listener.MessageHandler;
|
|
||||||
|
|
||||||
import javax.el.ExpressionFactory;
|
|
||||||
import javax.el.ValueExpression;
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* A filter that will use a expression from the handler annotation and
|
|
||||||
* parse it as EL.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
public class ElFilter implements IMessageFilter {
|
|
||||||
|
|
||||||
// thread-safe initialization of EL factory singleton
|
|
||||||
public static final class ExpressionFactoryHolder{
|
|
||||||
|
|
||||||
// if runtime exception is thrown, this will
|
|
||||||
public static final ExpressionFactory ELFactory = getELFactory();
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* Get an implementation of the ExpressionFactory. This uses the
|
|
||||||
* Java service lookup mechanism to find a proper implementation.
|
|
||||||
* If none if available we do not support EL filters.
|
|
||||||
************************************************************************/
|
|
||||||
private static final ExpressionFactory getELFactory(){
|
|
||||||
try {
|
|
||||||
return ExpressionFactory.newInstance();
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final boolean isELAvailable(){
|
|
||||||
return ExpressionFactoryHolder.ELFactory != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final ExpressionFactory ELFactory(){
|
|
||||||
return ExpressionFactoryHolder.ELFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts a message if the associated EL expression of the message handler resolves to 'true'
|
|
||||||
*
|
|
||||||
* @param message the message to be handled by the handler
|
|
||||||
* @param metadata the metadata object which describes the message handler
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean accepts(Object message, MessageHandler metadata) {
|
|
||||||
String expression = metadata.getCondition();
|
|
||||||
StandardELResolutionContext context = new StandardELResolutionContext(message);
|
|
||||||
return evalExpression(expression, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean evalExpression(String expression, StandardELResolutionContext context) {
|
|
||||||
ValueExpression ve = ELFactory().createValueExpression(context, expression, Boolean.class);
|
|
||||||
try{
|
|
||||||
Object result = ve.getValue(context);
|
|
||||||
return (Boolean)result;
|
|
||||||
}
|
|
||||||
catch(Throwable exception){
|
|
||||||
// TODO: BusRuntime should be available in this filter to propagate resolution errors
|
|
||||||
// -> this is generally a good feature for filters
|
|
||||||
return false;
|
|
||||||
//throw new IllegalStateException("A handler uses an EL filter but the output is not \"true\" or \"false\".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
package net.engio.mbassy.dispatch.el;
|
|
||||||
|
|
||||||
import javax.el.*;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This ELContext implementation provides support for standard BeanEL resolution in conditional message handlers.
|
|
||||||
* The message parameter of the message handlers is bound to 'msg' such that it can be referenced int the EL expressions.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* @Handler(condition = "msg.type == 'onClick'")
|
|
||||||
* public void handle(ButtonEvent event)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class StandardELResolutionContext extends ELContext {
|
|
||||||
|
|
||||||
private final ELResolver resolver;
|
|
||||||
private final FunctionMapper functionMapper;
|
|
||||||
private final VariableMapper variableMapper;
|
|
||||||
private final Object message;
|
|
||||||
|
|
||||||
|
|
||||||
public StandardELResolutionContext(Object message) {
|
|
||||||
super();
|
|
||||||
this.message = message;
|
|
||||||
this.functionMapper = new NoopFunctionMapper();
|
|
||||||
this.variableMapper = new MsgMapper();
|
|
||||||
// Composite resolver not necessary as the only resolution type currently supported is standard BeanEL
|
|
||||||
//this.resolver = new CompositeELResolver();
|
|
||||||
this.resolver = new BeanELResolver(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* The resolver for the event object.
|
|
||||||
* @see javax.el.ELContext#getELResolver()
|
|
||||||
************************************************************************/
|
|
||||||
@Override
|
|
||||||
public ELResolver getELResolver() {
|
|
||||||
return this.resolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* @see javax.el.ELContext#getFunctionMapper()
|
|
||||||
************************************************************************/
|
|
||||||
@Override
|
|
||||||
public FunctionMapper getFunctionMapper() {
|
|
||||||
return this.functionMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* @see javax.el.ELContext#getVariableMapper()
|
|
||||||
************************************************************************/
|
|
||||||
@Override
|
|
||||||
public VariableMapper getVariableMapper() {
|
|
||||||
return this.variableMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This mapper resolves the variable identifies "msg" to the message
|
|
||||||
* object of the current handler invocation
|
|
||||||
*/
|
|
||||||
private class MsgMapper extends VariableMapper {
|
|
||||||
private static final String msg = "msg";
|
|
||||||
// reuse the same expression as it always resolves to the same object
|
|
||||||
private final ValueExpression msgExpression = ElFilter.ELFactory().createValueExpression(message, message.getClass());
|
|
||||||
|
|
||||||
public ValueExpression resolveVariable(final String s) {
|
|
||||||
// resolve 'msg' to the message object of the handler invocation
|
|
||||||
return !s.equals(msg) ? null : msgExpression;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueExpression setVariable(String s,
|
|
||||||
ValueExpression valueExpression) {
|
|
||||||
// not necessary - the mapper resolves only "msg" and nothing else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function mapper does nothing, i.e. custom EL functions are not
|
|
||||||
* supported by default. It may be supported in the future to pass in
|
|
||||||
* custom function mappers at bus instanciation time.
|
|
||||||
*/
|
|
||||||
private class NoopFunctionMapper extends FunctionMapper {
|
|
||||||
public Method resolveFunction(String s, String s1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package net.engio.mbassy.listener;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Inherited;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure a handler to receive an enveloped message as a wrapper around the source
|
|
||||||
* message. An enveloped message can contain any type of message
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 2/8/12
|
|
||||||
*/
|
|
||||||
@Retention(value = RetentionPolicy.RUNTIME)
|
|
||||||
@Inherited
|
|
||||||
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
|
|
||||||
public @interface Enveloped {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The set of messages that should be dispatched to the message handler
|
|
||||||
*/
|
|
||||||
Class[] messages();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package net.engio.mbassy.listener;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The filter annotation is used to add filters to message listeners.
|
|
||||||
* It references a class that implements the IMessageFilter interface.
|
|
||||||
* The filter will be used to check whether a message should be delivered
|
|
||||||
* to the listener or not.
|
|
||||||
* <p/>
|
|
||||||
* <p/>
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 2/14/12
|
|
||||||
*/
|
|
||||||
@Retention(value = RetentionPolicy.RUNTIME)
|
|
||||||
@Target(value = {ElementType.ANNOTATION_TYPE})
|
|
||||||
public @interface Filter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The class that implements the filter.
|
|
||||||
* Note: A filter always needs to provide a non-arg constructor
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Class<? extends IMessageFilter> value();
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
package net.engio.mbassy.listener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of standard filters for common use cases.
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 12/12/12
|
|
||||||
*/
|
|
||||||
public class Filters {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This filter will only accept messages of the exact same type
|
|
||||||
* as specified for the handler. Subclasses (this includes interface implementations)
|
|
||||||
* will be rejected.
|
|
||||||
*
|
|
||||||
* NOTE: The same functionality (with better performance) is achieved using {@code rejectSubtypes = true}
|
|
||||||
* in the @Handler annotation
|
|
||||||
*/
|
|
||||||
public static final class RejectSubtypes implements IMessageFilter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean accepts(Object event, MessageHandler metadata) {
|
|
||||||
for (Class handledMessage : metadata.getHandledMessages()) {
|
|
||||||
if (handledMessage.equals(event.getClass())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This filter will only accept messages that are real subtypes
|
|
||||||
* of the specified message types handled by the message handler.
|
|
||||||
* Example: If the handler handles Object.class the filter accepts
|
|
||||||
* all objects except any direct instance of Object.class {@code new Object()}
|
|
||||||
*/
|
|
||||||
public static final class SubtypesOnly implements IMessageFilter{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean accepts(Object message, MessageHandler metadata) {
|
|
||||||
for(Class acceptedClasses : metadata.getHandledMessages()){
|
|
||||||
if(acceptedClasses.isAssignableFrom(message.getClass())
|
|
||||||
&& ! acceptedClasses.equals(message.getClass()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,9 +1,10 @@
|
|||||||
package net.engio.mbassy.listener;
|
package net.engio.mbassy.listener;
|
||||||
|
|
||||||
import net.engio.mbassy.dispatch.HandlerInvocation;
|
import java.lang.annotation.ElementType;
|
||||||
import net.engio.mbassy.dispatch.ReflectiveHandlerInvocation;
|
import java.lang.annotation.Inherited;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark any method of any class(=listener) as a message handler and configure the handler
|
* Mark any method of any class(=listener) as a message handler and configure the handler
|
||||||
@ -17,35 +18,6 @@ import java.lang.annotation.*;
|
|||||||
@Target(value = {ElementType.METHOD,ElementType.ANNOTATION_TYPE})
|
@Target(value = {ElementType.METHOD,ElementType.ANNOTATION_TYPE})
|
||||||
public @interface Handler {
|
public @interface Handler {
|
||||||
|
|
||||||
/**
|
|
||||||
* Add any numbers of filters to the handler. All filters are evaluated before the handler
|
|
||||||
* is actually invoked, which is only if all the filters accept the message.
|
|
||||||
*/
|
|
||||||
Filter[] filters() default {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines a filter condition as Expression Language. This can be used to filter the events based on
|
|
||||||
* attributes of the event object. Note that the expression must resolve to either
|
|
||||||
* <code>true</code> to allow the event or <code>false</code> to block it from delivery to the handler.
|
|
||||||
* The message itself is available as "msg" variable.
|
|
||||||
* @return the condition in EL syntax.
|
|
||||||
*/
|
|
||||||
String condition() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define the mode in which a message is delivered to each listener. Listeners can be notified
|
|
||||||
* sequentially or concurrently.
|
|
||||||
*/
|
|
||||||
Invoke delivery() default Invoke.Synchronously;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handlers are ordered by priority and handlers with higher priority are processed before
|
|
||||||
* those with lower priority, i.e. Influence the order in which different handlers that consume
|
|
||||||
* the same message type are invoked.
|
|
||||||
*/
|
|
||||||
int priority() default 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define whether or not the handler accepts sub types of the message type it declares in its
|
* Define whether or not the handler accepts sub types of the message type it declares in its
|
||||||
* signature.
|
* signature.
|
||||||
@ -59,18 +31,4 @@ public @interface Handler {
|
|||||||
* handlers that have been declared by a superclass but do not apply to the subclass
|
* handlers that have been declared by a superclass but do not apply to the subclass
|
||||||
*/
|
*/
|
||||||
boolean enabled() default true;
|
boolean enabled() default true;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Each handler call is implemented as an invocation object that implements the invocation mechanism.
|
|
||||||
* The basic implementation uses reflection and is the default. It is possible though to provide a custom
|
|
||||||
* invocation to add additional logic.
|
|
||||||
*
|
|
||||||
* Note: Providing a custom invocation will most likely reduce performance, since the JIT-Compiler
|
|
||||||
* can not do some of its sophisticated byte code optimizations.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
Class<? extends HandlerInvocation> invocation() default ReflectiveHandlerInvocation.class;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
package net.engio.mbassy.listener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Message filters can be used to control what messages are delivered to a specific message handler.
|
|
||||||
* Filters are attached to message handler using the @Listener annotation.
|
|
||||||
* If a message handler specifies filters, the filters accepts(...) method will be checked before the actual handler is invoked.
|
|
||||||
* The handler will be invoked only if each filter accepted the message.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* @Lister
|
|
||||||
* @Filters(Urlfilter.class)
|
|
||||||
* public void someHandler(String message){...}
|
|
||||||
*
|
|
||||||
* class Urlfilter implements IMessageFilter<String>{
|
|
||||||
* public boolean accepts(String message, MessageHandler metadata){
|
|
||||||
* return message.startsWith("http");
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* bus.post("http://www.infoq.com"); // will be delivered
|
|
||||||
* bus.post("www.stackoverflow.com"); // will not be delivered
|
|
||||||
*
|
|
||||||
* NOTE: A message filter must provide a no-arg constructor!!!
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 2/8/12
|
|
||||||
*/
|
|
||||||
public interface IMessageFilter<M> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the message for whatever criteria
|
|
||||||
*
|
|
||||||
* @param message the message to be handled by the handler
|
|
||||||
* @param metadata the metadata object which describes the message handler
|
|
||||||
* @return true: if the message matches the criteria and should be delivered to the handler
|
|
||||||
* false: otherwise
|
|
||||||
*/
|
|
||||||
boolean accepts(M message, MessageHandler metadata);
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package net.engio.mbassy.listener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created with IntelliJ IDEA.
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 11/16/12
|
|
||||||
*/
|
|
||||||
public enum Invoke {
|
|
||||||
Synchronously, Asynchronously
|
|
||||||
}
|
|
@ -1,6 +1,10 @@
|
|||||||
package net.engio.mbassy.listener;
|
package net.engio.mbassy.listener;
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Inherited;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -17,12 +21,4 @@ import java.lang.annotation.*;
|
|||||||
@Inherited
|
@Inherited
|
||||||
public @interface Listener {
|
public @interface Listener {
|
||||||
|
|
||||||
/**
|
|
||||||
* By default, references to message listeners are weak to eliminate risks of memory leaks.
|
|
||||||
* It is possible to use strong references instead.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
References references() default References.Weak;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
package net.engio.mbassy.listener;
|
package net.engio.mbassy.listener;
|
||||||
|
|
||||||
import net.engio.mbassy.common.ReflectionUtils;
|
|
||||||
import net.engio.mbassy.dispatch.HandlerInvocation;
|
|
||||||
import net.engio.mbassy.dispatch.el.ElFilter;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import net.engio.mbassy.common.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Any method in any class annotated with the @Handler annotation represents a message handler. The class that contains
|
* Any method in any class annotated with the @Handler annotation represents a message handler. The class that contains
|
||||||
@ -19,198 +15,57 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class MessageHandler {
|
public class MessageHandler {
|
||||||
|
|
||||||
public static final class Properties{
|
|
||||||
|
|
||||||
public static final String HandlerMethod = "handler";
|
|
||||||
public static final String InvocationMode = "invocationMode";
|
|
||||||
public static final String Filter = "filter";
|
|
||||||
public static final String Condition = "condition";
|
|
||||||
public static final String Enveloped = "envelope";
|
|
||||||
public static final String HandledMessages = "messages";
|
|
||||||
public static final String IsSynchronized = "synchronized";
|
|
||||||
public static final String Listener = "listener";
|
|
||||||
public static final String AcceptSubtypes = "subtypes";
|
|
||||||
public static final String Priority = "priority";
|
|
||||||
public static final String Invocation = "invocation";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the property map for the {@link MessageHandler} constructor using the default objects.
|
|
||||||
*
|
|
||||||
* @param handler The handler annotated method of the listener
|
|
||||||
* @param handlerConfig The annotation that configures the handler
|
|
||||||
* @param filter The set of preconfigured filters if any
|
|
||||||
* @param listenerConfig The listener metadata
|
|
||||||
* @return A map of properties initialized from the given parameters that will conform to the requirements of the
|
|
||||||
* {@link MessageHandler} constructor. See {@see MessageHandler.validate()} for more details.
|
|
||||||
*/
|
|
||||||
public static final Map<String, Object> Create(Method handler, Handler handlerConfig, IMessageFilter[] filter, MessageListener listenerConfig){
|
|
||||||
if(handler == null){
|
|
||||||
throw new IllegalArgumentException("The message handler configuration may not be null");
|
|
||||||
}
|
|
||||||
if(filter == null){
|
|
||||||
filter = new IMessageFilter[]{};
|
|
||||||
}
|
|
||||||
Enveloped enveloped = ReflectionUtils.getAnnotation( handler, Enveloped.class );
|
|
||||||
Class[] handledMessages = enveloped != null
|
|
||||||
? enveloped.messages()
|
|
||||||
: handler.getParameterTypes();
|
|
||||||
handler.setAccessible(true);
|
|
||||||
Map<String, Object> properties = new HashMap<String, Object>();
|
|
||||||
properties.put(HandlerMethod, handler);
|
|
||||||
// add EL filter if a condition is present
|
|
||||||
if(handlerConfig.condition().length() > 0){
|
|
||||||
if (!ElFilter.isELAvailable()) {
|
|
||||||
throw new IllegalStateException("A handler uses an EL filter but no EL implementation is available.");
|
|
||||||
}
|
|
||||||
|
|
||||||
IMessageFilter[] expandedFilter = new IMessageFilter[filter.length + 1];
|
|
||||||
for(int i = 0; i < filter.length ; i++){
|
|
||||||
expandedFilter[i] = filter[i];
|
|
||||||
}
|
|
||||||
expandedFilter[filter.length] = new ElFilter();
|
|
||||||
filter = expandedFilter;
|
|
||||||
}
|
|
||||||
properties.put(Filter, filter);
|
|
||||||
properties.put(Condition, cleanEL(handlerConfig.condition()));
|
|
||||||
properties.put(Priority, handlerConfig.priority());
|
|
||||||
properties.put(Invocation, handlerConfig.invocation());
|
|
||||||
properties.put(InvocationMode, handlerConfig.delivery());
|
|
||||||
properties.put(Enveloped, enveloped != null);
|
|
||||||
properties.put(AcceptSubtypes, !handlerConfig.rejectSubtypes());
|
|
||||||
properties.put(Listener, listenerConfig);
|
|
||||||
properties.put(IsSynchronized, ReflectionUtils.getAnnotation( handler, Synchronized.class) != null);
|
|
||||||
properties.put(HandledMessages, handledMessages);
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String cleanEL(String expression) {
|
|
||||||
|
|
||||||
if (!expression.trim().startsWith("${") && !expression.trim().startsWith("#{")) {
|
|
||||||
expression = "${"+expression+"}";
|
|
||||||
}
|
|
||||||
return expression;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private final Method handler;
|
private final Method handler;
|
||||||
|
private final Class<?>[] handledMessages;
|
||||||
private final IMessageFilter[] filter;
|
|
||||||
|
|
||||||
private final String condition;
|
|
||||||
|
|
||||||
private final int priority;
|
|
||||||
|
|
||||||
private final Class<? extends HandlerInvocation> invocation;
|
|
||||||
|
|
||||||
private final Invoke invocationMode;
|
|
||||||
|
|
||||||
private final boolean isEnvelope;
|
|
||||||
|
|
||||||
private final Class[] handledMessages;
|
|
||||||
|
|
||||||
private final boolean acceptsSubtypes;
|
private final boolean acceptsSubtypes;
|
||||||
|
|
||||||
private final MessageListener listenerConfig;
|
private final MessageListener listenerConfig;
|
||||||
|
|
||||||
private final boolean isSynchronized;
|
private final boolean isSynchronized;
|
||||||
|
|
||||||
|
|
||||||
public MessageHandler(Map<String, Object> properties){
|
public MessageHandler(Method handler, Handler handlerConfig, MessageListener listenerMetadata){
|
||||||
super();
|
super();
|
||||||
validate(properties);
|
|
||||||
this.handler = (Method)properties.get(Properties.HandlerMethod);
|
if (handler == null) {
|
||||||
this.filter = (IMessageFilter[])properties.get(Properties.Filter);
|
throw new IllegalArgumentException("The message handler configuration may not be null");
|
||||||
this.condition = (String)properties.get(Properties.Condition);
|
|
||||||
this.priority = (Integer)properties.get(Properties.Priority);
|
|
||||||
this.invocation = (Class<? extends HandlerInvocation>)properties.get(Properties.Invocation);
|
|
||||||
this.invocationMode = (Invoke)properties.get(Properties.InvocationMode);
|
|
||||||
this.isEnvelope = (Boolean)properties.get(Properties.Enveloped);
|
|
||||||
this.acceptsSubtypes = (Boolean)properties.get(Properties.AcceptSubtypes);
|
|
||||||
this.listenerConfig = (MessageListener)properties.get(Properties.Listener);
|
|
||||||
this.isSynchronized = (Boolean)properties.get(Properties.IsSynchronized);
|
|
||||||
this.handledMessages = (Class[])properties.get(Properties.HandledMessages);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validate(Map<String, Object> properties){
|
|
||||||
Object[][] expectedProperties = new Object[][]{
|
|
||||||
new Object[]{Properties.HandlerMethod, Method.class },
|
|
||||||
new Object[]{Properties.Priority, Integer.class },
|
|
||||||
new Object[]{Properties.Invocation, Class.class },
|
|
||||||
new Object[]{Properties.Filter, IMessageFilter[].class },
|
|
||||||
new Object[]{Properties.Condition, String.class },
|
|
||||||
new Object[]{Properties.Enveloped, Boolean.class },
|
|
||||||
new Object[]{Properties.HandledMessages, Class[].class },
|
|
||||||
new Object[]{Properties.IsSynchronized, Boolean.class },
|
|
||||||
new Object[]{Properties.Listener, MessageListener.class },
|
|
||||||
new Object[]{Properties.AcceptSubtypes, Boolean.class }
|
|
||||||
};
|
|
||||||
for(Object[] property : expectedProperties){
|
|
||||||
if (properties.get(property[0]) == null || !((Class)property[1]).isAssignableFrom(properties.get(property[0]).getClass()))
|
|
||||||
throw new IllegalArgumentException("Property " + property[0] + " was expected to be not null and of type " + property[1]
|
|
||||||
+ " but was: " + properties.get(property[0]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Class<?>[] handledMessages = handler.getParameterTypes();
|
||||||
|
handler.setAccessible(true);
|
||||||
|
|
||||||
|
this.handler = handler;
|
||||||
|
this.acceptsSubtypes = !handlerConfig.rejectSubtypes();
|
||||||
|
this.listenerConfig = listenerMetadata;
|
||||||
|
this.isSynchronized = ReflectionUtils.getAnnotation(handler, Synchronized.class) != null;
|
||||||
|
this.handledMessages = handledMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <A extends Annotation> A getAnnotation(Class<A> annotationType){
|
public <A extends Annotation> A getAnnotation(Class<A> annotationType){
|
||||||
return ReflectionUtils.getAnnotation(handler,annotationType);
|
return ReflectionUtils.getAnnotation(this.handler,annotationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSynchronized(){
|
public boolean isSynchronized(){
|
||||||
return isSynchronized;
|
return this.isSynchronized;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean useStrongReferences(){
|
public boolean isFromListener(Class<?> listener){
|
||||||
return listenerConfig.useStrongReferences();
|
return this.listenerConfig.isFromListener(listener);
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFromListener(Class listener){
|
|
||||||
return listenerConfig.isFromListener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAsynchronous() {
|
|
||||||
return invocationMode.equals(Invoke.Asynchronously);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFiltered() {
|
|
||||||
return filter.length > 0 || (condition != null && condition.trim().length() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPriority() {
|
|
||||||
return priority;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Method getHandler() {
|
public Method getHandler() {
|
||||||
return handler;
|
return this.handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IMessageFilter[] getFilter() {
|
public Class<?>[] getHandledMessages() {
|
||||||
return filter;
|
return this.handledMessages;
|
||||||
}
|
|
||||||
|
|
||||||
public String getCondition() {
|
|
||||||
return this.condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class[] getHandledMessages() {
|
|
||||||
return handledMessages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnveloped() {
|
|
||||||
return isEnvelope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<? extends HandlerInvocation> getHandlerInvocation(){
|
|
||||||
return invocation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean handlesMessage(Class<?> messageType) {
|
public boolean handlesMessage(Class<?> messageType) {
|
||||||
for (Class<?> handledMessage : handledMessages) {
|
for (Class<?> handledMessage : this.handledMessages) {
|
||||||
if (handledMessage.equals(messageType)) {
|
if (handledMessage.equals(messageType)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handledMessage.isAssignableFrom(messageType) && acceptsSubtypes()) {
|
if (handledMessage.isAssignableFrom(messageType) && acceptsSubtypes()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -219,7 +74,6 @@ public class MessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean acceptsSubtypes() {
|
public boolean acceptsSubtypes() {
|
||||||
return acceptsSubtypes;
|
return this.acceptsSubtypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package net.engio.mbassy.listener;
|
package net.engio.mbassy.listener;
|
||||||
|
|
||||||
import net.engio.mbassy.common.IPredicate;
|
|
||||||
import net.engio.mbassy.common.ReflectionUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -23,55 +20,36 @@ import java.util.List;
|
|||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 12/16/12
|
* Date: 12/16/12
|
||||||
*/
|
*/
|
||||||
public class MessageListener<T> {
|
public class MessageListener {
|
||||||
|
|
||||||
|
|
||||||
public static IPredicate<MessageHandler> ForMessage(final Class<?> messageType) {
|
|
||||||
return new IPredicate<MessageHandler>() {
|
|
||||||
@Override
|
|
||||||
public boolean apply(MessageHandler target) {
|
|
||||||
return target.handlesMessage(messageType);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<MessageHandler> handlers = new ArrayList<MessageHandler>();
|
private List<MessageHandler> handlers = new ArrayList<MessageHandler>();
|
||||||
|
private Class<?> listenerDefinition;
|
||||||
|
|
||||||
private Class<T> listenerDefinition;
|
public MessageListener(Class<?> listenerDefinition) {
|
||||||
|
|
||||||
private Listener listenerAnnotation;
|
|
||||||
|
|
||||||
public MessageListener(Class<T> listenerDefinition) {
|
|
||||||
this.listenerDefinition = listenerDefinition;
|
this.listenerDefinition = listenerDefinition;
|
||||||
listenerAnnotation = ReflectionUtils.getAnnotation( listenerDefinition, Listener.class );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFromListener(Class<?> listener){
|
||||||
public boolean isFromListener(Class listener){
|
return this.listenerDefinition.equals(listener);
|
||||||
return listenerDefinition.equals(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean useStrongReferences(){
|
|
||||||
return listenerAnnotation != null && listenerAnnotation.references().equals(References.Strong);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessageListener addHandlers(Collection<? extends MessageHandler> c) {
|
public MessageListener addHandlers(Collection<? extends MessageHandler> c) {
|
||||||
handlers.addAll(c);
|
this.handlers.addAll(c);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addHandler(MessageHandler messageHandler) {
|
public boolean addHandler(MessageHandler messageHandler) {
|
||||||
return handlers.add(messageHandler);
|
return this.handlers.add(messageHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MessageHandler> getHandlers(){
|
public List<MessageHandler> getHandlers(){
|
||||||
return handlers;
|
return this.handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MessageHandler> getHandlers(IPredicate<MessageHandler> filter) {
|
public List<MessageHandler> getHandlers(Class<?> messageType) {
|
||||||
List<MessageHandler> matching = new LinkedList<MessageHandler>();
|
List<MessageHandler> matching = new LinkedList<MessageHandler>();
|
||||||
for (MessageHandler handler : handlers) {
|
for (MessageHandler handler : this.handlers) {
|
||||||
if (filter.apply(handler)) {
|
if (handler.handlesMessage(messageType)) {
|
||||||
matching.add(handler);
|
matching.add(handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,10 +57,10 @@ public class MessageListener<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean handles(Class<?> messageType) {
|
public boolean handles(Class<?> messageType) {
|
||||||
return !getHandlers(ForMessage(messageType)).isEmpty();
|
return !getHandlers(messageType).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<T> getListerDefinition() {
|
public Class<?> getListerDefinition() {
|
||||||
return listenerDefinition;
|
return this.listenerDefinition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
package net.engio.mbassy.listener;
|
package net.engio.mbassy.listener;
|
||||||
|
|
||||||
import net.engio.mbassy.common.IPredicate;
|
|
||||||
import net.engio.mbassy.common.ReflectionUtils;
|
|
||||||
import net.engio.mbassy.subscription.MessageEnvelope;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
import net.engio.mbassy.common.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The meta data reader is responsible for parsing and validating message handler configurations.
|
* The meta data reader is responsible for parsing and validating message handler configurations.
|
||||||
@ -18,46 +14,13 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class MetadataReader {
|
public class MetadataReader {
|
||||||
|
|
||||||
// This predicate is used to find all message listeners (methods annotated with @Handler)
|
|
||||||
private static final IPredicate<Method> AllMessageHandlers = new IPredicate<Method>() {
|
|
||||||
@Override
|
|
||||||
public boolean apply(Method target) {
|
|
||||||
return ReflectionUtils.getAnnotation(target, Handler.class) != null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// cache already created filter instances
|
|
||||||
private final Map<Class<? extends IMessageFilter>, IMessageFilter> filterCache = new HashMap<Class<? extends IMessageFilter>, IMessageFilter>();
|
|
||||||
|
|
||||||
// retrieve all instances of filters associated with the given subscription
|
|
||||||
private IMessageFilter[] getFilter(Handler subscription) {
|
|
||||||
if (subscription.filters().length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
IMessageFilter[] filters = new IMessageFilter[subscription.filters().length];
|
|
||||||
int i = 0;
|
|
||||||
for (Filter filterDef : subscription.filters()) {
|
|
||||||
IMessageFilter filter = filterCache.get(filterDef.value());
|
|
||||||
if (filter == null) {
|
|
||||||
try {
|
|
||||||
filter = filterDef.value().newInstance();
|
|
||||||
filterCache.put(filterDef.value(), filter);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);// propagate as runtime exception
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filters[i] = filter;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return filters;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get all listeners defined by the given class (includes
|
// get all listeners defined by the given class (includes
|
||||||
// listeners defined in super classes)
|
// listeners defined in super classes)
|
||||||
public MessageListener getMessageListener(Class target) {
|
public MessageListener getMessageListener(Class<?> target) {
|
||||||
MessageListener listenerMetadata = new MessageListener(target);
|
|
||||||
// get all handlers (this will include all (inherited) methods directly annotated using @Handler)
|
// get all handlers (this will include all (inherited) methods directly annotated using @Handler)
|
||||||
List<Method> allHandlers = ReflectionUtils.getMethods(AllMessageHandlers, target);
|
List<Method> allHandlers = ReflectionUtils.getMethods(target);
|
||||||
|
|
||||||
// retain only those that are at the bottom of their respective class hierarchy (deepest overriding method)
|
// retain only those that are at the bottom of their respective class hierarchy (deepest overriding method)
|
||||||
List<Method> bottomMostHandlers = new LinkedList<Method>();
|
List<Method> bottomMostHandlers = new LinkedList<Method>();
|
||||||
for (Method handler : allHandlers) {
|
for (Method handler : allHandlers) {
|
||||||
@ -66,6 +29,8 @@ public class MetadataReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessageListener listenerMetadata = new MessageListener(target);
|
||||||
|
|
||||||
// for each handler there will be no overriding method that specifies @Handler annotation
|
// 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
|
// but an overriding method does inherit the listener configuration of the overwritten method
|
||||||
for (Method handler : bottomMostHandlers) {
|
for (Method handler : bottomMostHandlers) {
|
||||||
@ -73,11 +38,14 @@ public class MetadataReader {
|
|||||||
if (!handlerConfig.enabled() || !isValidMessageHandler(handler)) {
|
if (!handlerConfig.enabled() || !isValidMessageHandler(handler)) {
|
||||||
continue; // disabled or invalid listeners are ignored
|
continue; // disabled or invalid listeners are ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
Method overriddenHandler = ReflectionUtils.getOverridingMethod(handler, target);
|
Method overriddenHandler = ReflectionUtils.getOverridingMethod(handler, target);
|
||||||
|
if (overriddenHandler == null) {
|
||||||
|
overriddenHandler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
// if a handler is overwritten it inherits the configuration of its parent method
|
// if a handler is overwritten it inherits the configuration of its parent method
|
||||||
Map<String, Object> handlerProperties = MessageHandler.Properties.Create(overriddenHandler == null ? handler : overriddenHandler,
|
MessageHandler handlerMetadata = new MessageHandler(overriddenHandler, handlerConfig, listenerMetadata);
|
||||||
handlerConfig, getFilter(handlerConfig), listenerMetadata);
|
|
||||||
MessageHandler handlerMetadata = new MessageHandler(handlerProperties);
|
|
||||||
listenerMetadata.addHandler(handlerMetadata);
|
listenerMetadata.addHandler(handlerMetadata);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -86,7 +54,7 @@ public class MetadataReader {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: change this to support MORE THAN ONE object in the signature
|
||||||
private boolean isValidMessageHandler(Method handler) {
|
private boolean isValidMessageHandler(Method handler) {
|
||||||
if (handler == null || ReflectionUtils.getAnnotation( handler, Handler.class) == null) {
|
if (handler == null || ReflectionUtils.getAnnotation( handler, Handler.class) == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -97,15 +65,7 @@ public class MetadataReader {
|
|||||||
+ "]. A messageHandler must define exactly one parameter");
|
+ "]. A messageHandler must define exactly one parameter");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Enveloped envelope = ReflectionUtils.getAnnotation( handler, Enveloped.class);
|
|
||||||
if (envelope != null && !MessageEnvelope.class.isAssignableFrom(handler.getParameterTypes()[0])) {
|
|
||||||
System.out.println("Message envelope configured but no subclass of MessageEnvelope found as parameter");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (envelope != null && envelope.messages().length == 0) {
|
|
||||||
System.out.println("Message envelope configured but message types defined for handler");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package net.engio.mbassy.listener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 3/29/13
|
|
||||||
*/
|
|
||||||
public enum References {
|
|
||||||
Strong,Weak
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package net.engio.mbassy.subscription;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A message envelope is used to wrap messages of arbitrary type such that a handler
|
|
||||||
* my receive messages of different types.
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 12/12/12
|
|
||||||
*/
|
|
||||||
public class MessageEnvelope {
|
|
||||||
|
|
||||||
// Internal state
|
|
||||||
private Object message;
|
|
||||||
|
|
||||||
public MessageEnvelope(Object message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T getMessage() {
|
|
||||||
return (T) message;
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,9 +4,6 @@ import net.engio.mbassy.bus.IMessagePublication;
|
|||||||
import net.engio.mbassy.common.IConcurrentSet;
|
import net.engio.mbassy.common.IConcurrentSet;
|
||||||
import net.engio.mbassy.dispatch.IMessageDispatcher;
|
import net.engio.mbassy.dispatch.IMessageDispatcher;
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subscription is a thread-safe container that manages exactly one message handler of all registered
|
* A subscription is a thread-safe container that manages exactly one message handler of all registered
|
||||||
* message listeners of the same class, i.e. all subscribed instances (exlcuding subclasses) of a SingleMessageHandler.class
|
* message listeners of the same class, i.e. all subscribed instances (exlcuding subclasses) of a SingleMessageHandler.class
|
||||||
@ -21,8 +18,6 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
public class Subscription {
|
public class Subscription {
|
||||||
|
|
||||||
private final UUID id = UUID.randomUUID();
|
|
||||||
|
|
||||||
protected final IConcurrentSet<Object> listeners;
|
protected final IConcurrentSet<Object> listeners;
|
||||||
|
|
||||||
private final IMessageDispatcher dispatcher;
|
private final IMessageDispatcher dispatcher;
|
||||||
@ -41,8 +36,8 @@ public class Subscription {
|
|||||||
* @param listener
|
* @param listener
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean belongsTo(Class listener){
|
public boolean belongsTo(Class<?> listener){
|
||||||
return context.getHandlerMetadata().isFromListener(listener);
|
return this.context.getHandlerMetadata().isFromListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +46,7 @@ public class Subscription {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean contains(Object listener){
|
public boolean contains(Object listener){
|
||||||
return listeners.contains(listener);
|
return this.listeners.contains(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,46 +55,30 @@ public class Subscription {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean handlesMessageType(Class<?> messageType) {
|
public boolean handlesMessageType(Class<?> messageType) {
|
||||||
return context.getHandlerMetadata().handlesMessage(messageType);
|
return this.context.getHandlerMetadata().handlesMessage(messageType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class[] getHandledMessageTypes(){
|
public Class<?>[] getHandledMessageTypes(){
|
||||||
return context.getHandlerMetadata().getHandledMessages();
|
return this.context.getHandlerMetadata().getHandledMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void publish(IMessagePublication publication, Object message){
|
public void publish(IMessagePublication publication, Object message){
|
||||||
if(listeners.size() > 0)
|
if(this.listeners.size() > 0) {
|
||||||
dispatcher.dispatch(publication, message, listeners);
|
this.dispatcher.dispatch(publication, message, this.listeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPriority() {
|
|
||||||
return context.getHandlerMetadata().getPriority();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void subscribe(Object o) {
|
public void subscribe(Object o) {
|
||||||
listeners.add(o);
|
this.listeners.add(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean unsubscribe(Object existingListener) {
|
public boolean unsubscribe(Object existingListener) {
|
||||||
return listeners.remove(existingListener);
|
return this.listeners.remove(existingListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
return listeners.size();
|
return this.listeners.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static final Comparator<Subscription> SubscriptionByPriorityDesc = new Comparator<Subscription>() {
|
|
||||||
@Override
|
|
||||||
public int compare(Subscription o1, Subscription o2) {
|
|
||||||
int byPriority = ((Integer)o2.getPriority()).compareTo(o1.getPriority());
|
|
||||||
return byPriority == 0 ? o2.id.compareTo(o1.id) : byPriority;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
package net.engio.mbassy.subscription;
|
package net.engio.mbassy.subscription;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.BusRuntime;
|
|
||||||
import net.engio.mbassy.bus.error.IPublicationErrorHandler;
|
|
||||||
import net.engio.mbassy.bus.error.MessageBusException;
|
|
||||||
import net.engio.mbassy.common.StrongConcurrentSet;
|
|
||||||
import net.engio.mbassy.common.WeakConcurrentSet;
|
|
||||||
import net.engio.mbassy.dispatch.*;
|
|
||||||
import net.engio.mbassy.listener.MessageHandler;
|
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import net.engio.mbassy.bus.BusRuntime;
|
||||||
|
import net.engio.mbassy.bus.error.IPublicationErrorHandler;
|
||||||
|
import net.engio.mbassy.bus.error.MessageBusException;
|
||||||
|
import net.engio.mbassy.common.WeakConcurrentSet;
|
||||||
|
import net.engio.mbassy.dispatch.HandlerInvocation;
|
||||||
|
import net.engio.mbassy.dispatch.IHandlerInvocation;
|
||||||
|
import net.engio.mbassy.dispatch.IMessageDispatcher;
|
||||||
|
import net.engio.mbassy.dispatch.MessageDispatcher;
|
||||||
|
import net.engio.mbassy.dispatch.ReflectiveHandlerInvocation;
|
||||||
|
import net.engio.mbassy.dispatch.SynchronizedHandlerInvocation;
|
||||||
|
import net.engio.mbassy.listener.MessageHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The subscription factory is used to create an empty subscription for specific message handler.
|
* The subscription factory is used to create an empty subscription for specific message handler.
|
||||||
* The message handler's configuration is evaluated and a corresponding subscription is built.
|
* The message handler's configuration is evaluated and a corresponding subscription is built.
|
||||||
@ -24,9 +28,7 @@ public class SubscriptionFactory {
|
|||||||
SubscriptionContext context = new SubscriptionContext(runtime, handlerMetadata, errorHandlers);
|
SubscriptionContext context = new SubscriptionContext(runtime, handlerMetadata, errorHandlers);
|
||||||
IHandlerInvocation invocation = buildInvocationForHandler(context);
|
IHandlerInvocation invocation = buildInvocationForHandler(context);
|
||||||
IMessageDispatcher dispatcher = buildDispatcher(context, invocation);
|
IMessageDispatcher dispatcher = buildDispatcher(context, invocation);
|
||||||
return new Subscription(context, dispatcher, handlerMetadata.useStrongReferences()
|
return new Subscription(context, dispatcher, new WeakConcurrentSet<Object>());
|
||||||
? new StrongConcurrentSet<Object>()
|
|
||||||
: new WeakConcurrentSet<Object>());
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new MessageBusException(e);
|
throw new MessageBusException(e);
|
||||||
}
|
}
|
||||||
@ -37,25 +39,18 @@ public class SubscriptionFactory {
|
|||||||
if(context.getHandlerMetadata().isSynchronized()){
|
if(context.getHandlerMetadata().isSynchronized()){
|
||||||
invocation = new SynchronizedHandlerInvocation(invocation);
|
invocation = new SynchronizedHandlerInvocation(invocation);
|
||||||
}
|
}
|
||||||
if (context.getHandlerMetadata().isAsynchronous()) {
|
|
||||||
invocation = new AsynchronousHandlerInvocation(invocation);
|
|
||||||
}
|
|
||||||
return invocation;
|
return invocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IMessageDispatcher buildDispatcher(SubscriptionContext context, IHandlerInvocation invocation) {
|
protected IMessageDispatcher buildDispatcher(SubscriptionContext context, IHandlerInvocation invocation) {
|
||||||
IMessageDispatcher dispatcher = new MessageDispatcher(context, invocation);
|
IMessageDispatcher dispatcher = new MessageDispatcher(context, invocation);
|
||||||
if (context.getHandlerMetadata().isEnveloped()) {
|
|
||||||
dispatcher = new EnvelopedMessageDispatcher(dispatcher);
|
|
||||||
}
|
|
||||||
if (context.getHandlerMetadata().isFiltered()) {
|
|
||||||
dispatcher = new FilteredMessageDispatcher(dispatcher);
|
|
||||||
}
|
|
||||||
return dispatcher;
|
return dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IHandlerInvocation createBaseHandlerInvocation(SubscriptionContext context) throws MessageBusException {
|
protected IHandlerInvocation createBaseHandlerInvocation(SubscriptionContext context) throws MessageBusException {
|
||||||
Class<? extends HandlerInvocation> invocation = context.getHandlerMetadata().getHandlerInvocation();
|
Class<? extends HandlerInvocation> invocation = ReflectiveHandlerInvocation.class;
|
||||||
if(invocation.isMemberClass() && !Modifier.isStatic(invocation.getModifiers())){
|
if(invocation.isMemberClass() && !Modifier.isStatic(invocation.getModifiers())){
|
||||||
throw new MessageBusException("The handler invocation must be top level class or nested STATIC inner class");
|
throw new MessageBusException("The handler invocation must be top level class or nested STATIC inner class");
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
package net.engio.mbassy.subscription;
|
package net.engio.mbassy.subscription;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.BusRuntime;
|
import net.engio.mbassy.bus.BusRuntime;
|
||||||
import net.engio.mbassy.common.ReflectionUtils;
|
import net.engio.mbassy.common.ReflectionUtils;
|
||||||
import net.engio.mbassy.common.StrongConcurrentSet;
|
|
||||||
import net.engio.mbassy.listener.MessageHandler;
|
import net.engio.mbassy.listener.MessageHandler;
|
||||||
import net.engio.mbassy.listener.MetadataReader;
|
import net.engio.mbassy.listener.MetadataReader;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The subscription managers responsibility is to consistently handle and synchronize the message listener subscription process.
|
* The subscription managers responsibility is to consistently handle and synchronize the message listener subscription process.
|
||||||
* It provides fast lookup of existing subscriptions when another instance of an already known
|
* It provides fast lookup of existing subscriptions when another instance of an already known
|
||||||
@ -20,24 +25,26 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|||||||
*/
|
*/
|
||||||
public class SubscriptionManager {
|
public class SubscriptionManager {
|
||||||
|
|
||||||
|
private static final Object setObject = new Object();
|
||||||
|
|
||||||
// the metadata reader that is used to inspect objects passed to the subscribe method
|
// the metadata reader that is used to inspect objects passed to the subscribe method
|
||||||
private final MetadataReader metadataReader;
|
private final MetadataReader metadataReader;
|
||||||
|
|
||||||
// all subscriptions per message type
|
// all subscriptions per message type
|
||||||
// this is the primary list for dispatching a specific message
|
// this is the primary list for dispatching a specific message
|
||||||
// write access is synchronized and happens only when a listener of a specific class is registered the first time
|
// write access is synchronized and happens only when a listener of a specific class is registered the first time
|
||||||
private final Map<Class, Collection<Subscription>> subscriptionsPerMessage
|
private final Map<Class<?>, Collection<Subscription>> subscriptionsPerMessage
|
||||||
= new HashMap<Class, Collection<Subscription>>(50);
|
= new HashMap<Class<?>, Collection<Subscription>>(50);
|
||||||
|
|
||||||
// all subscriptions per messageHandler type
|
// all subscriptions per messageHandler type
|
||||||
// this map provides fast access for subscribing and unsubscribing
|
// this map provides fast access for subscribing and unsubscribing
|
||||||
// write access is synchronized and happens very infrequently
|
// write access is synchronized and happens very infrequently
|
||||||
// once a collection of subscriptions is stored it does not change
|
// once a collection of subscriptions is stored it does not change
|
||||||
private final Map<Class, Collection<Subscription>> subscriptionsPerListener
|
private final Map<Class<?>, Collection<Subscription>> subscriptionsPerListener
|
||||||
= new HashMap<Class, Collection<Subscription>>(50);
|
= new HashMap<Class<?>, Collection<Subscription>>(50);
|
||||||
|
|
||||||
// remember already processed classes that do not contain any message handlers
|
// remember already processed classes that do not contain any message handlers
|
||||||
private final StrongConcurrentSet<Class> nonListeners = new StrongConcurrentSet<Class>();
|
private final ConcurrentHashMap<Class<?>, Object> nonListeners = new ConcurrentHashMap<Class<?>, Object>();
|
||||||
|
|
||||||
// this factory is used to create specialized subscriptions based on the given message handler configuration
|
// this factory is used to create specialized subscriptions based on the given message handler configuration
|
||||||
// it can be customized by implementing the getSubscriptionFactory() method
|
// it can be customized by implementing the getSubscriptionFactory() method
|
||||||
@ -74,33 +81,38 @@ public class SubscriptionManager {
|
|||||||
private Collection<Subscription> getSubscriptionsByListener(Object listener) {
|
private Collection<Subscription> getSubscriptionsByListener(Object listener) {
|
||||||
Collection<Subscription> subscriptions;
|
Collection<Subscription> subscriptions;
|
||||||
try {
|
try {
|
||||||
readWriteLock.readLock().lock();
|
this.readWriteLock.readLock().lock();
|
||||||
subscriptions = subscriptionsPerListener.get(listener.getClass());
|
subscriptions = this.subscriptionsPerListener.get(listener.getClass());
|
||||||
} finally {
|
} finally {
|
||||||
readWriteLock.readLock().unlock();
|
this.readWriteLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
return subscriptions;
|
return subscriptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void subscribe(Object listener) {
|
public void subscribe(Object listener) {
|
||||||
try {
|
try {
|
||||||
if (isKnownNonListener(listener)) {
|
Class<? extends Object> listenerClass = listener.getClass();
|
||||||
|
|
||||||
|
if (this.nonListeners.contains(listenerClass)) {
|
||||||
return; // early reject of known classes that do not define message handlers
|
return; // early reject of known classes that do not define message handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<Subscription> subscriptionsByListener = getSubscriptionsByListener(listener);
|
Collection<Subscription> subscriptionsByListener = getSubscriptionsByListener(listener);
|
||||||
// a listener is either subscribed for the first time
|
// a listener is either subscribed for the first time
|
||||||
if (subscriptionsByListener == null) {
|
if (subscriptionsByListener == null) {
|
||||||
List<MessageHandler> messageHandlers = metadataReader.getMessageListener(listener.getClass()).getHandlers();
|
List<MessageHandler> messageHandlers = this.metadataReader.getMessageListener(listenerClass).getHandlers();
|
||||||
if (messageHandlers.isEmpty()) { // remember the class as non listening class if no handlers are found
|
if (messageHandlers.isEmpty()) { // remember the class as non listening class if no handlers are found
|
||||||
nonListeners.add(listener.getClass());
|
this.nonListeners.put(listenerClass, this.nonListeners);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
subscriptionsByListener = new ArrayList<Subscription>(messageHandlers.size()); // it's safe to use non-concurrent collection here (read only)
|
subscriptionsByListener = new ArrayList<Subscription>(messageHandlers.size()); // it's safe to use non-concurrent collection here (read only)
|
||||||
|
|
||||||
// create subscriptions for all detected message handlers
|
// create subscriptions for all detected message handlers
|
||||||
for (MessageHandler messageHandler : messageHandlers) {
|
for (MessageHandler messageHandler : messageHandlers) {
|
||||||
// create the subscription
|
// create the subscription
|
||||||
subscriptionsByListener.add(subscriptionFactory.createSubscription(runtime, messageHandler));
|
subscriptionsByListener.add(this.subscriptionFactory.createSubscription(this.runtime, messageHandler));
|
||||||
}
|
}
|
||||||
|
|
||||||
// this will acquire a write lock and handle the case when another thread already subscribed
|
// this will acquire a write lock and handle the case when another thread already subscribed
|
||||||
// this particular listener in the mean-time
|
// this particular listener in the mean-time
|
||||||
subscribe(listener, subscriptionsByListener);
|
subscribe(listener, subscriptionsByListener);
|
||||||
@ -119,7 +131,7 @@ public class SubscriptionManager {
|
|||||||
|
|
||||||
private void subscribe(Object listener, Collection<Subscription> subscriptions) {
|
private void subscribe(Object listener, Collection<Subscription> subscriptions) {
|
||||||
try {
|
try {
|
||||||
readWriteLock.writeLock().lock();
|
this.readWriteLock.writeLock().lock();
|
||||||
// basically this is a deferred double check
|
// basically this is a deferred double check
|
||||||
// it's an ugly pattern but necessary because atomic upgrade from read to write lock
|
// it's an ugly pattern but necessary because atomic upgrade from read to write lock
|
||||||
// is not possible
|
// is not possible
|
||||||
@ -134,7 +146,7 @@ public class SubscriptionManager {
|
|||||||
addMessageTypeSubscription(messageType, subscription);
|
addMessageTypeSubscription(messageType, subscription);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subscriptionsPerListener.put(listener.getClass(), subscriptions);
|
this.subscriptionsPerListener.put(listener.getClass(), subscriptions);
|
||||||
}
|
}
|
||||||
// the rare case when multiple threads concurrently subscribed the same class for the first time
|
// the rare case when multiple threads concurrently subscribed the same class for the first time
|
||||||
// one will be first, all others will have to subscribe to the existing instead the generated subscriptions
|
// one will be first, all others will have to subscribe to the existing instead the generated subscriptions
|
||||||
@ -144,29 +156,29 @@ public class SubscriptionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
readWriteLock.writeLock().unlock();
|
this.readWriteLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isKnownNonListener(Object listener) {
|
|
||||||
Class listeningClass = listener.getClass();
|
|
||||||
return nonListeners.contains(listeningClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
// obtain the set of subscriptions for the given message type
|
// obtain the set of subscriptions for the given message type
|
||||||
// Note: never returns null!
|
// Note: never returns null!
|
||||||
public Collection<Subscription> getSubscriptionsByMessageType(Class messageType) {
|
public Collection<Subscription> getSubscriptionsByMessageType(Class<?> messageType) {
|
||||||
Set<Subscription> subscriptions = new TreeSet<Subscription>(Subscription.SubscriptionByPriorityDesc);
|
// thread safe publication
|
||||||
try{
|
Collection<Subscription> subscriptions = new LinkedList<Subscription>();
|
||||||
readWriteLock.readLock().lock();
|
|
||||||
|
|
||||||
if (subscriptionsPerMessage.get(messageType) != null) {
|
try{
|
||||||
subscriptions.addAll(subscriptionsPerMessage.get(messageType));
|
this.readWriteLock.readLock().lock();
|
||||||
|
|
||||||
|
Collection<Subscription> collection = this.subscriptionsPerMessage.get(messageType);
|
||||||
|
if (collection != null) {
|
||||||
|
subscriptions.addAll(collection);
|
||||||
}
|
}
|
||||||
for (Class eventSuperType : ReflectionUtils.getSuperTypes(messageType)) {
|
|
||||||
Collection<Subscription> subs = subscriptionsPerMessage.get(eventSuperType);
|
// also add all subscriptions that match super types
|
||||||
|
for (Class<?> eventSuperType : ReflectionUtils.getSuperTypes(messageType)) {
|
||||||
|
Collection<Subscription> subs = this.subscriptionsPerMessage.get(eventSuperType);
|
||||||
if (subs != null) {
|
if (subs != null) {
|
||||||
for (Subscription sub : subs) {
|
for (Subscription sub : subs) {
|
||||||
if (sub.handlesMessageType(messageType)) {
|
if (sub.handlesMessageType(messageType)) {
|
||||||
@ -176,19 +188,20 @@ public class SubscriptionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}finally{
|
}finally{
|
||||||
readWriteLock.readLock().unlock();
|
this.readWriteLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return subscriptions;
|
return subscriptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// associate a subscription with a message type
|
// associate a subscription with a message type
|
||||||
// NOTE: Not thread-safe! must be synchronized in outer scope
|
// NOTE: Not thread-safe! must be synchronized in outer scope
|
||||||
private void addMessageTypeSubscription(Class messageType, Subscription subscription) {
|
private void addMessageTypeSubscription(Class<?> messageType, Subscription subscription) {
|
||||||
Collection<Subscription> subscriptions = subscriptionsPerMessage.get(messageType);
|
Collection<Subscription> subscriptions = this.subscriptionsPerMessage.get(messageType);
|
||||||
if (subscriptions == null) {
|
if (subscriptions == null) {
|
||||||
subscriptions = new LinkedList<Subscription>();
|
subscriptions = new LinkedList<Subscription>();
|
||||||
subscriptionsPerMessage.put(messageType, subscriptions);
|
this.subscriptionsPerMessage.put(messageType, subscriptions);
|
||||||
}
|
}
|
||||||
subscriptions.add(subscription);
|
subscriptions.add(subscription);
|
||||||
}
|
}
|
||||||
|
@ -11,19 +11,16 @@ import org.junit.runners.Suite;
|
|||||||
*/
|
*/
|
||||||
@RunWith(Suite.class)
|
@RunWith(Suite.class)
|
||||||
@Suite.SuiteClasses({
|
@Suite.SuiteClasses({
|
||||||
StrongConcurrentSetTest.class,
|
|
||||||
WeakConcurrentSetTest.class,
|
WeakConcurrentSetTest.class,
|
||||||
MBassadorTest.class,
|
MBassadorTest.class,
|
||||||
SyncBusTest.MBassadorTest.class,
|
SyncBusTest.MBassadorTest.class,
|
||||||
SyncBusTest.SyncMessageBusTest.class,
|
SyncBusTest.SyncMessageBusTest.class,
|
||||||
FilterTest.class,
|
|
||||||
MetadataReaderTest.class,
|
MetadataReaderTest.class,
|
||||||
MethodDispatchTest.class,
|
MethodDispatchTest.class,
|
||||||
DeadMessageTest.class,
|
DeadMessageTest.class,
|
||||||
SynchronizedHandlerTest.class,
|
SynchronizedHandlerTest.class,
|
||||||
SubscriptionManagerTest.class,
|
SubscriptionManagerTest.class,
|
||||||
AsyncFIFOBusTest.class,
|
AsyncFIFOBusTest.class,
|
||||||
ConditionalHandlers.class
|
|
||||||
})
|
})
|
||||||
public class AllTests {
|
public class AllTests {
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package net.engio.mbassy;
|
package net.engio.mbassy;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.BusFactory;
|
import net.engio.mbassy.bus.BusFactory;
|
||||||
import net.engio.mbassy.bus.common.IMessageBus;
|
import net.engio.mbassy.bus.common.IMessageBus;
|
||||||
import net.engio.mbassy.common.MessageBusTest;
|
import net.engio.mbassy.common.MessageBusTest;
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Invoke;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import org.junit.Test;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -35,11 +35,13 @@ public class AsyncFIFOBusTest extends MessageBusTest {
|
|||||||
messages[i] = i;
|
messages[i] = i;
|
||||||
}
|
}
|
||||||
// publish in ascending order
|
// publish in ascending order
|
||||||
for(Integer message : messages)
|
for(Integer message : messages) {
|
||||||
fifoBUs.post(message).asynchronously();
|
fifoBUs.post(message).asynchronously();
|
||||||
|
}
|
||||||
|
|
||||||
while(fifoBUs.hasPendingMessages())
|
while(fifoBUs.hasPendingMessages()) {
|
||||||
pause(1000);
|
pause(1000);
|
||||||
|
}
|
||||||
|
|
||||||
for(SyncListener listener : listeners){
|
for(SyncListener listener : listeners){
|
||||||
assertEquals(messages.length, listener.receivedSync.size());
|
assertEquals(messages.length, listener.receivedSync.size());
|
||||||
@ -69,19 +71,18 @@ public class AsyncFIFOBusTest extends MessageBusTest {
|
|||||||
messages[i] = i;
|
messages[i] = i;
|
||||||
}
|
}
|
||||||
// publish in ascending order
|
// publish in ascending order
|
||||||
for(Integer message : messages)
|
for(Integer message : messages) {
|
||||||
fifoBUs.post(message).asynchronously();
|
fifoBUs.post(message).asynchronously();
|
||||||
|
}
|
||||||
|
|
||||||
while(fifoBUs.hasPendingMessages())
|
while(fifoBUs.hasPendingMessages()) {
|
||||||
pause(2000);
|
pause(2000);
|
||||||
|
}
|
||||||
|
|
||||||
for(SyncAsyncListener listener : listeners){
|
for(SyncAsyncListener listener : listeners){
|
||||||
assertEquals(messages.length, listener.receivedSync.size());
|
assertEquals(messages.length, listener.receivedSync.size());
|
||||||
assertEquals(listener.receivedSync.size(), listener.receivedAsync.size());
|
for(int i=0; i < messages.length; i++){
|
||||||
for(int i=0; i < listener.receivedAsync.size(); i++){
|
|
||||||
assertEquals(messages[i], listener.receivedSync.get(i));
|
assertEquals(messages[i], listener.receivedSync.get(i));
|
||||||
// sync and async in same order
|
|
||||||
assertEquals(listener.receivedSync.get(i), listener.receivedAsync.get(i));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +138,7 @@ public class AsyncFIFOBusTest extends MessageBusTest {
|
|||||||
|
|
||||||
@Handler
|
@Handler
|
||||||
public void handleSync(Integer message){
|
public void handleSync(Integer message){
|
||||||
receivedSync.add(message);
|
this.receivedSync.add(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -145,18 +146,11 @@ public class AsyncFIFOBusTest extends MessageBusTest {
|
|||||||
public static class SyncAsyncListener {
|
public static class SyncAsyncListener {
|
||||||
|
|
||||||
private List<Integer> receivedSync = new LinkedList<Integer>();
|
private List<Integer> receivedSync = new LinkedList<Integer>();
|
||||||
private List<Integer> receivedAsync = new LinkedList<Integer>();
|
|
||||||
|
|
||||||
@Handler
|
@Handler
|
||||||
public void handleSync(Integer message){
|
public void handleSync(Integer message){
|
||||||
receivedSync.add(message);
|
this.receivedSync.add(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Handler(delivery = Invoke.Asynchronously)
|
|
||||||
public void handleASync(Integer message){
|
|
||||||
receivedAsync.add(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,167 +0,0 @@
|
|||||||
package net.engio.mbassy;
|
|
||||||
|
|
||||||
import net.engio.mbassy.bus.MBassador;
|
|
||||||
import net.engio.mbassy.common.MessageBusTest;
|
|
||||||
import net.engio.mbassy.listener.Enveloped;
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
|
||||||
import net.engio.mbassy.listener.Listener;
|
|
||||||
import net.engio.mbassy.listener.References;
|
|
||||||
import net.engio.mbassy.subscription.MessageEnvelope;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Some unit tests for the "condition" filter.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
public class ConditionalHandlers extends MessageBusTest {
|
|
||||||
|
|
||||||
public static class TestEvent {
|
|
||||||
|
|
||||||
private Set<String> handledBy = new HashSet<String>();
|
|
||||||
private String type;
|
|
||||||
private int size;
|
|
||||||
|
|
||||||
public TestEvent(String type, int size) {
|
|
||||||
super();
|
|
||||||
this.type = type;
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSize() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean wasHandledBy(String ...handlers){
|
|
||||||
for(String handler : handlers){
|
|
||||||
if (!handledBy.contains(handler)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handledBy(String handler){
|
|
||||||
handledBy.add(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Listener(references = References.Strong)
|
|
||||||
public static class ConditionalMessageListener {
|
|
||||||
|
|
||||||
@Handler(condition = "msg.type == 'TEST'")
|
|
||||||
public void handleTypeMessage(TestEvent message) {
|
|
||||||
message.handledBy("handleTypeMessage");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler(condition = "msg.size > 4")
|
|
||||||
public void handleSizeMessage(TestEvent message) {
|
|
||||||
message.handledBy("handleSizeMessage");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler(condition = "msg.foo > 4")
|
|
||||||
public void handleInvalidEL(TestEvent message) {
|
|
||||||
message.handledBy("handleInvalidEL");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler(condition = "msg.size > 2 && msg.size < 4")
|
|
||||||
public void handleCombinedEL(TestEvent message) {
|
|
||||||
message.handledBy( "handleCombinedEL");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler(condition = "msg.getType().equals('XYZ') && msg.getSize() == 1")
|
|
||||||
public void handleMethodAccessEL(TestEvent message) {
|
|
||||||
message.handledBy("handleMethodAccessEL");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler(condition = "msg.type == 'TEST'")
|
|
||||||
@Enveloped(messages = {TestEvent.class, Object.class})
|
|
||||||
public void handleEnvelopedMessage(MessageEnvelope envelope) {
|
|
||||||
envelope.<TestEvent>getMessage().handledBy("handleEnvelopedMessage");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* @throws Exception
|
|
||||||
************************************************************************/
|
|
||||||
@Test
|
|
||||||
public void testSimpleStringCondition() throws Exception {
|
|
||||||
MBassador bus = createBus(SyncAsync());
|
|
||||||
bus.subscribe(new ConditionalMessageListener());
|
|
||||||
|
|
||||||
TestEvent message = new TestEvent("TEST", 0);
|
|
||||||
bus.publish(message);
|
|
||||||
|
|
||||||
assertTrue(message.wasHandledBy("handleTypeMessage", "handleEnvelopedMessage"));
|
|
||||||
assertFalse(message.wasHandledBy("handleInvalidEL"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* @throws Exception
|
|
||||||
************************************************************************/
|
|
||||||
@Test
|
|
||||||
public void testSimpleNumberCondition() throws Exception {
|
|
||||||
MBassador bus = new MBassador();
|
|
||||||
bus.subscribe(new ConditionalMessageListener());
|
|
||||||
|
|
||||||
TestEvent message = new TestEvent("", 5);
|
|
||||||
bus.publish(message);
|
|
||||||
|
|
||||||
assertTrue(message.wasHandledBy("handleSizeMessage"));
|
|
||||||
assertFalse(message.wasHandledBy("handleInvalidEL"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* @throws Exception
|
|
||||||
************************************************************************/
|
|
||||||
@Test
|
|
||||||
public void testHandleCombinedEL() throws Exception {
|
|
||||||
MBassador bus = createBus(SyncAsync());
|
|
||||||
bus.subscribe(new ConditionalMessageListener());
|
|
||||||
|
|
||||||
TestEvent message = new TestEvent("", 3);
|
|
||||||
bus.publish(message);
|
|
||||||
|
|
||||||
assertTrue(message.wasHandledBy("handleCombinedEL"));
|
|
||||||
assertFalse(message.wasHandledBy("handleInvalidEL"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* @throws Exception
|
|
||||||
************************************************************************/
|
|
||||||
@Test
|
|
||||||
public void testNotMatchingAnyCondition() throws Exception {
|
|
||||||
MBassador bus = createBus(SyncAsync());
|
|
||||||
bus.subscribe(new ConditionalMessageListener());
|
|
||||||
|
|
||||||
TestEvent message = new TestEvent("", 0);
|
|
||||||
bus.publish(message);
|
|
||||||
|
|
||||||
assertTrue(message.handledBy.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* @throws Exception
|
|
||||||
************************************************************************/
|
|
||||||
@Test
|
|
||||||
public void testHandleMethodAccessEL() throws Exception {
|
|
||||||
MBassador bus = createBus(SyncAsync());
|
|
||||||
bus.subscribe(new ConditionalMessageListener());
|
|
||||||
|
|
||||||
TestEvent message = new TestEvent("XYZ", 1);
|
|
||||||
bus.publish(message);
|
|
||||||
|
|
||||||
assertTrue(message.wasHandledBy("handleMethodAccessEL"));
|
|
||||||
assertFalse(message.wasHandledBy("handleInvalidEL"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,15 +1,19 @@
|
|||||||
package net.engio.mbassy;
|
package net.engio.mbassy;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Inherited;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.MBassador;
|
import net.engio.mbassy.bus.MBassador;
|
||||||
import net.engio.mbassy.common.MessageBusTest;
|
import net.engio.mbassy.common.MessageBusTest;
|
||||||
import net.engio.mbassy.listener.*;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.subscription.MessageEnvelope;
|
import net.engio.mbassy.listener.Synchronized;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
import org.junit.Test;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests a custom handler annotation with a @Handler meta annotation and a default filter.
|
* Tests a custom handler annotation with a @Handler meta annotation and a default filter.
|
||||||
@ -22,7 +26,7 @@ public class CustomHandlerAnnotationTest extends MessageBusTest
|
|||||||
*/
|
*/
|
||||||
@Retention(value = RetentionPolicy.RUNTIME)
|
@Retention(value = RetentionPolicy.RUNTIME)
|
||||||
@Inherited
|
@Inherited
|
||||||
@Handler(filters = { @Filter(NamedMessageFilter.class) })
|
@Handler()
|
||||||
@Synchronized
|
@Synchronized
|
||||||
@Target(value = { ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
@Target(value = { ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||||
static @interface NamedMessageHandler
|
static @interface NamedMessageHandler
|
||||||
@ -50,8 +54,7 @@ public class CustomHandlerAnnotationTest extends MessageBusTest
|
|||||||
@Retention(value = RetentionPolicy.RUNTIME)
|
@Retention(value = RetentionPolicy.RUNTIME)
|
||||||
@Target(value = { ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
@Target(value = { ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||||
@Inherited
|
@Inherited
|
||||||
@Handler(filters = { @Filter(NamedMessageFilter.class) })
|
@Handler()
|
||||||
@Enveloped(messages = NamedMessage.class)
|
|
||||||
static @interface EnvelopedNamedMessageHandler
|
static @interface EnvelopedNamedMessageHandler
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -60,25 +63,6 @@ public class CustomHandlerAnnotationTest extends MessageBusTest
|
|||||||
String[] value();
|
String[] value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches for a NamedMessageHandler annotation on the handler method.
|
|
||||||
* The annotation specifies the supported message names.
|
|
||||||
*/
|
|
||||||
public static class NamedMessageFilter implements IMessageFilter<NamedMessage>
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean accepts( NamedMessage message, MessageHandler metadata ) {
|
|
||||||
NamedMessageHandler namedMessageHandler = metadata.getAnnotation(NamedMessageHandler.class);
|
|
||||||
if ( namedMessageHandler != null ) {
|
|
||||||
return Arrays.asList( namedMessageHandler.value() ).contains( message.getName() );
|
|
||||||
}
|
|
||||||
|
|
||||||
EnvelopedNamedMessageHandler envelopedHandler = metadata.getAnnotation(EnvelopedNamedMessageHandler.class);
|
|
||||||
return envelopedHandler != null && Arrays.asList( envelopedHandler.value() ).contains( message.getName() );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class NamedMessage
|
static class NamedMessage
|
||||||
{
|
{
|
||||||
private String name;
|
private String name;
|
||||||
@ -88,7 +72,7 @@ public class CustomHandlerAnnotationTest extends MessageBusTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return this.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,17 +84,12 @@ public class CustomHandlerAnnotationTest extends MessageBusTest
|
|||||||
|
|
||||||
@NamedMessageHandler({ "messageOne", "messageTwo" })
|
@NamedMessageHandler({ "messageOne", "messageTwo" })
|
||||||
void handlerOne( NamedMessage message ) {
|
void handlerOne( NamedMessage message ) {
|
||||||
handledByOne.add( message );
|
this.handledByOne.add( message );
|
||||||
}
|
|
||||||
|
|
||||||
@EnvelopedNamedMessageHandler({ "messageTwo", "messageThree" })
|
|
||||||
void handlerTwo( MessageEnvelope envelope ) {
|
|
||||||
handledByTwo.add( (NamedMessage) envelope.getMessage() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@MessageThree
|
@MessageThree
|
||||||
void handlerThree( NamedMessage message ) {
|
void handlerThree( NamedMessage message ) {
|
||||||
handledByThree.add( message );
|
this.handledByThree.add( message );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package net.engio.mbassy;
|
package net.engio.mbassy;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.MBassador;
|
import net.engio.mbassy.bus.MBassador;
|
||||||
import net.engio.mbassy.bus.common.DeadMessage;
|
import net.engio.mbassy.bus.common.DeadMessage;
|
||||||
import net.engio.mbassy.common.ConcurrentExecutor;
|
import net.engio.mbassy.common.ConcurrentExecutor;
|
||||||
@ -10,11 +12,10 @@ import net.engio.mbassy.listener.Handler;
|
|||||||
import net.engio.mbassy.listeners.IMessageListener;
|
import net.engio.mbassy.listeners.IMessageListener;
|
||||||
import net.engio.mbassy.listeners.MessagesListener;
|
import net.engio.mbassy.listeners.MessagesListener;
|
||||||
import net.engio.mbassy.listeners.ObjectListener;
|
import net.engio.mbassy.listeners.ObjectListener;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify correct behaviour in case of message publications that do not have any matching subscriptions
|
* Verify correct behaviour in case of message publications that do not have any matching subscriptions
|
||||||
*
|
*
|
||||||
@ -23,6 +24,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
*/
|
*/
|
||||||
public class DeadMessageTest extends MessageBusTest{
|
public class DeadMessageTest extends MessageBusTest{
|
||||||
|
|
||||||
|
@Override
|
||||||
@Before
|
@Before
|
||||||
public void beforeTest(){
|
public void beforeTest(){
|
||||||
DeadMessagHandler.deadMessages.set(0);
|
DeadMessagHandler.deadMessages.set(0);
|
||||||
@ -34,10 +36,8 @@ public class DeadMessageTest extends MessageBusTest{
|
|||||||
final MBassador bus = createBus(SyncAsync());
|
final MBassador bus = createBus(SyncAsync());
|
||||||
ListenerFactory listeners = new ListenerFactory()
|
ListenerFactory listeners = new ListenerFactory()
|
||||||
.create(InstancesPerListener, IMessageListener.DefaultListener.class)
|
.create(InstancesPerListener, IMessageListener.DefaultListener.class)
|
||||||
.create(InstancesPerListener, IMessageListener.AsyncListener.class)
|
|
||||||
.create(InstancesPerListener, IMessageListener.DisabledListener.class)
|
.create(InstancesPerListener, IMessageListener.DisabledListener.class)
|
||||||
.create(InstancesPerListener, MessagesListener.DefaultListener.class)
|
.create(InstancesPerListener, MessagesListener.DefaultListener.class)
|
||||||
.create(InstancesPerListener, MessagesListener.AsyncListener.class)
|
|
||||||
.create(InstancesPerListener, MessagesListener.DisabledListener.class)
|
.create(InstancesPerListener, MessagesListener.DisabledListener.class)
|
||||||
.create(InstancesPerListener, DeadMessagHandler.class)
|
.create(InstancesPerListener, DeadMessagHandler.class)
|
||||||
.create(InstancesPerListener, Object.class);
|
.create(InstancesPerListener, Object.class);
|
||||||
|
@ -1,150 +0,0 @@
|
|||||||
package net.engio.mbassy;
|
|
||||||
|
|
||||||
import net.engio.mbassy.bus.MBassador;
|
|
||||||
import net.engio.mbassy.bus.common.DeadMessage;
|
|
||||||
import net.engio.mbassy.bus.common.FilteredMessage;
|
|
||||||
import net.engio.mbassy.common.ListenerFactory;
|
|
||||||
import net.engio.mbassy.common.MessageBusTest;
|
|
||||||
import net.engio.mbassy.common.TestUtil;
|
|
||||||
import net.engio.mbassy.listener.*;
|
|
||||||
import net.engio.mbassy.messages.SubTestMessage;
|
|
||||||
import net.engio.mbassy.messages.TestMessage;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Testing of filter functionality
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 11/26/12
|
|
||||||
*/
|
|
||||||
public class FilterTest extends MessageBusTest {
|
|
||||||
|
|
||||||
private static final AtomicInteger FilteredEventCounter = new AtomicInteger(0);
|
|
||||||
private static final AtomicInteger DeadEventCounter = new AtomicInteger(0);
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSubclassFilter() throws Exception {
|
|
||||||
FilteredEventCounter.set(0);
|
|
||||||
DeadEventCounter.set(0);
|
|
||||||
|
|
||||||
MBassador bus = createBus(SyncAsync());
|
|
||||||
ListenerFactory listenerFactory = new ListenerFactory()
|
|
||||||
.create(100, FilteredMessageListener.class);
|
|
||||||
|
|
||||||
List<Object> listeners = listenerFactory.getAll();
|
|
||||||
|
|
||||||
// this will subscribe the listeners concurrently to the bus
|
|
||||||
TestUtil.setup(bus, listeners, 10);
|
|
||||||
|
|
||||||
TestMessage message = new TestMessage();
|
|
||||||
TestMessage subTestMessage = new SubTestMessage();
|
|
||||||
|
|
||||||
bus.post(message).now();
|
|
||||||
bus.post(subTestMessage).now();
|
|
||||||
|
|
||||||
assertEquals(100, message.counter.get());
|
|
||||||
assertEquals(0, subTestMessage.counter.get());
|
|
||||||
assertEquals(100, FilteredEventCounter.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFilteredFilteredEvent() throws Exception {
|
|
||||||
FilteredEventCounter.set(0);
|
|
||||||
DeadEventCounter.set(0);
|
|
||||||
|
|
||||||
MBassador bus = createBus(SyncAsync());
|
|
||||||
ListenerFactory listenerFactory = new ListenerFactory()
|
|
||||||
.create(100, FilteredMessageListener.class);
|
|
||||||
|
|
||||||
List<Object> listeners = listenerFactory.getAll();
|
|
||||||
|
|
||||||
// this will subscribe the listeners concurrently to the bus
|
|
||||||
TestUtil.setup(bus, listeners, 10);
|
|
||||||
|
|
||||||
bus.post(new Object()).now();
|
|
||||||
bus.post(new SubTestMessage()).now();
|
|
||||||
|
|
||||||
assertEquals(100, FilteredEventCounter.get()); // the SubTestMessage should have been republished as a filtered event
|
|
||||||
assertEquals(100, DeadEventCounter.get()); // Object.class was filtered and the fil
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class FilteredMessageListener{
|
|
||||||
|
|
||||||
// NOTE: Use rejectSubtypes property of @Handler to achieve the same functionality but with better performance
|
|
||||||
// and more concise syntax
|
|
||||||
@Handler(filters = {@Filter(Filters.RejectSubtypes.class)})
|
|
||||||
public void handleTestMessage(TestMessage message){
|
|
||||||
message.counter.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FilteredEvents that contain messages of class Object will be filtered (again) and should cause a DeadEvent to be thrown
|
|
||||||
@Handler(filters = {@Filter(RejectFilteredObjects.class)})
|
|
||||||
public void handleFilteredEvent(FilteredMessage filtered){
|
|
||||||
FilteredEventCounter.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
// will cause republication of a FilteredEvent
|
|
||||||
@Handler(filters = {@Filter(RejectAll.class)})
|
|
||||||
public void handleNone(Object any){
|
|
||||||
FilteredEventCounter.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
// will cause republication of a FilteredEvent
|
|
||||||
@Handler
|
|
||||||
public void handleDead(DeadMessage dead){
|
|
||||||
DeadEventCounter.incrementAndGet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSubtypesOnly(){
|
|
||||||
MBassador bus = createBus(SyncAsync());
|
|
||||||
ListenerFactory listeners = new ListenerFactory()
|
|
||||||
.create(100, TestMessageHandler.class);
|
|
||||||
|
|
||||||
// this will subscribe the listeners concurrently to the bus
|
|
||||||
TestUtil.setup(bus, listeners, 10);
|
|
||||||
|
|
||||||
TestMessage supertype = new TestMessage();
|
|
||||||
TestMessage subtype = new SubTestMessage();
|
|
||||||
|
|
||||||
bus.publish(supertype);
|
|
||||||
bus.publish(subtype);
|
|
||||||
|
|
||||||
assertEquals(100, subtype.counter.get());
|
|
||||||
assertEquals(0, supertype.counter.get());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TestMessageHandler{
|
|
||||||
|
|
||||||
@Handler(filters = @Filter(Filters.SubtypesOnly.class))
|
|
||||||
public void handle(TestMessage message){
|
|
||||||
message.counter.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class RejectFilteredObjects implements IMessageFilter{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean accepts(Object message, MessageHandler metadata) {
|
|
||||||
if(message.getClass().equals(FilteredMessage.class) && ((FilteredMessage)message).getMessage().getClass().equals(Object.class)){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class RejectAll implements IMessageFilter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean accepts(Object event, MessageHandler metadata) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,17 +1,24 @@
|
|||||||
package net.engio.mbassy;
|
package net.engio.mbassy;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.MBassador;
|
import net.engio.mbassy.bus.MBassador;
|
||||||
import net.engio.mbassy.bus.config.BusConfiguration;
|
|
||||||
import net.engio.mbassy.bus.error.IPublicationErrorHandler;
|
import net.engio.mbassy.bus.error.IPublicationErrorHandler;
|
||||||
import net.engio.mbassy.bus.error.PublicationError;
|
import net.engio.mbassy.bus.error.PublicationError;
|
||||||
import net.engio.mbassy.common.*;
|
import net.engio.mbassy.common.ConcurrentExecutor;
|
||||||
import net.engio.mbassy.listeners.*;
|
import net.engio.mbassy.common.ListenerFactory;
|
||||||
|
import net.engio.mbassy.common.MessageBusTest;
|
||||||
|
import net.engio.mbassy.common.MessageManager;
|
||||||
|
import net.engio.mbassy.common.TestUtil;
|
||||||
|
import net.engio.mbassy.listeners.ExceptionThrowingListener;
|
||||||
|
import net.engio.mbassy.listeners.IMessageListener;
|
||||||
|
import net.engio.mbassy.listeners.Listeners;
|
||||||
|
import net.engio.mbassy.listeners.MessagesListener;
|
||||||
import net.engio.mbassy.messages.MessageTypes;
|
import net.engio.mbassy.messages.MessageTypes;
|
||||||
import net.engio.mbassy.messages.MultipartMessage;
|
import net.engio.mbassy.messages.MultipartMessage;
|
||||||
import net.engio.mbassy.messages.StandardMessage;
|
import net.engio.mbassy.messages.StandardMessage;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test synchronous and asynchronous dispatch in single and multi-threaded scenario.
|
* Test synchronous and asynchronous dispatch in single and multi-threaded scenario.
|
||||||
@ -57,42 +64,10 @@ public class MBassadorTest extends MessageBusTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSyncPublicationAsyncHandlers() throws Exception {
|
|
||||||
ListenerFactory listeners = new ListenerFactory()
|
|
||||||
.create(InstancesPerListener, Listeners.asynchronous())
|
|
||||||
.create(InstancesPerListener, Listeners.noHandlers());
|
|
||||||
final MBassador bus = createBus(SyncAsync(), listeners);
|
|
||||||
|
|
||||||
final MessageManager messageManager = new MessageManager();
|
|
||||||
Runnable publishAndCheck = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
|
|
||||||
StandardMessage standardMessage = messageManager.create(StandardMessage.class, InstancesPerListener, Listeners.join(Listeners.asynchronous(), Listeners.handlesStandardMessage()));
|
|
||||||
MultipartMessage multipartMessage = messageManager.create(MultipartMessage.class, InstancesPerListener, IMessageListener.AsyncListener.class, IMultipartMessageListener.AsyncListener.class);
|
|
||||||
|
|
||||||
bus.post(standardMessage).now();
|
|
||||||
bus.post(multipartMessage).now();
|
|
||||||
bus.post(MessageTypes.Simple).now();
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ConcurrentExecutor.runConcurrent(publishAndCheck, 1);
|
|
||||||
messageManager.waitForMessages(processingTimeInMS);
|
|
||||||
|
|
||||||
MessageTypes.resetAll();
|
|
||||||
messageManager.register(MessageTypes.Simple, InstancesPerListener * ConcurrentUnits, IMessageListener.AsyncListener.class, MessagesListener.AsyncListener.class);
|
|
||||||
ConcurrentExecutor.runConcurrent(publishAndCheck, ConcurrentUnits);
|
|
||||||
messageManager.waitForMessages(processingTimeInMS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAsynchronousMessagePublication() throws Exception {
|
public void testAsynchronousMessagePublication() throws Exception {
|
||||||
|
|
||||||
ListenerFactory listeners = new ListenerFactory()
|
ListenerFactory listeners = new ListenerFactory()
|
||||||
.create(InstancesPerListener, Listeners.asynchronous())
|
|
||||||
.create(InstancesPerListener, Listeners.noHandlers());
|
.create(InstancesPerListener, Listeners.noHandlers());
|
||||||
final MBassador bus = createBus(SyncAsync(), listeners);
|
final MBassador bus = createBus(SyncAsync(), listeners);
|
||||||
|
|
||||||
@ -102,11 +77,7 @@ public class MBassadorTest extends MessageBusTest {
|
|||||||
Runnable publishAndCheck = new Runnable() {
|
Runnable publishAndCheck = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
StandardMessage standardMessage = messageManager.create(StandardMessage.class, InstancesPerListener, IMessageListener.AsyncListener.class);
|
|
||||||
MultipartMessage multipartMessage = messageManager.create(MultipartMessage.class, InstancesPerListener, IMessageListener.AsyncListener.class);
|
|
||||||
|
|
||||||
bus.post(standardMessage).asynchronously();
|
|
||||||
bus.post(multipartMessage).asynchronously();
|
|
||||||
bus.post(MessageTypes.Simple).asynchronously();
|
bus.post(MessageTypes.Simple).asynchronously();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
package net.engio.mbassy;
|
package net.engio.mbassy;
|
||||||
|
|
||||||
import net.engio.mbassy.common.AssertSupport;
|
|
||||||
import net.engio.mbassy.listener.MessageListener;
|
|
||||||
import org.junit.Test;
|
|
||||||
import net.engio.mbassy.listener.Enveloped;
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
|
||||||
import net.engio.mbassy.listener.MetadataReader;
|
|
||||||
import net.engio.mbassy.subscription.MessageEnvelope;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static net.engio.mbassy.listener.MessageListener.ForMessage;
|
import net.engio.mbassy.common.AssertSupport;
|
||||||
|
import net.engio.mbassy.listener.Handler;
|
||||||
|
import net.engio.mbassy.listener.MessageListener;
|
||||||
|
import net.engio.mbassy.listener.MetadataReader;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -26,7 +22,7 @@ public class MetadataReaderTest extends AssertSupport {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListenerWithoutInheritance() {
|
public void testListenerWithoutInheritance() {
|
||||||
MessageListener<MessageListener1> listener = reader.getMessageListener(MessageListener1.class);
|
MessageListener listener = this.reader.getMessageListener(MessageListener1.class);
|
||||||
ListenerValidator validator = new ListenerValidator()
|
ListenerValidator validator = new ListenerValidator()
|
||||||
.expectHandlers(2, String.class)
|
.expectHandlers(2, String.class)
|
||||||
.expectHandlers(2, Object.class)
|
.expectHandlers(2, Object.class)
|
||||||
@ -45,7 +41,7 @@ public class MetadataReaderTest extends AssertSupport {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListenerWithInheritance() {
|
public void testListenerWithInheritance() {
|
||||||
MessageListener<MessageListener2> listener = reader.getMessageListener(MessageListener2.class);
|
MessageListener listener = this.reader.getMessageListener(MessageListener2.class);
|
||||||
ListenerValidator validator = new ListenerValidator()
|
ListenerValidator validator = new ListenerValidator()
|
||||||
.expectHandlers(2, String.class)
|
.expectHandlers(2, String.class)
|
||||||
.expectHandlers(2, Object.class)
|
.expectHandlers(2, Object.class)
|
||||||
@ -55,7 +51,7 @@ public class MetadataReaderTest extends AssertSupport {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListenerWithInheritanceOverriding() {
|
public void testListenerWithInheritanceOverriding() {
|
||||||
MessageListener<MessageListener3> listener = reader.getMessageListener(MessageListener3.class);
|
MessageListener listener = this.reader.getMessageListener(MessageListener3.class);
|
||||||
|
|
||||||
ListenerValidator validator = new ListenerValidator()
|
ListenerValidator validator = new ListenerValidator()
|
||||||
.expectHandlers(0, String.class)
|
.expectHandlers(0, String.class)
|
||||||
@ -64,53 +60,26 @@ public class MetadataReaderTest extends AssertSupport {
|
|||||||
validator.check(listener);
|
validator.check(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEnveloped() {
|
|
||||||
MessageListener<EnvelopedListener> listener = reader.getMessageListener(EnvelopedListener.class);
|
|
||||||
ListenerValidator validator = new ListenerValidator()
|
|
||||||
.expectHandlers(1, String.class)
|
|
||||||
.expectHandlers(2, Integer.class)
|
|
||||||
.expectHandlers(2, Long.class)
|
|
||||||
.expectHandlers(1, Double.class)
|
|
||||||
.expectHandlers(1, Number.class)
|
|
||||||
.expectHandlers(0, List.class);
|
|
||||||
validator.check(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEnvelopedSubclass() {
|
|
||||||
MessageListener<EnvelopedListenerSubclass> listener = reader.getMessageListener(EnvelopedListenerSubclass.class);
|
|
||||||
ListenerValidator validator = new ListenerValidator()
|
|
||||||
.expectHandlers(1, String.class)
|
|
||||||
.expectHandlers(2, Integer.class)
|
|
||||||
.expectHandlers(1, Long.class)
|
|
||||||
.expectHandlers(0, Double.class)
|
|
||||||
.expectHandlers(0, Number.class);
|
|
||||||
validator.check(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class ListenerValidator {
|
private class ListenerValidator {
|
||||||
|
|
||||||
private Map<Class<?>, Integer> handlers = new HashMap<Class<?>, Integer>();
|
private Map<Class<?>, Integer> handlers = new HashMap<Class<?>, Integer>();
|
||||||
|
|
||||||
public ListenerValidator expectHandlers(Integer count, Class<?> messageType){
|
public ListenerValidator expectHandlers(Integer count, Class<?> messageType){
|
||||||
handlers.put(messageType, count);
|
this.handlers.put(messageType, count);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void check(MessageListener listener){
|
public void check(MessageListener listener){
|
||||||
for(Map.Entry<Class<?>, Integer> expectedHandler: handlers.entrySet()){
|
for(Map.Entry<Class<?>, Integer> expectedHandler: this.handlers.entrySet()){
|
||||||
if(expectedHandler.getValue() > 0){
|
if(expectedHandler.getValue() > 0){
|
||||||
assertTrue(listener.handles(expectedHandler.getKey()));
|
assertTrue(listener.handles(expectedHandler.getKey()));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
assertFalse(listener.handles(expectedHandler.getKey()));
|
assertFalse(listener.handles(expectedHandler.getKey()));
|
||||||
}
|
}
|
||||||
assertEquals(expectedHandler.getValue(), listener.getHandlers(ForMessage(expectedHandler.getKey())).size());
|
assertEquals(expectedHandler.getValue(), listener.getHandlers(expectedHandler.getKey()).size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -141,6 +110,7 @@ public class MetadataReaderTest extends AssertSupport {
|
|||||||
public class MessageListener2 extends MessageListener1 {
|
public class MessageListener2 extends MessageListener1 {
|
||||||
|
|
||||||
// redefine handler implementation (not configuration)
|
// redefine handler implementation (not configuration)
|
||||||
|
@Override
|
||||||
public void handleString(String s) {
|
public void handleString(String s) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -150,59 +120,17 @@ public class MetadataReaderTest extends AssertSupport {
|
|||||||
public class MessageListener3 extends MessageListener2 {
|
public class MessageListener3 extends MessageListener2 {
|
||||||
|
|
||||||
// narrow the handler
|
// narrow the handler
|
||||||
|
@Override
|
||||||
@Handler(rejectSubtypes = true)
|
@Handler(rejectSubtypes = true)
|
||||||
public void handleAny(Object o) {
|
public void handleAny(Object o) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(enabled = false)
|
@Handler(enabled = false)
|
||||||
public void handleString(String s) {
|
public void handleString(String s) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EnvelopedListener{
|
|
||||||
|
|
||||||
|
|
||||||
@Handler(rejectSubtypes = true)
|
|
||||||
@Enveloped(messages = {String.class, Integer.class, Long.class})
|
|
||||||
public void handleEnveloped(MessageEnvelope o) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler
|
|
||||||
@Enveloped(messages = Number.class)
|
|
||||||
public void handleEnveloped2(MessageEnvelope o) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EnvelopedListenerSubclass extends EnvelopedListener{
|
|
||||||
|
|
||||||
// narrow to integer
|
|
||||||
@Handler
|
|
||||||
@Enveloped(messages = Integer.class)
|
|
||||||
public void handleEnveloped2(MessageEnvelope o) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static interface ListenerInterface{
|
|
||||||
|
|
||||||
@Handler
|
|
||||||
@Enveloped(messages = Object.class)
|
|
||||||
void handle(MessageEnvelope envelope);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class InterfacedListener implements ListenerInterface{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(MessageEnvelope envelope) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
package net.engio.mbassy;
|
|
||||||
|
|
||||||
import net.engio.mbassy.common.IConcurrentSet;
|
|
||||||
import net.engio.mbassy.common.StrongConcurrentSet;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Todo: Add javadoc
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 3/29/13
|
|
||||||
*/
|
|
||||||
public class StrongConcurrentSetTest extends ConcurrentSetTest{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IConcurrentSet createSet() {
|
|
||||||
return new StrongConcurrentSet();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,33 @@
|
|||||||
package net.engio.mbassy;
|
package net.engio.mbassy;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.BusRuntime;
|
import net.engio.mbassy.bus.BusRuntime;
|
||||||
import net.engio.mbassy.common.*;
|
import net.engio.mbassy.common.AssertSupport;
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.common.ConcurrentExecutor;
|
||||||
|
import net.engio.mbassy.common.ListenerFactory;
|
||||||
|
import net.engio.mbassy.common.SubscriptionValidator;
|
||||||
|
import net.engio.mbassy.common.TestUtil;
|
||||||
import net.engio.mbassy.listener.MetadataReader;
|
import net.engio.mbassy.listener.MetadataReader;
|
||||||
import net.engio.mbassy.listeners.*;
|
import net.engio.mbassy.listeners.AbstractMessageListener;
|
||||||
import net.engio.mbassy.messages.*;
|
import net.engio.mbassy.listeners.ICountableListener;
|
||||||
import net.engio.mbassy.subscription.Subscription;
|
import net.engio.mbassy.listeners.IMessageListener;
|
||||||
|
import net.engio.mbassy.listeners.IMultipartMessageListener;
|
||||||
|
import net.engio.mbassy.listeners.MessagesListener;
|
||||||
|
import net.engio.mbassy.listeners.MultipartMessageListener;
|
||||||
|
import net.engio.mbassy.listeners.Overloading;
|
||||||
|
import net.engio.mbassy.listeners.StandardMessageListener;
|
||||||
|
import net.engio.mbassy.messages.AbstractMessage;
|
||||||
|
import net.engio.mbassy.messages.ICountable;
|
||||||
|
import net.engio.mbassy.messages.IMessage;
|
||||||
|
import net.engio.mbassy.messages.IMultipartMessage;
|
||||||
|
import net.engio.mbassy.messages.MessageTypes;
|
||||||
|
import net.engio.mbassy.messages.MultipartMessage;
|
||||||
|
import net.engio.mbassy.messages.StandardMessage;
|
||||||
import net.engio.mbassy.subscription.SubscriptionFactory;
|
import net.engio.mbassy.subscription.SubscriptionFactory;
|
||||||
import net.engio.mbassy.subscription.SubscriptionManager;
|
import net.engio.mbassy.subscription.SubscriptionManager;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import org.junit.Test;
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -32,15 +47,12 @@ public class SubscriptionManagerTest extends AssertSupport {
|
|||||||
public void testIMessageListener(){
|
public void testIMessageListener(){
|
||||||
ListenerFactory listeners = listeners(
|
ListenerFactory listeners = listeners(
|
||||||
IMessageListener.DefaultListener.class,
|
IMessageListener.DefaultListener.class,
|
||||||
IMessageListener.AsyncListener.class,
|
|
||||||
IMessageListener.DisabledListener.class,
|
IMessageListener.DisabledListener.class,
|
||||||
IMessageListener.NoSubtypesListener.class);
|
IMessageListener.NoSubtypesListener.class);
|
||||||
|
|
||||||
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
||||||
.listener(IMessageListener.DefaultListener.class).handles(IMessage.class,
|
.listener(IMessageListener.DefaultListener.class).handles(IMessage.class,
|
||||||
AbstractMessage.class, IMultipartMessage.class, StandardMessage.class, MessageTypes.class)
|
AbstractMessage.class, IMultipartMessage.class, StandardMessage.class, MessageTypes.class)
|
||||||
.listener(IMessageListener.AsyncListener.class).handles(IMessage.class,
|
|
||||||
AbstractMessage.class, IMultipartMessage.class, StandardMessage.class, MessageTypes.class)
|
|
||||||
.listener(IMessageListener.NoSubtypesListener.class).handles(IMessage.class);
|
.listener(IMessageListener.NoSubtypesListener.class).handles(IMessage.class);
|
||||||
|
|
||||||
runTestWith(listeners, expectedSubscriptions);
|
runTestWith(listeners, expectedSubscriptions);
|
||||||
@ -50,14 +62,12 @@ public class SubscriptionManagerTest extends AssertSupport {
|
|||||||
public void testAbstractMessageListener(){
|
public void testAbstractMessageListener(){
|
||||||
ListenerFactory listeners = listeners(
|
ListenerFactory listeners = listeners(
|
||||||
AbstractMessageListener.DefaultListener.class,
|
AbstractMessageListener.DefaultListener.class,
|
||||||
AbstractMessageListener.AsyncListener.class,
|
|
||||||
AbstractMessageListener.DisabledListener.class,
|
AbstractMessageListener.DisabledListener.class,
|
||||||
AbstractMessageListener.NoSubtypesListener.class);
|
AbstractMessageListener.NoSubtypesListener.class);
|
||||||
|
|
||||||
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
||||||
.listener(AbstractMessageListener.NoSubtypesListener.class).handles(AbstractMessage.class)
|
.listener(AbstractMessageListener.NoSubtypesListener.class).handles(AbstractMessage.class)
|
||||||
.listener(AbstractMessageListener.DefaultListener.class).handles(StandardMessage.class, AbstractMessage.class)
|
.listener(AbstractMessageListener.DefaultListener.class).handles(StandardMessage.class, AbstractMessage.class);
|
||||||
.listener(AbstractMessageListener.AsyncListener.class).handles(StandardMessage.class, AbstractMessage.class);
|
|
||||||
|
|
||||||
runTestWith(listeners, expectedSubscriptions);
|
runTestWith(listeners, expectedSubscriptions);
|
||||||
}
|
}
|
||||||
@ -66,14 +76,12 @@ public class SubscriptionManagerTest extends AssertSupport {
|
|||||||
public void testMessagesListener(){
|
public void testMessagesListener(){
|
||||||
ListenerFactory listeners = listeners(
|
ListenerFactory listeners = listeners(
|
||||||
MessagesListener.DefaultListener.class,
|
MessagesListener.DefaultListener.class,
|
||||||
MessagesListener.AsyncListener.class,
|
|
||||||
MessagesListener.DisabledListener.class,
|
MessagesListener.DisabledListener.class,
|
||||||
MessagesListener.NoSubtypesListener.class);
|
MessagesListener.NoSubtypesListener.class);
|
||||||
|
|
||||||
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
||||||
.listener(MessagesListener.NoSubtypesListener.class).handles(MessageTypes.class)
|
.listener(MessagesListener.NoSubtypesListener.class).handles(MessageTypes.class)
|
||||||
.listener(MessagesListener.DefaultListener.class).handles(MessageTypes.class)
|
.listener(MessagesListener.DefaultListener.class).handles(MessageTypes.class);
|
||||||
.listener(MessagesListener.AsyncListener.class).handles(MessageTypes.class);
|
|
||||||
|
|
||||||
runTestWith(listeners, expectedSubscriptions);
|
runTestWith(listeners, expectedSubscriptions);
|
||||||
}
|
}
|
||||||
@ -82,14 +90,12 @@ public class SubscriptionManagerTest extends AssertSupport {
|
|||||||
public void testMultipartMessageListener(){
|
public void testMultipartMessageListener(){
|
||||||
ListenerFactory listeners = listeners(
|
ListenerFactory listeners = listeners(
|
||||||
MultipartMessageListener.DefaultListener.class,
|
MultipartMessageListener.DefaultListener.class,
|
||||||
MultipartMessageListener.AsyncListener.class,
|
|
||||||
MultipartMessageListener.DisabledListener.class,
|
MultipartMessageListener.DisabledListener.class,
|
||||||
MultipartMessageListener.NoSubtypesListener.class);
|
MultipartMessageListener.NoSubtypesListener.class);
|
||||||
|
|
||||||
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
||||||
.listener(MultipartMessageListener.NoSubtypesListener.class).handles(MultipartMessage.class)
|
.listener(MultipartMessageListener.NoSubtypesListener.class).handles(MultipartMessage.class)
|
||||||
.listener(MultipartMessageListener.DefaultListener.class).handles(MultipartMessage.class)
|
.listener(MultipartMessageListener.DefaultListener.class).handles(MultipartMessage.class);
|
||||||
.listener(MultipartMessageListener.AsyncListener.class).handles(MultipartMessage.class);
|
|
||||||
|
|
||||||
runTestWith(listeners, expectedSubscriptions);
|
runTestWith(listeners, expectedSubscriptions);
|
||||||
}
|
}
|
||||||
@ -98,14 +104,12 @@ public class SubscriptionManagerTest extends AssertSupport {
|
|||||||
public void testIMultipartMessageListener(){
|
public void testIMultipartMessageListener(){
|
||||||
ListenerFactory listeners = listeners(
|
ListenerFactory listeners = listeners(
|
||||||
IMultipartMessageListener.DefaultListener.class,
|
IMultipartMessageListener.DefaultListener.class,
|
||||||
IMultipartMessageListener.AsyncListener.class,
|
|
||||||
IMultipartMessageListener.DisabledListener.class,
|
IMultipartMessageListener.DisabledListener.class,
|
||||||
IMultipartMessageListener.NoSubtypesListener.class);
|
IMultipartMessageListener.NoSubtypesListener.class);
|
||||||
|
|
||||||
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
||||||
.listener(IMultipartMessageListener.NoSubtypesListener.class).handles(IMultipartMessage.class)
|
.listener(IMultipartMessageListener.NoSubtypesListener.class).handles(IMultipartMessage.class)
|
||||||
.listener(IMultipartMessageListener.DefaultListener.class).handles(MultipartMessage.class, IMultipartMessage.class)
|
.listener(IMultipartMessageListener.DefaultListener.class).handles(MultipartMessage.class, IMultipartMessage.class);
|
||||||
.listener(IMultipartMessageListener.AsyncListener.class).handles(MultipartMessage.class, IMultipartMessage.class);
|
|
||||||
|
|
||||||
runTestWith(listeners, expectedSubscriptions);
|
runTestWith(listeners, expectedSubscriptions);
|
||||||
}
|
}
|
||||||
@ -114,14 +118,12 @@ public class SubscriptionManagerTest extends AssertSupport {
|
|||||||
public void testStandardMessageListener(){
|
public void testStandardMessageListener(){
|
||||||
ListenerFactory listeners = listeners(
|
ListenerFactory listeners = listeners(
|
||||||
StandardMessageListener.DefaultListener.class,
|
StandardMessageListener.DefaultListener.class,
|
||||||
StandardMessageListener.AsyncListener.class,
|
|
||||||
StandardMessageListener.DisabledListener.class,
|
StandardMessageListener.DisabledListener.class,
|
||||||
StandardMessageListener.NoSubtypesListener.class);
|
StandardMessageListener.NoSubtypesListener.class);
|
||||||
|
|
||||||
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
||||||
.listener(StandardMessageListener.NoSubtypesListener.class).handles(StandardMessage.class)
|
.listener(StandardMessageListener.NoSubtypesListener.class).handles(StandardMessage.class)
|
||||||
.listener(StandardMessageListener.DefaultListener.class).handles(StandardMessage.class)
|
.listener(StandardMessageListener.DefaultListener.class).handles(StandardMessage.class);
|
||||||
.listener(StandardMessageListener.AsyncListener.class).handles(StandardMessage.class);
|
|
||||||
|
|
||||||
runTestWith(listeners, expectedSubscriptions);
|
runTestWith(listeners, expectedSubscriptions);
|
||||||
}
|
}
|
||||||
@ -130,14 +132,12 @@ public class SubscriptionManagerTest extends AssertSupport {
|
|||||||
public void testICountableListener(){
|
public void testICountableListener(){
|
||||||
ListenerFactory listeners = listeners(
|
ListenerFactory listeners = listeners(
|
||||||
ICountableListener.DefaultListener.class,
|
ICountableListener.DefaultListener.class,
|
||||||
ICountableListener.AsyncListener.class,
|
|
||||||
ICountableListener.DisabledListener.class,
|
ICountableListener.DisabledListener.class,
|
||||||
ICountableListener.NoSubtypesListener.class);
|
ICountableListener.NoSubtypesListener.class);
|
||||||
|
|
||||||
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
||||||
.listener(ICountableListener.DefaultListener.class).handles(ICountable.class)
|
.listener(ICountableListener.DefaultListener.class).handles(ICountable.class)
|
||||||
.listener(ICountableListener.DefaultListener.class).handles(MultipartMessage.class, IMultipartMessage.class, ICountable.class, StandardMessage.class)
|
.listener(ICountableListener.DefaultListener.class).handles(MultipartMessage.class, IMultipartMessage.class, ICountable.class, StandardMessage.class);
|
||||||
.listener(ICountableListener.AsyncListener.class).handles(MultipartMessage.class, IMultipartMessage.class, ICountable.class, StandardMessage.class);
|
|
||||||
|
|
||||||
runTestWith(listeners, expectedSubscriptions);
|
runTestWith(listeners, expectedSubscriptions);
|
||||||
}
|
}
|
||||||
@ -146,42 +146,20 @@ public class SubscriptionManagerTest extends AssertSupport {
|
|||||||
public void testMultipleMessageListeners(){
|
public void testMultipleMessageListeners(){
|
||||||
ListenerFactory listeners = listeners(
|
ListenerFactory listeners = listeners(
|
||||||
ICountableListener.DefaultListener.class,
|
ICountableListener.DefaultListener.class,
|
||||||
ICountableListener.AsyncListener.class,
|
|
||||||
ICountableListener.DisabledListener.class,
|
ICountableListener.DisabledListener.class,
|
||||||
IMultipartMessageListener.DefaultListener.class,
|
IMultipartMessageListener.DefaultListener.class,
|
||||||
IMultipartMessageListener.AsyncListener.class,
|
|
||||||
IMultipartMessageListener.DisabledListener.class,
|
IMultipartMessageListener.DisabledListener.class,
|
||||||
MessagesListener.DefaultListener.class,
|
MessagesListener.DefaultListener.class,
|
||||||
MessagesListener.AsyncListener.class,
|
|
||||||
MessagesListener.DisabledListener.class);
|
MessagesListener.DisabledListener.class);
|
||||||
|
|
||||||
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
||||||
.listener(ICountableListener.DefaultListener.class)
|
.listener(ICountableListener.DefaultListener.class).handles(MultipartMessage.class, IMultipartMessage.class, ICountable.class, StandardMessage.class)
|
||||||
.handles(MultipartMessage.class, IMultipartMessage.class, ICountable.class, StandardMessage.class)
|
|
||||||
.listener(ICountableListener.AsyncListener.class)
|
|
||||||
.handles(MultipartMessage.class, IMultipartMessage.class, ICountable.class, StandardMessage.class)
|
|
||||||
.listener(IMultipartMessageListener.DefaultListener.class).handles(MultipartMessage.class, IMultipartMessage.class)
|
.listener(IMultipartMessageListener.DefaultListener.class).handles(MultipartMessage.class, IMultipartMessage.class)
|
||||||
.listener(IMultipartMessageListener.AsyncListener.class).handles(MultipartMessage.class, IMultipartMessage.class)
|
.listener(MessagesListener.DefaultListener.class).handles(MessageTypes.class);
|
||||||
.listener(MessagesListener.DefaultListener.class).handles(MessageTypes.class)
|
|
||||||
.listener(MessagesListener.AsyncListener.class).handles(MessageTypes.class);
|
|
||||||
|
|
||||||
runTestWith(listeners, expectedSubscriptions);
|
runTestWith(listeners, expectedSubscriptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStrongListenerSubscription() throws Exception {
|
|
||||||
ListenerFactory listeners = listeners(CustomInvocationListener.class);
|
|
||||||
SubscriptionManager subscriptionManager = new SubscriptionManager(new MetadataReader(), new SubscriptionFactory(), mockedRuntime());
|
|
||||||
ConcurrentExecutor.runConcurrent(TestUtil.subscriber(subscriptionManager, listeners), ConcurrentUnits);
|
|
||||||
|
|
||||||
listeners.clear();
|
|
||||||
runGC();
|
|
||||||
|
|
||||||
Collection<Subscription> subscriptions = subscriptionManager.getSubscriptionsByMessageType(StandardMessage.class);
|
|
||||||
assertEquals(1, subscriptions.size());
|
|
||||||
for(Subscription sub : subscriptions)
|
|
||||||
assertEquals(InstancesPerListener, sub.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOverloadedMessageHandlers(){
|
public void testOverloadedMessageHandlers(){
|
||||||
@ -199,19 +177,6 @@ public class SubscriptionManagerTest extends AssertSupport {
|
|||||||
runTestWith(listeners, expectedSubscriptions);
|
runTestWith(listeners, expectedSubscriptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testPrioritizedMessageHandlers(){
|
|
||||||
ListenerFactory listeners = listeners(PrioritizedListener.class);
|
|
||||||
|
|
||||||
SubscriptionManager subscriptionManager = new SubscriptionManager(new MetadataReader(), new SubscriptionFactory(), mockedRuntime());
|
|
||||||
ConcurrentExecutor.runConcurrent(TestUtil.subscriber(subscriptionManager, listeners), ConcurrentUnits);
|
|
||||||
|
|
||||||
SubscriptionValidator expectedSubscriptions = new SubscriptionValidator(listeners)
|
|
||||||
.listener(PrioritizedListener.class).handles(IMessage.class, IMessage.class, IMessage.class, IMessage.class);
|
|
||||||
|
|
||||||
runTestWith(listeners, expectedSubscriptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private BusRuntime mockedRuntime(){
|
private BusRuntime mockedRuntime(){
|
||||||
return new BusRuntime(null)
|
return new BusRuntime(null)
|
||||||
.add(BusRuntime.Properties.ErrorHandlers, Collections.EMPTY_SET)
|
.add(BusRuntime.Properties.ErrorHandlers, Collections.EMPTY_SET)
|
||||||
@ -241,33 +206,4 @@ public class SubscriptionManagerTest extends AssertSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* define handlers with different priorities which need to be executed
|
|
||||||
* in their respective order
|
|
||||||
*/
|
|
||||||
public static class PrioritizedListener{
|
|
||||||
|
|
||||||
|
|
||||||
@Handler(priority = 1)
|
|
||||||
public void handlePrio1(IMessage message){
|
|
||||||
message.handled(this.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler(priority = 2)
|
|
||||||
public void handlePrio2(IMessage message){
|
|
||||||
message.handled(this.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler(priority = 3)
|
|
||||||
public void handlePrio3(IMessage message){
|
|
||||||
message.handled(this.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler(priority = 4)
|
|
||||||
public void handlePrio4(IMessage message){
|
|
||||||
message.handled(this.getClass());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package net.engio.mbassy;
|
package net.engio.mbassy;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.BusFactory;
|
import net.engio.mbassy.bus.BusFactory;
|
||||||
import net.engio.mbassy.bus.MBassador;
|
import net.engio.mbassy.bus.MBassador;
|
||||||
import net.engio.mbassy.bus.common.GenericMessagePublicationSupport;
|
import net.engio.mbassy.bus.common.GenericMessagePublicationSupport;
|
||||||
@ -9,19 +11,16 @@ import net.engio.mbassy.common.ConcurrentExecutor;
|
|||||||
import net.engio.mbassy.common.ListenerFactory;
|
import net.engio.mbassy.common.ListenerFactory;
|
||||||
import net.engio.mbassy.common.MessageBusTest;
|
import net.engio.mbassy.common.MessageBusTest;
|
||||||
import net.engio.mbassy.common.TestUtil;
|
import net.engio.mbassy.common.TestUtil;
|
||||||
import net.engio.mbassy.listener.Handler;
|
|
||||||
import net.engio.mbassy.listeners.CustomInvocationListener;
|
|
||||||
import net.engio.mbassy.listeners.ExceptionThrowingListener;
|
import net.engio.mbassy.listeners.ExceptionThrowingListener;
|
||||||
import net.engio.mbassy.listeners.IMessageListener;
|
import net.engio.mbassy.listeners.IMessageListener;
|
||||||
import net.engio.mbassy.listeners.MessagesListener;
|
import net.engio.mbassy.listeners.MessagesListener;
|
||||||
import net.engio.mbassy.messages.MessageTypes;
|
import net.engio.mbassy.messages.MessageTypes;
|
||||||
import net.engio.mbassy.messages.MultipartMessage;
|
import net.engio.mbassy.messages.MultipartMessage;
|
||||||
import net.engio.mbassy.messages.StandardMessage;
|
import net.engio.mbassy.messages.StandardMessage;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test synchronous and asynchronous dispatch in single and multi-threaded scenario.
|
* Test synchronous and asynchronous dispatch in single and multi-threaded scenario.
|
||||||
*
|
*
|
||||||
@ -111,66 +110,6 @@ public abstract class SyncBusTest extends MessageBusTest {
|
|||||||
assertEquals(InstancesPerListener * ConcurrentUnits, exceptionCount.get());
|
assertEquals(InstancesPerListener * ConcurrentUnits, exceptionCount.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCustomHandlerInvocation(){
|
|
||||||
final GenericMessagePublicationSupport bus = getSyncMessageBus();
|
|
||||||
ListenerFactory listeners = new ListenerFactory()
|
|
||||||
.create(InstancesPerListener, CustomInvocationListener.class)
|
|
||||||
.create(InstancesPerListener, Object.class);
|
|
||||||
|
|
||||||
|
|
||||||
ConcurrentExecutor.runConcurrent(TestUtil.subscriber(bus, listeners), ConcurrentUnits);
|
|
||||||
|
|
||||||
Runnable publishAndCheck = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
StandardMessage standardMessage = new StandardMessage();
|
|
||||||
MultipartMessage multipartMessage = new MultipartMessage();
|
|
||||||
|
|
||||||
bus.post(standardMessage).now();
|
|
||||||
bus.post(multipartMessage).now();
|
|
||||||
bus.post(MessageTypes.Simple).now();
|
|
||||||
|
|
||||||
assertEquals(InstancesPerListener * 2, standardMessage.getTimesHandled(CustomInvocationListener.class));
|
|
||||||
assertEquals(0, multipartMessage.getTimesHandled(CustomInvocationListener.class));
|
|
||||||
assertEquals(0, MessageTypes.Simple.getTimesHandled(CustomInvocationListener.class));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// single threaded
|
|
||||||
ConcurrentExecutor.runConcurrent(publishAndCheck, 1);
|
|
||||||
|
|
||||||
// multi threaded
|
|
||||||
ConcurrentExecutor.runConcurrent(publishAndCheck, ConcurrentUnits);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHandlerPriorities(){
|
|
||||||
final GenericMessagePublicationSupport bus = getSyncMessageBus();
|
|
||||||
ListenerFactory listeners = new ListenerFactory()
|
|
||||||
.create(InstancesPerListener, PrioritizedListener.class)
|
|
||||||
.create(InstancesPerListener, Object.class);
|
|
||||||
|
|
||||||
ConcurrentExecutor.runConcurrent(TestUtil.subscriber(bus, listeners), ConcurrentUnits);
|
|
||||||
|
|
||||||
Runnable publishAndCheck = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
|
|
||||||
bus.post(new IncrementingMessage()).now();
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// single threaded
|
|
||||||
ConcurrentExecutor.runConcurrent(publishAndCheck, 1);
|
|
||||||
|
|
||||||
// multi threaded
|
|
||||||
ConcurrentExecutor.runConcurrent(publishAndCheck, ConcurrentUnits);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class MBassadorTest extends SyncBusTest {
|
public static class MBassadorTest extends SyncBusTest {
|
||||||
|
|
||||||
@ -199,37 +138,12 @@ public abstract class SyncBusTest extends MessageBusTest {
|
|||||||
|
|
||||||
public void markHandled(int newVal){
|
public void markHandled(int newVal){
|
||||||
// only transitions by the next handler are allowed
|
// only transitions by the next handler are allowed
|
||||||
if(count == newVal || count + 1 == newVal) count = newVal;
|
if(this.count == newVal || this.count + 1 == newVal) {
|
||||||
else Assert.fail("Message was handled out of order");
|
this.count = newVal;
|
||||||
|
} else {
|
||||||
|
Assert.fail("Message was handled out of order");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class PrioritizedListener{
|
|
||||||
|
|
||||||
@Handler(priority = Integer.MIN_VALUE)
|
|
||||||
public void handle1(IncrementingMessage message) {
|
|
||||||
message.markHandled(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler(priority = -2)
|
|
||||||
public void handle2(IncrementingMessage message) {
|
|
||||||
message.markHandled(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler
|
|
||||||
public void handle3(IncrementingMessage message) {
|
|
||||||
message.markHandled(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler(priority = Integer.MAX_VALUE)
|
|
||||||
public void handle4(IncrementingMessage message) {
|
|
||||||
message.markHandled(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
package net.engio.mbassy;
|
package net.engio.mbassy;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.IMessagePublication;
|
import net.engio.mbassy.bus.IMessagePublication;
|
||||||
import net.engio.mbassy.bus.common.IMessageBus;
|
import net.engio.mbassy.bus.common.IMessageBus;
|
||||||
import net.engio.mbassy.bus.config.Feature;
|
import net.engio.mbassy.bus.config.Feature;
|
||||||
import net.engio.mbassy.bus.config.IBusConfiguration;
|
import net.engio.mbassy.bus.config.IBusConfiguration;
|
||||||
import net.engio.mbassy.common.MessageBusTest;
|
import net.engio.mbassy.common.MessageBusTest;
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Invoke;
|
|
||||||
import net.engio.mbassy.listener.Synchronized;
|
import net.engio.mbassy.listener.Synchronized;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import org.junit.Test;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Todo: Add javadoc
|
* Todo: Add javadoc
|
||||||
@ -54,33 +54,6 @@ public class SynchronizedHandlerTest extends MessageBusTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSynchronizedWithAsSynchronousInvocation(){
|
|
||||||
List<SynchronizedWithAsynchronousDelivery> handlers = new LinkedList<SynchronizedWithAsynchronousDelivery>();
|
|
||||||
IBusConfiguration config = SyncAsync();
|
|
||||||
config.getFeature(Feature.AsynchronousMessageDispatch.class)
|
|
||||||
.setNumberOfMessageDispatchers(6);
|
|
||||||
IMessageBus bus = createBus(config);
|
|
||||||
for(int i = 0; i < numberOfListeners; i++){
|
|
||||||
SynchronizedWithAsynchronousDelivery handler = new SynchronizedWithAsynchronousDelivery();
|
|
||||||
handlers.add(handler);
|
|
||||||
bus.subscribe(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < numberOfMessages; i++){
|
|
||||||
track(bus.post(new Object()).asynchronously());
|
|
||||||
}
|
|
||||||
|
|
||||||
pause(10000);
|
|
||||||
|
|
||||||
for(SynchronizedWithAsynchronousDelivery handler : handlers){
|
|
||||||
assertEquals(incrementsPerMessage * numberOfMessages, handler.counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static class SynchronizedWithSynchronousDelivery {
|
public static class SynchronizedWithSynchronousDelivery {
|
||||||
|
|
||||||
private int counter = 0;
|
private int counter = 0;
|
||||||
@ -89,21 +62,7 @@ public class SynchronizedHandlerTest extends MessageBusTest {
|
|||||||
@Synchronized
|
@Synchronized
|
||||||
public void handleMessage(Object o){
|
public void handleMessage(Object o){
|
||||||
for(int i = 0; i < incrementsPerMessage; i++){
|
for(int i = 0; i < incrementsPerMessage; i++){
|
||||||
counter++;
|
this.counter++;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SynchronizedWithAsynchronousDelivery {
|
|
||||||
|
|
||||||
private int counter = 0;
|
|
||||||
|
|
||||||
@Handler(delivery = Invoke.Asynchronously)
|
|
||||||
@Synchronized
|
|
||||||
public void handleMessage(Object o){
|
|
||||||
for(int i = 0; i < incrementsPerMessage; i++){
|
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
package net.engio.mbassy.common;
|
package net.engio.mbassy.common;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
import net.engio.mbassy.bus.MBassador;
|
|
||||||
import net.engio.mbassy.bus.IMessagePublication;
|
import net.engio.mbassy.bus.IMessagePublication;
|
||||||
|
import net.engio.mbassy.bus.MBassador;
|
||||||
import net.engio.mbassy.bus.config.BusConfiguration;
|
import net.engio.mbassy.bus.config.BusConfiguration;
|
||||||
import net.engio.mbassy.bus.config.Feature;
|
import net.engio.mbassy.bus.config.Feature;
|
||||||
import net.engio.mbassy.bus.config.IBusConfiguration;
|
import net.engio.mbassy.bus.config.IBusConfiguration;
|
||||||
import net.engio.mbassy.bus.error.IPublicationErrorHandler;
|
import net.engio.mbassy.bus.error.IPublicationErrorHandler;
|
||||||
import net.engio.mbassy.bus.error.PublicationError;
|
import net.engio.mbassy.bus.error.PublicationError;
|
||||||
import net.engio.mbassy.messages.MessageTypes;
|
import net.engio.mbassy.messages.MessageTypes;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,15 +39,16 @@ public abstract class MessageBusTest extends AssertSupport {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static final Object mapObject = new Object();
|
||||||
private StrongConcurrentSet<IMessagePublication> issuedPublications = new StrongConcurrentSet<IMessagePublication>();
|
private ConcurrentHashMap<IMessagePublication, Object> issuedPublications = new ConcurrentHashMap<IMessagePublication, Object>();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp(){
|
public void setUp(){
|
||||||
issuedPublications = new StrongConcurrentSet<IMessagePublication>();
|
this.issuedPublications = new ConcurrentHashMap<IMessagePublication, Object>();
|
||||||
for(MessageTypes mes : MessageTypes.values())
|
for(MessageTypes mes : MessageTypes.values()) {
|
||||||
mes.reset();
|
mes.reset();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static IBusConfiguration SyncAsync() {
|
public static IBusConfiguration SyncAsync() {
|
||||||
return new BusConfiguration()
|
return new BusConfiguration()
|
||||||
@ -67,23 +71,25 @@ public abstract class MessageBusTest extends AssertSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void track(IMessagePublication asynchronously) {
|
protected void track(IMessagePublication asynchronously) {
|
||||||
issuedPublications.add(asynchronously);
|
this.issuedPublications.put(asynchronously, mapObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForPublications(long timeOutInMs){
|
public void waitForPublications(long timeOutInMs){
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
while(issuedPublications.size() > 0 && System.currentTimeMillis() - start < timeOutInMs){
|
while(this.issuedPublications.size() > 0 && System.currentTimeMillis() - start < timeOutInMs){
|
||||||
for(IMessagePublication pub : issuedPublications){
|
for(IMessagePublication pub : this.issuedPublications.keySet()){
|
||||||
if(pub.isFinished())
|
if(pub.isFinished()) {
|
||||||
issuedPublications.remove(pub);
|
this.issuedPublications.remove(pub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(issuedPublications.size() > 0)
|
}
|
||||||
|
if(this.issuedPublications.size() > 0) {
|
||||||
fail("Issued publications did not finish within specified timeout of " + timeOutInMs + " ms");
|
fail("Issued publications did not finish within specified timeout of " + timeOutInMs + " ms");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addPublication(IMessagePublication publication){
|
public void addPublication(IMessagePublication publication){
|
||||||
issuedPublications.add(publication);
|
this.issuedPublications.put(publication, mapObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package net.engio.mbassy.common;
|
package net.engio.mbassy.common;
|
||||||
|
|
||||||
import net.engio.mbassy.messages.IMessage;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import net.engio.mbassy.messages.IMessage;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -18,8 +19,8 @@ public class MessageManager {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
LoggerFactory.getLogger(MessageManager.class);
|
LoggerFactory.getLogger(MessageManager.class);
|
||||||
|
|
||||||
|
private static final Object mapObject = new Object();
|
||||||
private StrongConcurrentSet<MessageContext> messages = new StrongConcurrentSet();
|
private ConcurrentHashMap<MessageContext, Object> messages = new ConcurrentHashMap<MessageContext, Object>();
|
||||||
|
|
||||||
|
|
||||||
public <T extends IMessage> T create(Class<T> messageType, int expectedCount, Class ...listeners){
|
public <T extends IMessage> T create(Class<T> messageType, int expectedCount, Class ...listeners){
|
||||||
@ -46,7 +47,7 @@ public class MessageManager {
|
|||||||
|
|
||||||
public <T extends IMessage> void register(T message, int expectedCount, Class ...listeners){
|
public <T extends IMessage> void register(T message, int expectedCount, Class ...listeners){
|
||||||
try {
|
try {
|
||||||
messages.add(new MessageContext(expectedCount, message, listeners));
|
this.messages.put(new MessageContext(expectedCount, message, listeners), mapObject);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -54,7 +55,7 @@ public class MessageManager {
|
|||||||
|
|
||||||
public <T extends IMessage> void register(T message, int expectedCount, Collection<Class> listeners){
|
public <T extends IMessage> void register(T message, int expectedCount, Collection<Class> listeners){
|
||||||
try {
|
try {
|
||||||
messages.add(new MessageContext(expectedCount, message, listeners));
|
this.messages.put(new MessageContext(expectedCount, message, listeners), mapObject);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -62,9 +63,9 @@ public class MessageManager {
|
|||||||
|
|
||||||
public void waitForMessages(int timeoutInMs){
|
public void waitForMessages(int timeoutInMs){
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
while(System.currentTimeMillis() - start < timeoutInMs && messages.size() > 0){
|
while(System.currentTimeMillis() - start < timeoutInMs && this.messages.size() > 0){
|
||||||
// check each created message once
|
// check each created message once
|
||||||
for(MessageContext messageCtx : messages){
|
for(MessageContext messageCtx : this.messages.keySet()){
|
||||||
boolean handledCompletely = true;
|
boolean handledCompletely = true;
|
||||||
for(Class listener : messageCtx.getListeners()){
|
for(Class listener : messageCtx.getListeners()){
|
||||||
handledCompletely &= messageCtx.getMessage().getTimesHandled(listener) == messageCtx.getExpectedCount();
|
handledCompletely &= messageCtx.getMessage().getTimesHandled(listener) == messageCtx.getExpectedCount();
|
||||||
@ -72,14 +73,14 @@ public class MessageManager {
|
|||||||
// remove the ones that were handled as expected
|
// remove the ones that were handled as expected
|
||||||
if(handledCompletely){
|
if(handledCompletely){
|
||||||
logSuccess(messageCtx);
|
logSuccess(messageCtx);
|
||||||
messages.remove(messageCtx);
|
this.messages.remove(messageCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
pause(100);
|
pause(100);
|
||||||
}
|
}
|
||||||
if(messages.size() > 0){
|
if(this.messages.size() > 0){
|
||||||
logFailingMessages(messages);
|
logFailingMessages(this.messages);
|
||||||
throw new RuntimeException("Message were not fully processed in given time");
|
throw new RuntimeException("Message were not fully processed in given time");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,11 +101,12 @@ public class MessageManager {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void logFailingMessages(StrongConcurrentSet<MessageContext> failing){
|
private void logFailingMessages(ConcurrentHashMap<MessageContext, Object> failing){
|
||||||
StringBuilder errorMessage = new StringBuilder();
|
StringBuilder errorMessage = new StringBuilder();
|
||||||
errorMessage.append("Failing messages:\n");
|
errorMessage.append("Failing messages:\n");
|
||||||
for(MessageContext failingMessage : failing)
|
for(MessageContext failingMessage : failing.keySet()) {
|
||||||
errorMessage.append(failingMessage);
|
errorMessage.append(failingMessage);
|
||||||
|
}
|
||||||
LOG.info(errorMessage.toString());
|
LOG.info(errorMessage.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,20 +129,20 @@ public class MessageManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private long getExpectedCount() {
|
private long getExpectedCount() {
|
||||||
return expectedCount;
|
return this.expectedCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMessage getMessage() {
|
private IMessage getMessage() {
|
||||||
return message;
|
return this.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class[] getListeners() {
|
private Class[] getListeners() {
|
||||||
return listeners;
|
return this.listeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String printListeners(){
|
private String printListeners(){
|
||||||
StringBuilder listenersAsString = new StringBuilder();
|
StringBuilder listenersAsString = new StringBuilder();
|
||||||
for(Class listener : listeners){
|
for(Class listener : this.listeners){
|
||||||
listenersAsString.append(listener.getName());
|
listenersAsString.append(listener.getName());
|
||||||
listenersAsString.append(",");
|
listenersAsString.append(",");
|
||||||
}
|
}
|
||||||
@ -150,8 +152,8 @@ public class MessageManager {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
// TODO: actual count of listeners
|
// TODO: actual count of listeners
|
||||||
return message.getClass().getSimpleName() + "{" +
|
return this.message.getClass().getSimpleName() + "{" +
|
||||||
"expectedCount=" + expectedCount +
|
"expectedCount=" + this.expectedCount +
|
||||||
", listeners=" + printListeners() +
|
", listeners=" + printListeners() +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package net.engio.mbassy.common;
|
package net.engio.mbassy.common;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import net.engio.mbassy.subscription.Subscription;
|
import net.engio.mbassy.subscription.Subscription;
|
||||||
import net.engio.mbassy.subscription.SubscriptionManager;
|
import net.engio.mbassy.subscription.SubscriptionManager;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author bennidi
|
* @author bennidi
|
||||||
@ -26,18 +30,17 @@ public class SubscriptionValidator extends AssertSupport{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SubscriptionValidator expect(Class subscriber, Class messageType){
|
private SubscriptionValidator expect(Class subscriber, Class messageType){
|
||||||
validations.add(new ValidationEntry(messageType, subscriber));
|
this.validations.add(new ValidationEntry(messageType, subscriber));
|
||||||
messageTypes.add(messageType);
|
this.messageTypes.add(messageType);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// match subscriptions with existing validation entries
|
// match subscriptions with existing validation entries
|
||||||
// for each tuple of subscriber and message type the specified number of listeners must exist
|
// for each tuple of subscriber and message type the specified number of listeners must exist
|
||||||
public void validate(SubscriptionManager manager){
|
public void validate(SubscriptionManager manager){
|
||||||
for(Class messageType : messageTypes){
|
for(Class messageType : this.messageTypes){
|
||||||
Collection<Subscription> subscriptions = manager.getSubscriptionsByMessageType(messageType);
|
Collection<Subscription> subscriptions = manager.getSubscriptionsByMessageType(messageType);
|
||||||
ensureOrdering(subscriptions);
|
Collection<ValidationEntry> validationEntries = getEntries(messageType);
|
||||||
Collection<ValidationEntry> validationEntries = getEntries(EntriesByMessageType(messageType));
|
|
||||||
assertEquals(subscriptions.size(), validationEntries.size());
|
assertEquals(subscriptions.size(), validationEntries.size());
|
||||||
for(ValidationEntry validationValidationEntry : validationEntries){
|
for(ValidationEntry validationValidationEntry : validationEntries){
|
||||||
Subscription matchingSub = null;
|
Subscription matchingSub = null;
|
||||||
@ -49,38 +52,23 @@ public class SubscriptionValidator extends AssertSupport{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertNotNull(matchingSub);
|
assertNotNull(matchingSub);
|
||||||
assertEquals(subscribedListener.getNumberOfListeners(validationValidationEntry.subscriber), matchingSub.size());
|
assertEquals(this.subscribedListener.getNumberOfListeners(validationValidationEntry.subscriber), matchingSub.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureOrdering(Collection<Subscription> subscriptions){
|
|
||||||
int lastPriority = Integer.MAX_VALUE;// highest priority possible
|
|
||||||
for(Subscription sub : subscriptions){
|
|
||||||
assertTrue("Subscriptions should be ordered by priority (DESC)", lastPriority >= sub.getPriority());
|
|
||||||
lastPriority = sub.getPriority();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Collection<ValidationEntry> getEntries(IPredicate<ValidationEntry> filter){
|
private Collection<ValidationEntry> getEntries(Class messageType){
|
||||||
Collection<ValidationEntry> matching = new LinkedList<ValidationEntry>();
|
Collection<ValidationEntry> matching = new LinkedList<ValidationEntry>();
|
||||||
for (ValidationEntry validationValidationEntry : validations){
|
for (ValidationEntry validationValidationEntry : this.validations){
|
||||||
if(filter.apply(validationValidationEntry))matching.add(validationValidationEntry);
|
if (validationValidationEntry.messageType.equals(messageType)) {
|
||||||
|
matching.add(validationValidationEntry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return matching;
|
return matching;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IPredicate<ValidationEntry> EntriesByMessageType(final Class messageType){
|
|
||||||
return new IPredicate<ValidationEntry>() {
|
|
||||||
@Override
|
|
||||||
public boolean apply(ValidationEntry target) {
|
|
||||||
return target.messageType.equals(messageType);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class Expectation{
|
public class Expectation{
|
||||||
|
|
||||||
@ -91,8 +79,9 @@ public class SubscriptionValidator extends AssertSupport{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SubscriptionValidator handles(Class ...messages){
|
public SubscriptionValidator handles(Class ...messages){
|
||||||
for(Class message : messages)
|
for(Class message : messages) {
|
||||||
expect(listener, message);
|
expect(this.listener, message);
|
||||||
|
}
|
||||||
return SubscriptionValidator.this;
|
return SubscriptionValidator.this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.engio.mbassy.listeners;
|
package net.engio.mbassy.listeners;
|
||||||
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Invoke;
|
|
||||||
import net.engio.mbassy.messages.AbstractMessage;
|
import net.engio.mbassy.messages.AbstractMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,6 +21,7 @@ public class AbstractMessageListener {
|
|||||||
|
|
||||||
public static class DefaultListener extends BaseListener {
|
public static class DefaultListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void handle(AbstractMessage message){
|
public void handle(AbstractMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
@ -29,24 +29,17 @@ public class AbstractMessageListener {
|
|||||||
|
|
||||||
public static class NoSubtypesListener extends BaseListener {
|
public static class NoSubtypesListener extends BaseListener {
|
||||||
|
|
||||||
@Handler(rejectSubtypes = true, priority = 4)
|
@Override
|
||||||
|
@Handler(rejectSubtypes = true)
|
||||||
public void handle(AbstractMessage message){
|
public void handle(AbstractMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class AsyncListener extends BaseListener {
|
|
||||||
|
|
||||||
@Handler(delivery = Invoke.Asynchronously, priority = Integer.MAX_VALUE)
|
|
||||||
public void handle(AbstractMessage message){
|
|
||||||
super.handle(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DisabledListener extends BaseListener {
|
public static class DisabledListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(enabled = false)
|
@Handler(enabled = false)
|
||||||
public void handle(AbstractMessage message){
|
public void handle(AbstractMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package net.engio.mbassy.listeners;
|
|
||||||
|
|
||||||
import net.engio.mbassy.dispatch.HandlerInvocation;
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
|
||||||
import net.engio.mbassy.listener.Listener;
|
|
||||||
import net.engio.mbassy.listener.References;
|
|
||||||
import net.engio.mbassy.messages.StandardMessage;
|
|
||||||
import net.engio.mbassy.subscription.SubscriptionContext;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 5/25/13
|
|
||||||
*/
|
|
||||||
@Listener(references = References.Strong)
|
|
||||||
public class CustomInvocationListener {
|
|
||||||
|
|
||||||
|
|
||||||
// this handler will be invoked asynchronously
|
|
||||||
@Handler(invocation = HandleSubTestEventInvocation.class)
|
|
||||||
public void handle(StandardMessage message) {
|
|
||||||
message.handled(this.getClass());
|
|
||||||
message.handled(this.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class HandleSubTestEventInvocation extends HandlerInvocation<CustomInvocationListener, StandardMessage> {
|
|
||||||
|
|
||||||
public HandleSubTestEventInvocation(SubscriptionContext context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(CustomInvocationListener listener, StandardMessage message) {
|
|
||||||
listener.handle(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -2,14 +2,13 @@ package net.engio.mbassy.listeners;
|
|||||||
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Listener;
|
import net.engio.mbassy.listener.Listener;
|
||||||
import net.engio.mbassy.listener.References;
|
|
||||||
import net.engio.mbassy.messages.StandardMessage;
|
import net.engio.mbassy.messages.StandardMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 5/25/13
|
* Date: 5/25/13
|
||||||
*/
|
*/
|
||||||
@Listener(references = References.Strong)
|
@Listener()
|
||||||
public class ExceptionThrowingListener {
|
public class ExceptionThrowingListener {
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.engio.mbassy.listeners;
|
package net.engio.mbassy.listeners;
|
||||||
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Invoke;
|
|
||||||
import net.engio.mbassy.messages.ICountable;
|
import net.engio.mbassy.messages.ICountable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,6 +21,7 @@ public class ICountableListener {
|
|||||||
|
|
||||||
public static class DefaultListener extends BaseListener {
|
public static class DefaultListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void handle(ICountable message){
|
public void handle(ICountable message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
@ -29,6 +29,7 @@ public class ICountableListener {
|
|||||||
|
|
||||||
public static class NoSubtypesListener extends BaseListener {
|
public static class NoSubtypesListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(rejectSubtypes = true)
|
@Handler(rejectSubtypes = true)
|
||||||
public void handle(ICountable message){
|
public void handle(ICountable message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
@ -36,17 +37,9 @@ public class ICountableListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class AsyncListener extends BaseListener {
|
|
||||||
|
|
||||||
@Handler(delivery = Invoke.Asynchronously)
|
|
||||||
public void handle(ICountable message){
|
|
||||||
super.handle(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DisabledListener extends BaseListener {
|
public static class DisabledListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(enabled = false)
|
@Handler(enabled = false)
|
||||||
public void handle(ICountable message){
|
public void handle(ICountable message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.engio.mbassy.listeners;
|
package net.engio.mbassy.listeners;
|
||||||
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Invoke;
|
|
||||||
import net.engio.mbassy.messages.IMessage;
|
import net.engio.mbassy.messages.IMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,6 +21,7 @@ public class IMessageListener {
|
|||||||
|
|
||||||
public static class DefaultListener extends BaseListener {
|
public static class DefaultListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void handle(IMessage message){
|
public void handle(IMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
@ -29,6 +29,7 @@ public class IMessageListener {
|
|||||||
|
|
||||||
public static class NoSubtypesListener extends BaseListener {
|
public static class NoSubtypesListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(rejectSubtypes = true)
|
@Handler(rejectSubtypes = true)
|
||||||
public void handle(IMessage message){
|
public void handle(IMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
@ -36,17 +37,9 @@ public class IMessageListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class AsyncListener extends BaseListener {
|
|
||||||
|
|
||||||
@Handler(delivery = Invoke.Asynchronously)
|
|
||||||
public void handle(IMessage message){
|
|
||||||
super.handle(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DisabledListener extends BaseListener {
|
public static class DisabledListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(enabled = false)
|
@Handler(enabled = false)
|
||||||
public void handle(IMessage message){
|
public void handle(IMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.engio.mbassy.listeners;
|
package net.engio.mbassy.listeners;
|
||||||
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Invoke;
|
|
||||||
import net.engio.mbassy.messages.IMultipartMessage;
|
import net.engio.mbassy.messages.IMultipartMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,6 +21,7 @@ public class IMultipartMessageListener {
|
|||||||
|
|
||||||
public static class DefaultListener extends BaseListener {
|
public static class DefaultListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void handle(IMultipartMessage message){
|
public void handle(IMultipartMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
@ -29,25 +29,18 @@ public class IMultipartMessageListener {
|
|||||||
|
|
||||||
public static class NoSubtypesListener extends BaseListener {
|
public static class NoSubtypesListener extends BaseListener {
|
||||||
|
|
||||||
@Handler(rejectSubtypes = true, priority = Integer.MIN_VALUE)
|
@Override
|
||||||
|
@Handler(rejectSubtypes = true)
|
||||||
public void handle(IMultipartMessage message){
|
public void handle(IMultipartMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class AsyncListener extends BaseListener {
|
|
||||||
|
|
||||||
@Handler(delivery = Invoke.Asynchronously, priority = Integer.MIN_VALUE)
|
|
||||||
public void handle(IMultipartMessage message){
|
|
||||||
super.handle(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DisabledListener extends BaseListener {
|
public static class DisabledListener extends BaseListener {
|
||||||
|
|
||||||
@Handler(enabled = false , priority = 4)
|
@Override
|
||||||
|
@Handler(enabled = false)
|
||||||
public void handle(IMultipartMessage message){
|
public void handle(IMultipartMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
package net.engio.mbassy.listeners;
|
package net.engio.mbassy.listeners;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created with IntelliJ IDEA.
|
* Created with IntelliJ IDEA.
|
||||||
@ -19,14 +24,6 @@ public class Listeners {
|
|||||||
ICountableListener.DefaultListener.class,
|
ICountableListener.DefaultListener.class,
|
||||||
IMultipartMessageListener.DefaultListener.class}));
|
IMultipartMessageListener.DefaultListener.class}));
|
||||||
|
|
||||||
private static final List<Class> Asynchronous = Collections.unmodifiableList(Arrays.asList(new Class[]{
|
|
||||||
MessagesListener.AsyncListener.class,
|
|
||||||
IMessageListener.AsyncListener.class,
|
|
||||||
StandardMessageListener.AsyncListener.class,
|
|
||||||
MultipartMessageListener.AsyncListener.class,
|
|
||||||
ICountableListener.AsyncListener.class,
|
|
||||||
IMultipartMessageListener.AsyncListener.class}));
|
|
||||||
|
|
||||||
private static final List<Class> SubtypeRejecting = Collections.unmodifiableList(Arrays.asList(new Class[]{
|
private static final List<Class> SubtypeRejecting = Collections.unmodifiableList(Arrays.asList(new Class[]{
|
||||||
MessagesListener.NoSubtypesListener.class,
|
MessagesListener.NoSubtypesListener.class,
|
||||||
IMessageListener.NoSubtypesListener.class,
|
IMessageListener.NoSubtypesListener.class,
|
||||||
@ -47,28 +44,20 @@ public class Listeners {
|
|||||||
|
|
||||||
private static final List<Class> HandlesIMessage = Collections.unmodifiableList(Arrays.asList(new Class[]{
|
private static final List<Class> HandlesIMessage = Collections.unmodifiableList(Arrays.asList(new Class[]{
|
||||||
IMessageListener.DefaultListener.class,
|
IMessageListener.DefaultListener.class,
|
||||||
IMessageListener.AsyncListener.class,
|
|
||||||
IMessageListener.NoSubtypesListener.class,
|
IMessageListener.NoSubtypesListener.class,
|
||||||
IMultipartMessageListener.DefaultListener.class,
|
IMultipartMessageListener.DefaultListener.class,
|
||||||
IMultipartMessageListener.AsyncListener.class,
|
|
||||||
IMultipartMessageListener.NoSubtypesListener.class,
|
IMultipartMessageListener.NoSubtypesListener.class,
|
||||||
MessagesListener.DefaultListener.class,
|
MessagesListener.DefaultListener.class,
|
||||||
MessagesListener.AsyncListener.class,
|
|
||||||
MessagesListener.NoSubtypesListener.class,
|
MessagesListener.NoSubtypesListener.class,
|
||||||
StandardMessageListener.DefaultListener.class,
|
StandardMessageListener.DefaultListener.class,
|
||||||
StandardMessageListener.AsyncListener.class,
|
|
||||||
StandardMessageListener.NoSubtypesListener.class,
|
StandardMessageListener.NoSubtypesListener.class,
|
||||||
MultipartMessageListener.DefaultListener.class,
|
MultipartMessageListener.DefaultListener.class,
|
||||||
MultipartMessageListener.AsyncListener.class,
|
|
||||||
MultipartMessageListener.NoSubtypesListener.class}));
|
MultipartMessageListener.NoSubtypesListener.class}));
|
||||||
|
|
||||||
private static final List<Class> HandlesStandardessage = Collections.unmodifiableList(Arrays.asList(new Class[]{
|
private static final List<Class> HandlesStandardessage = Collections.unmodifiableList(Arrays.asList(new Class[]{
|
||||||
IMessageListener.DefaultListener.class,
|
IMessageListener.DefaultListener.class,
|
||||||
IMessageListener.AsyncListener.class,
|
|
||||||
ICountableListener.DefaultListener.class,
|
ICountableListener.DefaultListener.class,
|
||||||
ICountableListener.AsyncListener.class,
|
|
||||||
StandardMessageListener.DefaultListener.class,
|
StandardMessageListener.DefaultListener.class,
|
||||||
StandardMessageListener.AsyncListener.class,
|
|
||||||
StandardMessageListener.NoSubtypesListener.class}));
|
StandardMessageListener.NoSubtypesListener.class}));
|
||||||
|
|
||||||
|
|
||||||
@ -76,10 +65,6 @@ public class Listeners {
|
|||||||
return Synchronous;
|
return Synchronous;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Collection<Class> asynchronous(){
|
|
||||||
return Asynchronous;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Collection<Class> subtypeRejecting(){
|
public static Collection<Class> subtypeRejecting(){
|
||||||
return SubtypeRejecting;
|
return SubtypeRejecting;
|
||||||
}
|
}
|
||||||
@ -99,10 +84,12 @@ public class Listeners {
|
|||||||
|
|
||||||
public static Collection<Class> join(Collection<Class>...listenerSets){
|
public static Collection<Class> join(Collection<Class>...listenerSets){
|
||||||
Set<Class> join = new HashSet<Class>();
|
Set<Class> join = new HashSet<Class>();
|
||||||
for(Collection<Class> listeners : listenerSets)
|
for(Collection<Class> listeners : listenerSets) {
|
||||||
join.addAll(listeners);
|
join.addAll(listeners);
|
||||||
for(Collection<Class> listeners : listenerSets)
|
}
|
||||||
|
for(Collection<Class> listeners : listenerSets) {
|
||||||
join.retainAll(listeners);
|
join.retainAll(listeners);
|
||||||
|
}
|
||||||
return join;
|
return join;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.engio.mbassy.listeners;
|
package net.engio.mbassy.listeners;
|
||||||
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Invoke;
|
|
||||||
import net.engio.mbassy.messages.MessageTypes;
|
import net.engio.mbassy.messages.MessageTypes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,6 +21,7 @@ public class MessagesListener {
|
|||||||
|
|
||||||
public static class DefaultListener extends BaseListener {
|
public static class DefaultListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void handle(MessageTypes message){
|
public void handle(MessageTypes message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
@ -29,6 +29,7 @@ public class MessagesListener {
|
|||||||
|
|
||||||
public static class NoSubtypesListener extends BaseListener {
|
public static class NoSubtypesListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(rejectSubtypes = true)
|
@Handler(rejectSubtypes = true)
|
||||||
public void handle(MessageTypes message){
|
public void handle(MessageTypes message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
@ -36,17 +37,9 @@ public class MessagesListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class AsyncListener extends BaseListener {
|
|
||||||
|
|
||||||
@Handler(delivery = Invoke.Asynchronously)
|
|
||||||
public void handle(MessageTypes message){
|
|
||||||
super.handle(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DisabledListener extends BaseListener {
|
public static class DisabledListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(enabled = false)
|
@Handler(enabled = false)
|
||||||
public void handle(MessageTypes message){
|
public void handle(MessageTypes message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.engio.mbassy.listeners;
|
package net.engio.mbassy.listeners;
|
||||||
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Invoke;
|
|
||||||
import net.engio.mbassy.messages.MultipartMessage;
|
import net.engio.mbassy.messages.MultipartMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,6 +21,7 @@ public class MultipartMessageListener {
|
|||||||
|
|
||||||
public static class DefaultListener extends BaseListener {
|
public static class DefaultListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void handle(MultipartMessage message){
|
public void handle(MultipartMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
@ -29,6 +29,7 @@ public class MultipartMessageListener {
|
|||||||
|
|
||||||
public static class NoSubtypesListener extends BaseListener {
|
public static class NoSubtypesListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(rejectSubtypes = true)
|
@Handler(rejectSubtypes = true)
|
||||||
public void handle(MultipartMessage message){
|
public void handle(MultipartMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
@ -36,17 +37,9 @@ public class MultipartMessageListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class AsyncListener extends BaseListener {
|
|
||||||
|
|
||||||
@Handler(delivery = Invoke.Asynchronously)
|
|
||||||
public void handle(MultipartMessage message){
|
|
||||||
super.handle(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DisabledListener extends BaseListener {
|
public static class DisabledListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(enabled = false)
|
@Handler(enabled = false)
|
||||||
public void handle(MultipartMessage message){
|
public void handle(MultipartMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
package net.engio.mbassy.listeners;
|
package net.engio.mbassy.listeners;
|
||||||
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.engio.mbassy.listener.Handler;
|
||||||
|
|
||||||
|
|
||||||
public class ObjectListener {
|
public class ObjectListener {
|
||||||
|
|
||||||
private List handledMessages = Collections.synchronizedList(new LinkedList());
|
private List handledMessages = Collections.synchronizedList(new LinkedList());
|
||||||
|
|
||||||
@Handler(priority = Integer.MAX_VALUE)
|
@Handler()
|
||||||
public void handle(Object message){
|
public void handle(Object message){
|
||||||
handledMessages.add(message);
|
this.handledMessages.add(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package net.engio.mbassy.listeners;
|
|||||||
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Listener;
|
import net.engio.mbassy.listener.Listener;
|
||||||
import net.engio.mbassy.listener.References;
|
|
||||||
import net.engio.mbassy.messages.AbstractMessage;
|
import net.engio.mbassy.messages.AbstractMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,7 +24,7 @@ public class Overloading {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listener(references = References.Strong)
|
@Listener()
|
||||||
public static class ListenerBase {
|
public static class ListenerBase {
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.engio.mbassy.listeners;
|
package net.engio.mbassy.listeners;
|
||||||
|
|
||||||
import net.engio.mbassy.listener.Handler;
|
import net.engio.mbassy.listener.Handler;
|
||||||
import net.engio.mbassy.listener.Invoke;
|
|
||||||
import net.engio.mbassy.messages.StandardMessage;
|
import net.engio.mbassy.messages.StandardMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -13,7 +12,7 @@ public class StandardMessageListener {
|
|||||||
|
|
||||||
private static abstract class BaseListener {
|
private static abstract class BaseListener {
|
||||||
|
|
||||||
@Handler(priority = 3)
|
@Handler()
|
||||||
public void handle(StandardMessage message){
|
public void handle(StandardMessage message){
|
||||||
message.handled(this.getClass());
|
message.handled(this.getClass());
|
||||||
}
|
}
|
||||||
@ -22,6 +21,7 @@ public class StandardMessageListener {
|
|||||||
|
|
||||||
public static class DefaultListener extends BaseListener {
|
public static class DefaultListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void handle(StandardMessage message){
|
public void handle(StandardMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
@ -29,24 +29,17 @@ public class StandardMessageListener {
|
|||||||
|
|
||||||
public static class NoSubtypesListener extends BaseListener {
|
public static class NoSubtypesListener extends BaseListener {
|
||||||
|
|
||||||
@Handler(rejectSubtypes = true, priority = 4)
|
@Override
|
||||||
|
@Handler(rejectSubtypes = true)
|
||||||
public void handle(StandardMessage message){
|
public void handle(StandardMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class AsyncListener extends BaseListener {
|
|
||||||
|
|
||||||
@Handler(delivery = Invoke.Asynchronously, priority = -10)
|
|
||||||
public void handle(StandardMessage message){
|
|
||||||
super.handle(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DisabledListener extends BaseListener {
|
public static class DisabledListener extends BaseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
@Handler(enabled = false)
|
@Handler(enabled = false)
|
||||||
public void handle(StandardMessage message){
|
public void handle(StandardMessage message){
|
||||||
super.handle(message);
|
super.handle(message);
|
||||||
|
Loading…
Reference in New Issue
Block a user