MessageBus/README.md

252 lines
13 KiB
Markdown
Raw Normal View History

2013-01-10 13:18:01 +01:00
MBassador
2012-10-23 09:27:32 +02:00
=========
2013-01-10 13:18:01 +01:00
MBassador is a very light-weight message (event) bus implementation following the publish subscribe pattern. It is designed
2012-12-25 16:52:37 +01:00
for ease of use and aims to be feature rich and extensible while preserving resource efficiency and performance. It uses a specialized
data structure to allow high throughput for concurrent access.
2012-11-22 14:41:51 +01:00
Read this documentation to get an overview of its features. You can also check out the <a href="http://codeblock.engio.net/?p=37" target="_blank">performance comparison</a>
2012-11-21 00:02:00 +01:00
which also contains a partial list of the features of the compared implementations.
2012-11-20 14:12:57 +01:00
2013-05-26 18:20:32 +02:00
The current version is 1.1.7 and it is available from the Maven Central Repository. See the release notes for more details.
2012-11-22 14:41:51 +01:00
2012-11-20 14:12:57 +01:00
Table of contents:
2012-11-20 14:03:30 +01:00
+ [Features](#features)
2012-11-20 14:12:57 +01:00
+ [Usage](#usage)
+ [Installation](#installation)
+ [Wiki](#wiki)
2012-12-25 16:52:37 +01:00
+ [Release Notes](#releasenotes)
2012-11-20 14:12:57 +01:00
+ [Roadmap](#roadmap)
+ [Credits](#credits)
2012-11-21 00:00:18 +01:00
+ [Contribute](#contribute)
2012-11-20 14:03:30 +01:00
+ [License](#license)
2012-11-20 13:58:36 +01:00
2012-11-19 12:34:53 +01:00
2012-11-20 14:15:15 +01:00
<h2 name="features">Features</h2>
2012-11-20 14:03:30 +01:00
2012-11-21 00:00:18 +01:00
At its core MBassador offers the following features:
2012-10-23 10:31:12 +02:00
+ <em><strong>Annotation driven</em></strong>: To define and customize a message handler simply mark it with @Handler annotation
+ <em><strong>Delivers everything</em></strong>: Messages must not implement any interface and can be of any type. It is
possible though to define an upper bound of the message type using generics. The class hierarchy of a message is considered during message delivery.
2013-04-01 15:29:19 +02:00
This means that handlers will also receive subtypes of the message type they are listening for, e.g. a handler of Object.class receives everything.
2012-10-28 09:41:12 +01:00
+ <em><strong>Synchronous and asynchronous message delivery</em></strong>: A handler can be invoked to handle a message either synchronously or
2012-10-23 10:31:12 +02:00
asynchronously. This is configurable for each handler via annotations. Message publication itself supports synchronous (method
blocks until messages are delivered to all handlers) or asynchronous (fire and forget) dispatch
2013-04-01 15:13:52 +02:00
+ <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
2012-10-23 10:31:12 +02:00
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
2012-10-23 10:31:12 +02:00
ignore objects without message handlers and automatically clean-up orphaned weak references after the garbage collector has done its job.
2013-04-01 15:29:19 +02:00
+ <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
2012-10-23 10:31:12 +02:00
a single message handler
+ <em><strong>Message envelopes</em></strong>: Message handlers can declare to receive an enveloped message. The envelope can wrap different
2013-04-01 15:29:19 +02:00
types of messages. This allows for a single handler to handle multiple, unrelated message types.
2013-04-01 15:30:43 +02:00
+ <em><strong>Handler priorities</em></strong>: A handler can be associated with a priority to influence the order in which messages are delivered when multiple matching handlers exist
+ <em><strong>Custom error handling</em></strong>: Errors during message delivery are sent to all registered error handlers which can be added to the bus as necessary.
2013-03-06 12:08:48 +01:00
+ <em><strong>DeadMessage event</em></strong>: Messages that do not match any handler result in the publication of a DeadMessage object which wraps the original message. DeadMessage events
can be handled by registering listeners that handle DeadMessage.
+ <em><strong>FilteredMessage event</em></strong>: Messages that have matching handlers but do not pass the configured filters result in the publication of a FilteredMessage object which wraps the original message.
2013-03-06 12:08:48 +01:00
FilteredMessage events can be handled by registering listeners that handle FilteredMessage.
2013-04-01 15:29:19 +02:00
+ <em><strong>Synchronization</em></strong>: It is possible to ensure that a handler is invoked non-concurrently,i.e. making it thread-safe by adding @Synchronized
+ <em><strong>Extensibility</em></strong>:MBassador is designed to be extensible with custom implementations of various components like message
dispatchers and handler invocations (using the decorator pattern), metadata reader (you can add your own annotations) and factories for different
2013-04-01 15:33:18 +02:00
kinds of objects. A configuration object is used to customize the different configurable parts
+ <em><strong>Ease of Use</em></strong>: Using MBassador in your project is very easy. Create as many instances of MBassador as you like (usually a singleton will do),
mark and configure your message handlers with @Handler annotations and finally register the listeners at any MBassador instance. Start
sending messages to your listeners using one of MBassador's publication methods (sync or async). Done!
2012-10-23 10:31:12 +02:00
2012-10-28 09:11:45 +01:00
2012-10-28 09:19:55 +01:00
2013-04-01 15:29:19 +02:00
2012-11-20 14:15:15 +01:00
<h2>Usage</h2>
2012-10-28 09:11:45 +01:00
2013-04-01 15:13:52 +02:00
Handler definition (in any bean):
2012-11-23 04:41:12 +01:00
2013-03-06 12:08:48 +01:00
// every message of type TestMessage or any subtype will be delivered
2012-10-28 09:11:45 +01:00
// to this handler
@Handler
2013-03-06 12:08:48 +01:00
public void handleTestMessage(TestMessage message) {
2012-10-28 09:11:45 +01:00
// do something
}
2013-04-01 15:13:52 +02:00
// every message of type TestMessage or any subtype will be delivered
// to this handler
@Handler
public void handleTestMessageStrong(TestMessage message) {
// do something
}
// this handler will be invoked asynchronously (in a different thread)
@Handler(delivery = Invoke.Asynchronously)
2013-03-06 12:08:48 +01:00
public void handleSubTestMessage(SubTestMessage message) {
2012-10-28 09:11:45 +01:00
// do something more expensive here
}
// this handler will receive messages of type SubTestMessage
2012-12-25 17:19:58 +01:00
// or any of its sub types that passe the given filter(s)
@Handler(priority = 10,
2013-04-01 15:33:18 +02:00
delivery = Invoke.Synchronously,
filters = {@Filter(Filters.SpecialMessage.class)})
2013-03-06 12:08:48 +01:00
public void handleFiltered(SubTestMessage message) {
2012-10-28 09:11:45 +01:00
//do something special here
}
2013-04-01 15:33:18 +02:00
@Handler(delivery = Invoke.Synchronously, rejectSubtypes = true)
@Enveloped(messages = {TestMessage.class, TestMessage2.class})
2013-03-04 10:25:24 +01:00
public void handleUnrelatedMessageTypes(MessageEnvelope envelope) {
// the envelope will contain either an instance of TestMessage or TestMessage2
// if rejectSubtypes were set to 'false' (default) also subtypes of TestMessage or TestMessage2 would be allowed
2012-12-12 14:56:28 +01:00
}
2013-04-01 15:13:52 +02:00
// configure a listener to be stored using strong instead of weak references
@Listener(references = References.Strong)
public class MessageListener{
// any handler definitions
}
2012-10-28 09:11:45 +01:00
Creation of message bus and registration of listeners:
// create as many instances as necessary
// bind it to any upper bound
MBassador<TestMessage> bus = new MBassador<TestMessage>(BusConfiguration.Default());
2012-10-28 09:11:45 +01:00
ListeningBean listener = new ListeningBean();
2013-04-01 15:34:19 +02:00
// the listener will be registered using a weak-reference if not configured otherwise with @Listener
2012-10-28 09:16:47 +01:00
bus.subscribe(listener);
// objects without handlers will be ignored
bus.subscribe(new ClassWithoutAnyDefinedHandlers());
2012-10-28 09:11:45 +01:00
2012-11-13 19:39:23 +01:00
Message publication:
2012-10-28 09:11:45 +01:00
TestMessage message = new TestMessage();
TestMessage subMessage = new SubTestMessage();
2012-10-28 09:11:45 +01:00
bus.publishAsync(message); //returns immediately, publication will continue asynchronously
bus.post(message).asynchronously(); // same as above
bus.publish(subMessage); // will return after each handler has been invoked
bus.post(subMessage).now(); // same as above
2012-10-28 09:11:45 +01:00
2012-11-20 14:15:15 +01:00
<h2>Installation</h2>
2013-04-01 15:13:52 +02:00
Beginning with version 1.1.0 MBassador is available from the Maven Central Repository using the following coordinates:
2013-04-01 15:40:58 +02:00
```xml
<dependency>
<groupId>net.engio</groupId>
<artifactId>mbassador</artifactId>
2013-04-01 16:21:59 +02:00
<version>1.1.6</version>
2013-04-01 15:40:58 +02:00
</dependency>
```
2013-04-01 15:39:44 +02:00
2012-11-19 16:10:40 +01:00
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
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.
2012-11-19 16:10:40 +01:00
2012-12-25 16:52:37 +01:00
<h2>Release Notes</h2>
2013-05-26 18:20:32 +02:00
<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
+ Prevented dispatcher threads from dying on exceptions
+ Improved test-infrastructure and increased test-coverage
+ Thanks for your feedback!
2013-04-01 16:21:59 +02:00
<h3>1.1.6</h3>
2013-04-01 15:13:52 +02:00
+ Added support for choosing between strong and weak references using the new @Listener annotation. @Listener can be
added to any class that defines message handlers and allows to configure which reference type is used
+ Custom handler invocations: It is possible to provide a custom handler invocation for each message handler, see "invocation"
property of @Handler
+ Changed packaging to "bundle" to support OSGI environments
+ Synchronization of message handlers via @Synchronized: Handlers that are not thread-safe can be synchronized to guarantee
that only one thread at a time can invoke that handler
+ Created a message bus implementation that does not use threading to support use in non-multi-threaded environments like GWT,
see ISyncMessageBus
<h3>1.1.3</h3>
+ Added support for FilteredMessage event
+ Renamed @Listener to @Handler and DeadEvent to DeadMessage to increase alignment with the established terminology.
Sorry for the inconvenience since this will lead to compile errors but good old find&replace will do
+ Repackaging and refactoring of some parts
+ Introduced message publication factories as configurable components to make MBassador more extensible/customizable
+ Added more documentation and unit tests
<h3>1.1.1</h3>
+ Added support for DeadMessage event
+ Introduced new property to @Handler annotation that allows to activate/deactivate any message handler
+ Full support of proxies created by cglib
+ Message handler inheritance changed! See wiki page about handler definition for more details.
+ Changed @Handler property "dispatch" to "delivery" and renamed the associated enumeration values to
more precisely indicate their meaning
+ Added more unit tests
2013-01-09 17:43:35 +01:00
<h3>1.1.0</h3>
First stable release!
+ Refactoring and repackaging
+ More exhaustive unit tests
2013-01-10 13:18:01 +01:00
+ Installation from the central repository
2013-01-09 17:43:35 +01:00
2012-12-25 16:52:37 +01:00
<h3>1.0.6.RC</h3>
+ Fixed behaviour with capacity bound blocking queue such that there now are two methods to schedule a message
asynchronously. One will block until capacity becomes available, the other will timeout after a specified amount of
time.
2013-04-01 15:13:52 +02:00
+ Additional unit tests
2012-12-25 16:52:37 +01:00
<h3>1.0.5.RC</h3>
+ Added MessageEnvelope and @Enveloped annotation to configure handlers that might receive arbitrary message type
+ Added handler configuration property to @Handler annotation to move from message filtering to more specific implementation
2012-12-25 16:52:37 +01:00
of this feature
<h3>1.0.4.RC</h3>
+ Introduced BusConfiguration as a central class to encapsulate configurational aspects
2012-11-20 14:15:15 +01:00
<h2>Roadmap</h2>
2012-11-13 19:39:23 +01:00
+ Spring integration with support for conditional message dispatch in transactional context (dispatch only after
2012-11-21 00:46:23 +01:00
successful commit etc.). Currently in beta, see <a href="https://github.com/bennidi/mbassador-spring">this</a> repository
2012-11-20 14:12:57 +01:00
2012-11-20 14:15:15 +01:00
<h2>Credits</h2>
The initial inspiration for creating this component came from trying out Google Guava's event bus implementation.
I liked the simplicity of its design and I do trust the developers at Google a lot, so I was happy to find that they also
provided an event bus system. The main reason it proved to be unusable for our scenario was that it uses strong references
to the listeners such that every object has to be explicitly deregistered. This was difficult in our Spring managed environment.
2013-03-06 12:08:48 +01:00
Finally, I decided to create a custom implementation, which then matured to be stable, extensible and yet very efficient.
2012-12-25 16:52:37 +01:00
I want to thank the development team from friendsurance (www.friendsurance.de) for their support and feedback on the bus
implementation and the management of friendsurance for allowing me to publish the component as an open source project.
2012-11-20 14:18:03 +01:00
2012-11-21 00:00:18 +01:00
<h2>Contribute</h2>
Any feature requests and feedback are more than welcome. You may suggest improvements either by submitting an
issue or by forking the repo and creating a pull request. I will try to respond as quickly as possible.
2012-10-23 10:37:19 +02:00
Sample code and documentation are both very appreciated contributions. Especially integration with different frameworks
such as Spring, Guice or other is of great value. Feel free and welcome to create Wiki pages to share your code and ideas.
2012-11-20 14:15:15 +01:00
<h2>License</h2>
2012-10-30 14:22:56 +01:00
This project is distributed under the terms of the MIT License. See file "LICENSE" for further reference.
2012-10-23 10:37:19 +02:00
2012-11-21 00:00:18 +01:00