Skip to content

Commit

Permalink
updated documentation, small refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
bennidi committed Nov 11, 2013
1 parent cf0328c commit a488114
Show file tree
Hide file tree
Showing 14 changed files with 182 additions and 134 deletions.
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Read this documentation to get an overview of MBassadors features. There is also
not enough to make a developer happy (work is in progress). But usage of publish subscribe pattern at its core is pretty straight forward and the basic
use cases are very easy to understand and implement.

The current version is 1.1.8 and it is available from the Maven Central Repository. See the release notes for more details.
The current version is 1.1.9 and it is available from the Maven Central Repository. See the release notes for more details.

There is also an extension available to support CDI-like transactional message sending in a Spring environment. It's beta but
stable enough to give it a try. See <a href="https://github.com/bennidi/mbassador-spring" target="_blank">here</a>.
Expand Down Expand Up @@ -41,7 +41,7 @@ asynchronously. This is configurable for each handler via annotations. Message p
blocks until messages are delivered to all handlers) or asynchronous (fire and forget) dispatch
+ <em><strong>Weak references</em></strong>: By default, MBassador uses weak references to all listening objects to relieve the programmer of the burden to explicitly unregister
listeners that are not used anymore (of course it is also possible to explicitly unregister a listener if needed). This is very comfortable
in certain environments where listeners are managed by frameworks, i.e. spring, guice etc. Just stuff everything into the message bus, it will
in certain environments where listeners are managed by frameworks, i.e. Spring, Guice etc. Just stuff everything into the message bus, it will
ignore objects without message handlers and automatically clean-up orphaned weak references after the garbage collector has done its job.
+ <em><strong>Strong references</em></strong>: Instead of using weak references, a listener can be configured to be referenced using strong references using @Listener
+ <em><strong>Filtering</em></strong>: MBassador offers static message filtering. Filters are configured using annotations and multiple filters can be attached to
Expand Down Expand Up @@ -143,20 +143,24 @@ Beginning with version 1.1.0 MBassador is available from the Maven Central Repos
<dependency>
<groupId>net.engio</groupId>
<artifactId>mbassador</artifactId>
<version>1.1.7</version>
<version>1.1.9</version>
</dependency>
```


Of course you can always clone the repository and build from source.

<h2>Wiki</h2>
There is ongoing afford to extend documentation and provide code samples and detailed explanations of how the message bus
There is ongoing effort to extend documentation and provide code samples and detailed explanations of how the message bus
works. Code samples can also be found in the various test cases. Please read about the terminology used in this project
to avoid confusion and misunderstanding.

<h2>Release Notes</h2>

<h3>1.1.9</h3>

+ Fixed memory leak reported in issue #53

<h3>1.1.8</h3>

+ Internal refactorings and code improvements
Expand All @@ -168,8 +172,8 @@ to avoid confusion and misunderstanding.
<h3>1.1.7</h3>

+ Console Logger not added to message bus instances by default -> use addErrorHandler(IPublicationErrorHandler.ConsoleLogger)
+ Fixed race conditions in subscription and of WeakConcurrentSet.contains()
+ Improved message hierarchy handling: Now interfaces, enums , (abstract) classes all work in all combinations
+ Fixed race conditions in net.engio.mbassy.subscription.Subscription and of WeakConcurrentSet.contains()
+ Improved message hierarchy handling: Now interfaces, enums , (abstract) classes should work in all combinations
+ Prevented dispatcher threads from dying on exceptions
+ Improved test-infrastructure and increased test-coverage
+ Thanks for your feedback!
Expand Down Expand Up @@ -232,13 +236,14 @@ First stable release!


<h2>Roadmap</h2>
Check the issues marked with label enhancement. Comment if you would like to see the feature in a future release.
Check the issues labeled 'enhancement'. Comment if you would like to see the feature in a future release and/or want to share
your ideas on the feature (or a variation thereof).
Please understand that I have limited time to include new features and that I will focus on stability and cleaner APIs.
Adding features only works well with well designed and thoroughly tested components especially with all this multi-threaded code
and I am still not 100 percent happy with the existing test coverage.
Adding features only works with well designed and thoroughly tested components. This is especially true for multi-threaded code
and I am still not 100 percent happy with the existing test design and some parts of the internal code layout.

Planned for release:Spring integration with support for conditional message dispatch in transactional context (dispatch only after
successful commit etc.). Currently in beta, see <a href="https://github.com/bennidi/mbassador-spring">this</a> repository
successful transaction commit etc.). Currently in beta, see <a href="https://github.com/bennidi/mbassador-spring">this</a> repository


<h2>Credits</h2>
Expand Down
2 changes: 1 addition & 1 deletion src/docs/wiki-listener-def.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
MBassador allows a variety of message handler configurations that will affect how a message
MBassador understands a variety of message handler configurations that will affect how a message
is delivered to a specific listener. There are properties to control the handling of subclasses
of the specified message (the method parameter), the execution order of handlers for the same message type,
filters, delivery modes etc.
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/net/engio/mbassy/listener/Filters.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ public class Filters {
public static final class AllowAll implements IMessageFilter {

@Override
public boolean accepts(Object event, MessageHandlerMetadata metadata) {
public boolean accepts(Object event, MessageHandler metadata) {
return true;
}
}

public static final class RejectAll implements IMessageFilter {

@Override
public boolean accepts(Object event, MessageHandlerMetadata metadata) {
public boolean accepts(Object event, MessageHandler metadata) {
return false;
}
}
Expand All @@ -29,7 +29,7 @@ public boolean accepts(Object event, MessageHandlerMetadata metadata) {
public static final class RejectSubtypes implements IMessageFilter {

@Override
public boolean accepts(Object event, MessageHandlerMetadata metadata) {
public boolean accepts(Object event, MessageHandler metadata) {
for (Class handledMessage : metadata.getHandledMessages()) {
if (handledMessage.equals(event.getClass())) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ public interface IMessageFilter {
* @param message the message to be delivered
* @return
*/
boolean accepts(Object message, MessageHandlerMetadata metadata);
boolean accepts(Object message, MessageHandler metadata);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
import java.util.List;

/**
* Any method in any class annotated with the @Handler annotation represents a message handler. The class that contains
* the handler defines the message listener and more generally, any class containing a message handler in its class hierarchy
* defines a message listener.
*
* @author bennidi
* Date: 11/14/12
*/
public class MessageHandlerMetadata {
public class MessageHandler {

private final Method handler;

Expand All @@ -26,14 +30,14 @@ public class MessageHandlerMetadata {

private final boolean acceptsSubtypes;

private final MessageListenerMetadata listenerConfig;
private final MessageListener listenerConfig;

private final boolean isSynchronized;

private Class listeningClass;


public MessageHandlerMetadata(Method handler, IMessageFilter[] filter, Handler handlerConfig, MessageListenerMetadata listenerConfig) {
public MessageHandler(Method handler, IMessageFilter[] filter, Handler handlerConfig, MessageListener listenerConfig) {
if(handler == null || handlerConfig == null){
throw new IllegalArgumentException("The message handler configuration may not be null");
}
Expand Down
87 changes: 87 additions & 0 deletions src/main/java/net/engio/mbassy/listener/MessageListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package net.engio.mbassy.listener;

import net.engio.mbassy.common.IPredicate;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

/**
* All instances of any class that defines at least one message handler (see @MessageHandler) are message listeners. Thus,
* a message listener is any object capable of receiving messages by means of defined message handlers.
* There are no restrictions about the number of allowed message handlers in a message listener.
*
* A message listener can be configured using the @Listener annotation but is always implicitly configured by the handler
* definition it contains.
*
* This class is an internal representation of a message listener used to encapsulate all relevant objects
* and data about that message listener, especially all its handlers.
* There will be only one instance of MessageListener per message listener class and message bus instance.
*
* @author bennidi
* Date: 12/16/12
*/
public class MessageListener<T> {


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 Class<T> listenerDefinition;

private Listener listenerAnnotation;

public MessageListener(Class<T> listenerDefinition) {
this.listenerDefinition = listenerDefinition;
listenerAnnotation = listenerDefinition.getAnnotation(Listener.class);
}


public boolean isFromListener(Class listener){
return listenerDefinition.equals(listener);
}

public boolean useStrongReferences(){
return listenerAnnotation != null && listenerAnnotation.references().equals(References.Strong);
}

public MessageListener addHandlers(Collection<? extends MessageHandler> c) {
handlers.addAll(c);
return this;
}

public boolean addHandler(MessageHandler messageHandler) {
return handlers.add(messageHandler);
}

public List<MessageHandler> getHandlers(){
return handlers;
}

public List<MessageHandler> getHandlers(IPredicate<MessageHandler> filter) {
List<MessageHandler> matching = new LinkedList<MessageHandler>();
for (MessageHandler handler : handlers) {
if (filter.apply(handler)) {
matching.add(handler);
}
}
return matching;
}

public boolean handles(Class<?> messageType) {
return !getHandlers(ForMessage(messageType)).isEmpty();
}

public Class<T> getListerDefinition() {
return listenerDefinition;
}
}

This file was deleted.

6 changes: 3 additions & 3 deletions src/main/java/net/engio/mbassy/listener/MetadataReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ private IMessageFilter[] getFilter(Handler subscription) {

// get all listeners defined by the given class (includes
// listeners defined in super classes)
public MessageListenerMetadata getMessageListener(Class target) {
MessageListenerMetadata listenerMetadata = new MessageListenerMetadata(target);
public MessageListener getMessageListener(Class target) {
MessageListener listenerMetadata = new MessageListener(target);
// get all handlers (this will include all (inherited) methods directly annotated using @Handler)
List<Method> allHandlers = ReflectionUtils.getMethods(AllMessageHandlers, target);
// retain only those that are at the bottom of their respective class hierarchy (deepest overriding method)
Expand All @@ -76,7 +76,7 @@ public MessageListenerMetadata getMessageListener(Class target) {
}
Method overriddenHandler = ReflectionUtils.getOverridingMethod(handler, target);
// if a handler is overwritten it inherits the configuration of its parent method
MessageHandlerMetadata handlerMetadata = new MessageHandlerMetadata(overriddenHandler == null ? handler : overriddenHandler,
MessageHandler handlerMetadata = new MessageHandler(overriddenHandler == null ? handler : overriddenHandler,
getFilter(handlerConfig), handlerConfig, listenerMetadata);
listenerMetadata.addHandler(handlerMetadata);

Expand Down
27 changes: 26 additions & 1 deletion src/main/java/net/engio/mbassy/subscription/Subscription.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@
import java.util.UUID;

/**
* A subscription is a thread safe container for objects that contain message handlers
* 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 of a SingleMessageHandler.class
* will be referenced in the subscription created for SingleMessageHandler.class.
*
* There will be as many unique subscription objects per message listener class as there are message handlers
* defined in the message listeners class hierarchy.
*
* The subscription provides functionality for message publication by means of delegation to the respective
* message dispatcher.
*
*/
public class Subscription {

Expand All @@ -27,14 +36,30 @@ public class Subscription {
this.listeners = listeners;
}

/**
* Check whether this subscription manages a message handler of the given message listener class
*
* @param listener
* @return
*/
public boolean belongsTo(Class listener){
return context.getHandlerMetadata().isFromListener(listener);
}

/**
* Check whether this subscriptions manages the given listener instance
* @param listener
* @return
*/
public boolean contains(Object listener){
return listeners.contains(listener);
}

/**
* Check whether this subscription manages a message handler
* @param messageType
* @return
*/
public boolean handlesMessageType(Class<?> messageType) {
return context.getHandlerMetadata().handlesMessage(messageType);
}
Expand Down
Loading

0 comments on commit a488114

Please sign in to comment.