Release 1.1.4
This commit is contained in:
parent
f52fc0e681
commit
12a3e778e9
58
README.md
58
README.md
@ -8,7 +8,7 @@ data structure to allow high throughput for concurrent access.
|
|||||||
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>
|
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>
|
||||||
which also contains a partial list of the features of the compared implementations.
|
which also contains a partial list of the features of the compared implementations.
|
||||||
|
|
||||||
The current version is 1.1.3 and it is available from the Maven Central Repository. See the release notes for more details.
|
The current version is 1.1.4 and it is available from the Maven Central Repository. See the release notes for more details.
|
||||||
|
|
||||||
Table of contents:
|
Table of contents:
|
||||||
+ [Features](#features)
|
+ [Features](#features)
|
||||||
@ -33,10 +33,11 @@ This means that listeners will also receivesubtypes of the message type they are
|
|||||||
+ <em><strong>Synchronous and asynchronous message delivery</em></strong>: A handler can be invoked to handle a message either synchronously or
|
+ <em><strong>Synchronous and asynchronous message delivery</em></strong>: A handler can be invoked to handle a message either synchronously or
|
||||||
asynchronously. This is configurable for each handler via annotations. Message publication itself supports synchronous (method
|
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
|
blocks until messages are delivered to all handlers) or asynchronous (fire and forget) dispatch
|
||||||
+ <em><strong>Weak references</em></strong>: MBassador uses weak references to all listening objects to relieve the programmer of the burden to explicitly unregister
|
+ <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
|
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.
|
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, the bus can be configured to use strong references.
|
||||||
+ <em><strong>Filtering</em></strong>: MBassador offers static message filtering. Filters are configured using annotations and multiple filters can be attached to
|
+ <em><strong>Filtering</em></strong>: MBassador offers static message filtering. Filters are configured using annotations and multiple filters can be attached to
|
||||||
a single message handler
|
a single message handler
|
||||||
+ <em><strong>Message envelopes</em></strong>: Message handlers can declare to receive an enveloped message. The envelope can wrap different
|
+ <em><strong>Message envelopes</em></strong>: Message handlers can declare to receive an enveloped message. The envelope can wrap different
|
||||||
@ -58,7 +59,7 @@ sending messages to your listeners using one of MBassador's publication methods
|
|||||||
|
|
||||||
<h2>Usage</h2>
|
<h2>Usage</h2>
|
||||||
|
|
||||||
Listener definition (in any bean):
|
Handler definition (in any bean):
|
||||||
|
|
||||||
// every message of type TestMessage or any subtype will be delivered
|
// every message of type TestMessage or any subtype will be delivered
|
||||||
// to this handler
|
// to this handler
|
||||||
@ -67,8 +68,15 @@ Listener definition (in any bean):
|
|||||||
// do something
|
// do something
|
||||||
}
|
}
|
||||||
|
|
||||||
// this handler will be invoked concurrently
|
// every message of type TestMessage or any subtype will be delivered
|
||||||
@Handler(delivery = Mode.Concurrent)
|
// 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)
|
||||||
public void handleSubTestMessage(SubTestMessage message) {
|
public void handleSubTestMessage(SubTestMessage message) {
|
||||||
// do something more expensive here
|
// do something more expensive here
|
||||||
}
|
}
|
||||||
@ -90,6 +98,15 @@ Listener definition (in any bean):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// configure a listener to be stored using strong instead of weak references
|
||||||
|
@Listener(references = References.Strong)
|
||||||
|
public class MessageListener{
|
||||||
|
|
||||||
|
// any handler definitions
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Creation of message bus and registration of listeners:
|
Creation of message bus and registration of listeners:
|
||||||
|
|
||||||
// create as many instances as necessary
|
// create as many instances as necessary
|
||||||
@ -113,22 +130,8 @@ Message publication:
|
|||||||
bus.post(subMessage).now(); // same as above
|
bus.post(subMessage).now(); // same as above
|
||||||
|
|
||||||
<h2>Installation</h2>
|
<h2>Installation</h2>
|
||||||
Beginning with version 1.1.0 MBassador is available from the Maven Central Repository (Hooray!). Older versions are
|
Beginning with version 1.1.0 MBassador is available from the Maven Central Repository using the following coordinates:
|
||||||
still available from the included maven repository in this github repo but will be deleted in the future.
|
|
||||||
The recommended way of using MBassador in your project is to add the dependency as shown in step two. Step one is only necessary
|
|
||||||
if you want to use an older version that is not available in the central repository.
|
|
||||||
|
|
||||||
1. Add the repository location to your pom.xml
|
|
||||||
<pre><code class="xml">
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>mbassador-github-repo</id>
|
|
||||||
<url>https://raw.github.com/bennidi/mbassador/master/maven </url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
</pre></code>
|
|
||||||
2. Add the MBassador dependency to your pom.xml. You can check which versions are available by browsing
|
|
||||||
the git repository online.
|
|
||||||
<pre><code class="xml">
|
<pre><code class="xml">
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.engio</groupId>
|
<groupId>net.engio</groupId>
|
||||||
@ -136,7 +139,6 @@ if you want to use an older version that is not available in the central reposit
|
|||||||
<version>1.1.0</version>
|
<version>1.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</pre></code>
|
</pre></code>
|
||||||
3. Run mvn clean package to have maven download and install the required version into your local repository
|
|
||||||
|
|
||||||
Of course you can always clone the repository and build from source.
|
Of course you can always clone the repository and build from source.
|
||||||
|
|
||||||
@ -147,6 +149,18 @@ to avoid confusion and misunderstanding.
|
|||||||
|
|
||||||
<h2>Release Notes</h2>
|
<h2>Release Notes</h2>
|
||||||
|
|
||||||
|
<h3>1.1.4</h3>
|
||||||
|
|
||||||
|
+ 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>
|
<h3>1.1.3</h3>
|
||||||
|
|
||||||
+ Added support for FilteredMessage event
|
+ Added support for FilteredMessage event
|
||||||
@ -179,7 +193,7 @@ First stable release!
|
|||||||
+ Fixed behaviour with capacity bound blocking queue such that there now are two methods to schedule a message
|
+ 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
|
asynchronously. One will block until capacity becomes available, the other will timeout after a specified amount of
|
||||||
time.
|
time.
|
||||||
+ Added unit tests
|
+ Additional unit tests
|
||||||
|
|
||||||
<h3>1.0.5.RC</h3>
|
<h3>1.0.5.RC</h3>
|
||||||
|
|
||||||
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
d53edd50a68307a4c209fd21fa0625d7
|
|
@ -1 +0,0 @@
|
|||||||
f2ed26a15178d83c80212ccce73584e97e7d6fb8
|
|
@ -1,58 +0,0 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>org.mbassy</groupId>
|
|
||||||
<artifactId>mbassador</artifactId>
|
|
||||||
<version>1.0.0.RC</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<name>mbassador</name>
|
|
||||||
<description>Mbassador is a fast and flexible message bus system that follows the publish subscribe pattern
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.build.java.version>1.6</project.build.java.version>
|
|
||||||
<github.url>file://${project.basedir}/maven</github.url>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.10</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<distributionManagement>
|
|
||||||
<repository>
|
|
||||||
<id>mbassador-github-repo</id>
|
|
||||||
<url>${github.url}</url>
|
|
||||||
</repository>
|
|
||||||
</distributionManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>${project.build.java.version}</source>
|
|
||||||
<target>${project.build.java.version}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skipTests>false</skipTests>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
@ -1 +0,0 @@
|
|||||||
760688c8fb33fc90918146e68dab2646
|
|
@ -1 +0,0 @@
|
|||||||
0abf762df11d85841f8f8b7f28361ff19549f019
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
933328ff6220f5910770b9b5f13f2eeb
|
|
@ -1 +0,0 @@
|
|||||||
003aa85106cfbab5ce618ffd1a6fe36cd0e37b71
|
|
@ -1,58 +0,0 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>org.mbassy</groupId>
|
|
||||||
<artifactId>mbassador</artifactId>
|
|
||||||
<version>1.0.1.RC</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<name>mbassador</name>
|
|
||||||
<description>Mbassador is a fast and flexible message bus system that follows the publish subscribe pattern
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.build.java.version>1.6</project.build.java.version>
|
|
||||||
<github.url>file://${project.basedir}/maven</github.url>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.10</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<distributionManagement>
|
|
||||||
<repository>
|
|
||||||
<id>mbassador-github-repo</id>
|
|
||||||
<url>${github.url}</url>
|
|
||||||
</repository>
|
|
||||||
</distributionManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>${project.build.java.version}</source>
|
|
||||||
<target>${project.build.java.version}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skipTests>false</skipTests>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
@ -1 +0,0 @@
|
|||||||
5959d236fd411d499f3b46ecedc28a84
|
|
@ -1 +0,0 @@
|
|||||||
5203632e409974a234ff8ce0ea88c5897a8cbffe
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
5ad621adc6addc2292ee1fc7a2bd756d
|
|
@ -1 +0,0 @@
|
|||||||
258a17785e15390e868efe2a51d5370aeb602129
|
|
@ -1,58 +0,0 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>org.mbassy</groupId>
|
|
||||||
<artifactId>mbassador</artifactId>
|
|
||||||
<version>1.0.2.RC</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<name>mbassador</name>
|
|
||||||
<description>Mbassador is a fast and flexible message bus system that follows the publish subscribe pattern
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.build.java.version>1.6</project.build.java.version>
|
|
||||||
<github.url>file://${project.basedir}/maven</github.url>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.10</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<distributionManagement>
|
|
||||||
<repository>
|
|
||||||
<id>mbassador-github-repo</id>
|
|
||||||
<url>${github.url}</url>
|
|
||||||
</repository>
|
|
||||||
</distributionManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>${project.build.java.version}</source>
|
|
||||||
<target>${project.build.java.version}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skipTests>false</skipTests>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
@ -1 +0,0 @@
|
|||||||
f7972cec0f8ebde2a2a17a678ef36eb6
|
|
@ -1 +0,0 @@
|
|||||||
f8c24fe42f192dbdd1f5d2b29bff0220d40039dd
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
2bcfd233f83cb6fc4241c91a99f74030
|
|
@ -1 +0,0 @@
|
|||||||
20df67988104be77a9c3e2edbb8ba615a664671b
|
|
@ -1,58 +0,0 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>org.mbassy</groupId>
|
|
||||||
<artifactId>mbassador</artifactId>
|
|
||||||
<version>1.0.3.RC</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<name>mbassador</name>
|
|
||||||
<description>Mbassador is a fast and flexible message bus system that follows the publish subscribe pattern
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.build.java.version>1.6</project.build.java.version>
|
|
||||||
<github.url>file://${project.basedir}/maven</github.url>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.10</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<distributionManagement>
|
|
||||||
<repository>
|
|
||||||
<id>mbassador-github-repo</id>
|
|
||||||
<url>${github.url}</url>
|
|
||||||
</repository>
|
|
||||||
</distributionManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>${project.build.java.version}</source>
|
|
||||||
<target>${project.build.java.version}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skipTests>false</skipTests>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
@ -1 +0,0 @@
|
|||||||
d766622aea3238ee52a60920313274d1
|
|
@ -1 +0,0 @@
|
|||||||
55c27ec10ee4067843f05fb735a2af95bc2c06cf
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
2dcb34daf560ac4b9a87a95924aa7be6
|
|
@ -1 +0,0 @@
|
|||||||
275d892046554f6a86226d813202c5ab8a22cf92
|
|
@ -1,58 +0,0 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>org.mbassy</groupId>
|
|
||||||
<artifactId>mbassador</artifactId>
|
|
||||||
<version>1.0.4.RC</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<name>mbassador</name>
|
|
||||||
<description>Mbassador is a fast and flexible message bus system that follows the publish subscribe pattern
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.build.java.version>1.6</project.build.java.version>
|
|
||||||
<github.url>file://${project.basedir}/maven</github.url>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.10</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<distributionManagement>
|
|
||||||
<repository>
|
|
||||||
<id>mbassador-github-repo</id>
|
|
||||||
<url>${github.url}</url>
|
|
||||||
</repository>
|
|
||||||
</distributionManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>${project.build.java.version}</source>
|
|
||||||
<target>${project.build.java.version}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skipTests>false</skipTests>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
@ -1 +0,0 @@
|
|||||||
75dda79a70a43a84877c3d62fdef401d
|
|
@ -1 +0,0 @@
|
|||||||
ed21bd9587e9ee76e63b31ede3cbb6eedb04fa70
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
3ad14134e9752e3a073c75ab296427ef
|
|
@ -1 +0,0 @@
|
|||||||
bedef44bb92cbfafcba48624c91e185d692ea39d
|
|
@ -1,58 +0,0 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>org.mbassy</groupId>
|
|
||||||
<artifactId>mbassador</artifactId>
|
|
||||||
<version>1.0.5.RC</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<name>mbassador</name>
|
|
||||||
<description>Mbassador is a fast and flexible message bus system that follows the publish subscribe pattern
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.build.java.version>1.6</project.build.java.version>
|
|
||||||
<github.url>file://${project.basedir}/maven</github.url>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.10</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<distributionManagement>
|
|
||||||
<repository>
|
|
||||||
<id>mbassador-github-repo</id>
|
|
||||||
<url>${github.url}</url>
|
|
||||||
</repository>
|
|
||||||
</distributionManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>${project.build.java.version}</source>
|
|
||||||
<target>${project.build.java.version}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skipTests>false</skipTests>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
@ -1 +0,0 @@
|
|||||||
0a781a5e9f22e5dafeb7f48fff65e46d
|
|
@ -1 +0,0 @@
|
|||||||
4378b82fa04f4c31f21321424d0c4c328905d3ad
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
dac16b8c129ee38d08e63d4cd487bdc9
|
|
@ -1 +0,0 @@
|
|||||||
110fd15551d0a40fafd46cc4e66c590e4d1b2fc7
|
|
@ -1,58 +0,0 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>org.mbassy</groupId>
|
|
||||||
<artifactId>mbassador</artifactId>
|
|
||||||
<version>1.0.6.RC</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<name>mbassador</name>
|
|
||||||
<description>Mbassador is a fast and flexible message bus system that follows the publish subscribe pattern
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.build.java.version>1.6</project.build.java.version>
|
|
||||||
<github.url>file://${project.basedir}/maven</github.url>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.10</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<distributionManagement>
|
|
||||||
<repository>
|
|
||||||
<id>mbassador-github-repo</id>
|
|
||||||
<url>${github.url}</url>
|
|
||||||
</repository>
|
|
||||||
</distributionManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>${project.build.java.version}</source>
|
|
||||||
<target>${project.build.java.version}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skipTests>false</skipTests>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
@ -1 +0,0 @@
|
|||||||
ebf2e22bfe53d858092befaa865d0bf4
|
|
@ -1 +0,0 @@
|
|||||||
950ca7e831a9060060f943ca02d313f7c7f5ccbf
|
|
@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<metadata>
|
|
||||||
<groupId>org.mbassy</groupId>
|
|
||||||
<artifactId>mbassador</artifactId>
|
|
||||||
<version>1.0.7.RC-SNAPSHOT</version>
|
|
||||||
<versioning>
|
|
||||||
<snapshot>
|
|
||||||
<timestamp>20121229.133808</timestamp>
|
|
||||||
<buildNumber>1</buildNumber>
|
|
||||||
</snapshot>
|
|
||||||
<lastUpdated>20121229133808</lastUpdated>
|
|
||||||
</versioning>
|
|
||||||
</metadata>
|
|
@ -1 +0,0 @@
|
|||||||
732608242394f6b316a7cf631208b635
|
|
@ -1 +0,0 @@
|
|||||||
2cae8933661f8cf18afc2c923436c2457e0b3809
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
d20f34dc532b790786a74566598e5e68
|
|
@ -1 +0,0 @@
|
|||||||
13de5221308cf546ff55aa6b5a35ec1f78ecf691
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
ec63e6aa1e908e4036cca782675742df
|
|
@ -1 +0,0 @@
|
|||||||
79eb0716f839f2b63cf5d3d9796800967d54fdb5
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
21ac5231ee676ba2461e31392e210b54
|
|
@ -1 +0,0 @@
|
|||||||
9cfcc0fe9534d2a530b48445331d451b97ca3342
|
|
@ -1,152 +0,0 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>org.mbassy</groupId>
|
|
||||||
<artifactId>mbassador</artifactId>
|
|
||||||
<version>1.0.7.RC-SNAPSHOT</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<name>mbassador</name>
|
|
||||||
<description>
|
|
||||||
Mbassador is a fast and flexible message bus system following the publish subscribe pattern.
|
|
||||||
It is designed for ease of use and aims to be feature rich and extensible
|
|
||||||
while preserving resource efficiency and performance.
|
|
||||||
|
|
||||||
It features:
|
|
||||||
declarative listener definition via annotations,
|
|
||||||
sync and/or async message delivery,
|
|
||||||
weak-references,
|
|
||||||
message filtering,
|
|
||||||
ordering of message handlers etc.
|
|
||||||
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<url>https://github.com/bennidi/mbassador</url>
|
|
||||||
<licenses>
|
|
||||||
<license>
|
|
||||||
<name>MIT license</name>
|
|
||||||
<url>http://www.opensource.org/licenses/mit-license.php</url>
|
|
||||||
</license>
|
|
||||||
</licenses>
|
|
||||||
<scm>
|
|
||||||
<url>scm:git:git@github.com:bennidi/mbassador.git</url>
|
|
||||||
<connection>scm:git:git@github.com:bennidi/mbassador.git</connection>
|
|
||||||
</scm>
|
|
||||||
<developers>
|
|
||||||
|
|
||||||
<developer>
|
|
||||||
<id>bennidi</id>
|
|
||||||
<name>Benjamin Diedrichsen</name>
|
|
||||||
<timezone>+1</timezone>
|
|
||||||
</developer>
|
|
||||||
</developers>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.build.java.version>1.6</project.build.java.version>
|
|
||||||
<github.url>file://${project.basedir}/maven</github.url>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.10</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<distributionManagement>
|
|
||||||
<repository>
|
|
||||||
<id>mbassador-github-repo</id>
|
|
||||||
<url>${github.url}</url>
|
|
||||||
</repository>
|
|
||||||
</distributionManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>${project.build.java.version}</source>
|
|
||||||
<target>${project.build.java.version}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-release-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skipTests>false</skipTests>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<!-- bind the source attaching to package phase -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>attach-sources</id>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>attach-javadocs</id>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>release-sign-artifacts</id>
|
|
||||||
<activation>
|
|
||||||
<property>
|
|
||||||
<name>performRelease</name>
|
|
||||||
<value>true</value>
|
|
||||||
</property>
|
|
||||||
</activation>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
|
||||||
<version>1.4</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>sign-artifacts</id>
|
|
||||||
<phase>verify</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>sign</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
</project>
|
|
@ -1 +0,0 @@
|
|||||||
05e16f4d46db6bc39529ebe889ff552d
|
|
@ -1 +0,0 @@
|
|||||||
5e078c7f168816392ca34e41cbc8f58c81b8c5d9
|
|
@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<metadata>
|
|
||||||
<groupId>org.mbassy</groupId>
|
|
||||||
<artifactId>mbassador</artifactId>
|
|
||||||
<version>1.0.0.RC</version>
|
|
||||||
<versioning>
|
|
||||||
<versions>
|
|
||||||
<version>1.0.0.RC</version>
|
|
||||||
<version>1.0.1.RC</version>
|
|
||||||
<version>1.0.2.RC</version>
|
|
||||||
<version>1.0.3.RC</version>
|
|
||||||
<version>1.0.4.RC</version>
|
|
||||||
<version>1.0.5.RC</version>
|
|
||||||
<version>1.0.6.RC</version>
|
|
||||||
<version>1.0.7.RC-SNAPSHOT</version>
|
|
||||||
</versions>
|
|
||||||
<lastUpdated>20121229133808</lastUpdated>
|
|
||||||
</versioning>
|
|
||||||
</metadata>
|
|
@ -1 +0,0 @@
|
|||||||
46231d9bfb55280deeea69a9e18ed52b
|
|
@ -1 +0,0 @@
|
|||||||
3608eef0e3183c20460c8b1839c6a3d5740dd63e
|
|
@ -18,9 +18,10 @@ The basic contract of the bus is that it will deliver a specific message exactly
|
|||||||
Currently, message handlers will be invoked in inverse sequence of subscription but any
|
Currently, message handlers will be invoked in inverse sequence of subscription but any
|
||||||
client using this bus should not rely on this assumption.
|
client using this bus should not rely on this assumption.
|
||||||
|
|
||||||
The bus uses weak references to all listeners such that registered listeners do not need to
|
By default, the bus uses weak references to all listeners such that registered listeners do not need to
|
||||||
be explicitly unregistered to be eligible for garbage collection. Dead (garbage collected) listeners are
|
be explicitly unregistered to be eligible for garbage collection. Dead (garbage collected) listeners are
|
||||||
removed on-the-fly as messages get published.
|
removed on-the-fly as messages get published. It is possible to enable the use of strong references on the message handler
|
||||||
|
level.
|
||||||
|
|
||||||
Unsubscribing a listener means removing all subscribed message handlers of that listener. This remove operation
|
Unsubscribing a listener means removing all subscribed message handlers of that listener. This remove operation
|
||||||
immediately effects all running publications processes -> A removed listener will under no circumstances receive any message publications.
|
immediately effects all running publications processes -> A removed listener will under no circumstances receive any message publications.
|
||||||
|
@ -10,10 +10,17 @@ filters, delivery modes etc.
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>delivery</td>
|
<td>delivery</td>
|
||||||
<td>Message delivery can either run sequentially(i.e. one listener at a time) or concurrently
|
<td>Message handler invocation can be configured to run
|
||||||
(i.e. multiple threads are used to deliver the same message to different listeners).
|
<ul>
|
||||||
Note:The number of parallel threads is configurable per instance using the BusConfiguration</td>
|
<li>Synchronously: One handler at a time within a given message publication. Each invocation occurs from the same thread</li>
|
||||||
<td>Sequential</td>
|
<li>Asynchronously: Multiple threads are used within a given message publication. Each handler invocation
|
||||||
|
runs in a separate thread.Note:The number of parallel threads is configurable per instance using the BusConfiguration</li>
|
||||||
|
</ul>
|
||||||
|
Note: Use @Synchronized if your handler does not allow multiple, concurrent message publications, i.e.
|
||||||
|
handlers that are not thread-safe but are used in a multi-threaded environment where asynchronous message publication
|
||||||
|
is possible.
|
||||||
|
</td>
|
||||||
|
<td>Synchronously</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@ -42,6 +49,21 @@ filters, delivery modes etc.
|
|||||||
<td>true</td>
|
<td>true</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>strongReferencess</td>
|
||||||
|
<td>Whether the bus should use storng references to the listeners instead of weak references
|
||||||
|
</td>
|
||||||
|
<td>false</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>invocation</td>
|
||||||
|
<td>Specify a custom implementation for the handler invocation. By default, a generic implementation
|
||||||
|
that uses reflection will be used. Note: A custom implementation will not be faster than the generic one
|
||||||
|
since there are heavy optimizations by the JVM using JIT-Compiler and more.
|
||||||
|
</td>
|
||||||
|
<td>false</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -59,22 +81,22 @@ receive all messages of type TestEvent or any subtype sequentially.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
This handler will receive all messages of type SubTestEvent or any subtype concurrently
|
This handler will receive all messages of type SubTestEvent or any subtype
|
||||||
|
|
||||||
// this handler will be invoked concurrently
|
// handler invocation will occur in a different thread
|
||||||
@Handler(delivery = Mode.Concurrent)
|
@Handler(delivery = Invoke.Asynchronously)
|
||||||
public void handleSubTestEvent(SubTestEvent event) {
|
public void handleSubTestEvent(SubTestEvent event) {
|
||||||
// do something more expensive here
|
// do something more expensive here
|
||||||
}
|
}
|
||||||
|
|
||||||
This handler will receive all messages of type SubTestEvent or any subtype sequentially,
|
This handler will receive all messages of type SubTestEvent or any subtype,
|
||||||
given that they pass the specified filters. This handler will be invoked before the formerly
|
given that they pass the specified filters. This handler will be invoked before the formerly
|
||||||
defined one, since it specifies a higher priority
|
defined one, since it specifies a higher priority
|
||||||
|
|
||||||
// this handler will receive messages of type SubTestEvent
|
// this handler will receive messages of type SubTestEvent
|
||||||
// or any of its sub types that passe the given filter(s)
|
// or any of its sub types that passe the given filter(s)
|
||||||
@Handler(priority = 10,
|
@Handler(priority = 10,
|
||||||
dispatch = Mode.Synchronous,
|
dispatch = Invoke.Synchronously,
|
||||||
filters = {@Filter(Filters.SpecialEvent.class)})
|
filters = {@Filter(Filters.SpecialEvent.class)})
|
||||||
public void handleFiltered(SubTestEvent event) {
|
public void handleFiltered(SubTestEvent event) {
|
||||||
//do something special here
|
//do something special here
|
||||||
@ -112,8 +134,8 @@ Message handler inheritance corresponds to inheritance of methods as defined in
|
|||||||
A subclass of any class that defines message handlers will inherit these handler and their configuration.
|
A subclass of any class that defines message handlers will inherit these handler and their configuration.
|
||||||
It is possible to change (override) the configuration simply by overriding the super class' method and
|
It is possible to change (override) the configuration simply by overriding the super class' method and
|
||||||
specifying a different configuration. This way, it is also possible to deactivate a message handler of
|
specifying a different configuration. This way, it is also possible to deactivate a message handler of
|
||||||
a super class by using the "enabled" property on the overridden method.
|
a super class by setting the "enabled" property to "false" on the overridden method.
|
||||||
If a class overrides a method that is configured as a message handler in one of its super classes
|
If a class overrides a method that is already configured as a message handler
|
||||||
it is still considered a message handler but of course the implementation of the overriding class
|
it is still considered a message handler but of course the implementation of the overriding class
|
||||||
will be used.
|
will be used.
|
||||||
|
|
||||||
|
29
src/main/java/net/engio/mbassy/MessageBusException.java
Normal file
29
src/main/java/net/engio/mbassy/MessageBusException.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package net.engio.mbassy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Todo: Add javadoc
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/29/13
|
||||||
|
*/
|
||||||
|
public class MessageBusException extends Exception{
|
||||||
|
|
||||||
|
public MessageBusException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBusException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBusException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBusException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBusException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package net.engio.mbassy.bus;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base class for all message bus implementations.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* @param <P>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractSyncAsyncMessageBus<T, P extends IMessageBus.IPostCommand> extends AbstractSyncMessageBus<T, P> implements IMessageBus<T, P> {
|
||||||
|
|
||||||
|
// executor for asynchronous message handlers
|
||||||
|
private final ExecutorService executor;
|
||||||
|
|
||||||
|
// all threads that are available for asynchronous message dispatching
|
||||||
|
private final List<Thread> dispatchers;
|
||||||
|
|
||||||
|
// all pending messages scheduled for asynchronous dispatch are queued here
|
||||||
|
private final BlockingQueue<MessagePublication> pendingMessages;
|
||||||
|
|
||||||
|
public AbstractSyncAsyncMessageBus(BusConfiguration configuration) {
|
||||||
|
super(configuration);
|
||||||
|
this.executor = configuration.getExecutor();
|
||||||
|
pendingMessages = new LinkedBlockingQueue<MessagePublication>(configuration.getMaximumNumberOfPendingMessages());
|
||||||
|
dispatchers = new ArrayList<Thread>(configuration.getNumberOfMessageDispatchers());
|
||||||
|
initDispatcherThreads(configuration.getNumberOfMessageDispatchers());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// initialize the dispatch workers
|
||||||
|
private void initDispatcherThreads(int numberOfThreads) {
|
||||||
|
for (int i = 0; i < numberOfThreads; i++) {
|
||||||
|
// each thread will run forever and process incoming
|
||||||
|
//dispatch requests
|
||||||
|
Thread dispatcher = new Thread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
pendingMessages.take().execute();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dispatcher.setDaemon(true); // do not prevent the JVM from exiting
|
||||||
|
dispatchers.add(dispatcher);
|
||||||
|
dispatcher.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// this method enqueues a message delivery request
|
||||||
|
protected MessagePublication addAsynchronousDeliveryRequest(MessagePublication request) {
|
||||||
|
try {
|
||||||
|
pendingMessages.put(request);
|
||||||
|
return request.markScheduled();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return request.setError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this method enqueues a message delivery request
|
||||||
|
protected MessagePublication addAsynchronousDeliveryRequest(MessagePublication request, long timeout, TimeUnit unit) {
|
||||||
|
try {
|
||||||
|
return pendingMessages.offer(request, timeout, unit)
|
||||||
|
? request.markScheduled()
|
||||||
|
: request.setError();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return request.setError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
shutdown();
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
for (Thread dispatcher : dispatchers) {
|
||||||
|
dispatcher.interrupt();
|
||||||
|
}
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPendingMessages() {
|
||||||
|
return pendingMessages.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Executor getExecutor() {
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,22 +9,8 @@ import net.engio.mbassy.subscription.Subscription;
|
|||||||
import net.engio.mbassy.subscription.SubscriptionContext;
|
import net.engio.mbassy.subscription.SubscriptionContext;
|
||||||
import net.engio.mbassy.subscription.SubscriptionFactory;
|
import net.engio.mbassy.subscription.SubscriptionFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
import java.util.concurrent.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base class for all message bus implementations.
|
* The base class for all message bus implementations.
|
||||||
@ -32,10 +18,8 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* @param <T>
|
* @param <T>
|
||||||
* @param <P>
|
* @param <P>
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractMessageBus<T, P extends IMessageBus.IPostCommand> implements IMessageBus<T, P> {
|
public abstract class AbstractSyncMessageBus<T, P extends ISyncMessageBus.ISyncPostCommand> implements ISyncMessageBus<T, P> {
|
||||||
|
|
||||||
// executor for asynchronous listeners using unbound queuing strategy to ensure that no events get lost
|
|
||||||
private final ExecutorService executor;
|
|
||||||
|
|
||||||
// the metadata reader that is used to parse objects passed to the subscribe method
|
// the metadata reader that is used to parse objects passed to the subscribe method
|
||||||
private final MetadataReader metadataReader;
|
private final MetadataReader metadataReader;
|
||||||
@ -58,12 +42,6 @@ public abstract class AbstractMessageBus<T, P extends IMessageBus.IPostCommand>
|
|||||||
// this handler will receive all errors that occur during message dispatch or message handling
|
// this handler will receive all errors that occur during message dispatch or message handling
|
||||||
private final List<IPublicationErrorHandler> errorHandlers = new CopyOnWriteArrayList<IPublicationErrorHandler>();
|
private final List<IPublicationErrorHandler> errorHandlers = new CopyOnWriteArrayList<IPublicationErrorHandler>();
|
||||||
|
|
||||||
// all threads that are available for asynchronous message dispatching
|
|
||||||
private final List<Thread> dispatchers = new CopyOnWriteArrayList<Thread>();
|
|
||||||
|
|
||||||
// all pending messages scheduled for asynchronous dispatch are queued here
|
|
||||||
private final BlockingQueue<MessagePublication> pendingMessages;
|
|
||||||
|
|
||||||
// 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
|
||||||
private final SubscriptionFactory subscriptionFactory;
|
private final SubscriptionFactory subscriptionFactory;
|
||||||
@ -71,40 +49,13 @@ public abstract class AbstractMessageBus<T, P extends IMessageBus.IPostCommand>
|
|||||||
private final MessagePublication.Factory publicationFactory;
|
private final MessagePublication.Factory publicationFactory;
|
||||||
|
|
||||||
|
|
||||||
public AbstractMessageBus(BusConfiguration configuration) {
|
public AbstractSyncMessageBus(SyncBusConfiguration configuration) {
|
||||||
this.executor = configuration.getExecutor();
|
|
||||||
subscriptionFactory = configuration.getSubscriptionFactory();
|
subscriptionFactory = configuration.getSubscriptionFactory();
|
||||||
this.metadataReader = configuration.getMetadataReader();
|
this.metadataReader = configuration.getMetadataReader();
|
||||||
this.publicationFactory = configuration.getMessagePublicationFactory();
|
this.publicationFactory = configuration.getMessagePublicationFactory();
|
||||||
pendingMessages = new LinkedBlockingQueue<MessagePublication>(configuration.getMaximumNumberOfPendingMessages());
|
|
||||||
initDispatcherThreads(configuration.getNumberOfMessageDispatchers());
|
|
||||||
addErrorHandler(new IPublicationErrorHandler.ConsoleLogger());
|
addErrorHandler(new IPublicationErrorHandler.ConsoleLogger());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// initialize the dispatch workers
|
|
||||||
private void initDispatcherThreads(int numberOfThreads) {
|
|
||||||
for (int i = 0; i < numberOfThreads; i++) {
|
|
||||||
// each thread will run forever and process incoming
|
|
||||||
//dispatch requests
|
|
||||||
Thread dispatcher = new Thread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
pendingMessages.take().execute();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dispatcher.setDaemon(true); // do not prevent the JVM from exiting
|
|
||||||
dispatchers.add(dispatcher);
|
|
||||||
dispatcher.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MessagePublication.Factory getPublicationFactory() {
|
protected MessagePublication.Factory getPublicationFactory() {
|
||||||
return publicationFactory;
|
return publicationFactory;
|
||||||
}
|
}
|
||||||
@ -179,26 +130,7 @@ public abstract class AbstractMessageBus<T, P extends IMessageBus.IPostCommand>
|
|||||||
errorHandlers.add(handler);
|
errorHandlers.add(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this method enqueues a message delivery request
|
|
||||||
protected MessagePublication addAsynchronousDeliveryRequest(MessagePublication request) {
|
|
||||||
try {
|
|
||||||
pendingMessages.put(request);
|
|
||||||
return request.markScheduled();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
return request.setError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this method enqueues a message delivery request
|
|
||||||
protected MessagePublication addAsynchronousDeliveryRequest(MessagePublication request, long timeout, TimeUnit unit) {
|
|
||||||
try {
|
|
||||||
return pendingMessages.offer(request, timeout, unit)
|
|
||||||
? request.markScheduled()
|
|
||||||
: request.setError();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
return request.setError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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!
|
||||||
@ -241,26 +173,4 @@ public abstract class AbstractMessageBus<T, P extends IMessageBus.IPostCommand>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void finalize() throws Throwable {
|
|
||||||
shutdown();
|
|
||||||
super.finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void shutdown() {
|
|
||||||
for (Thread dispatcher : dispatchers) {
|
|
||||||
dispatcher.interrupt();
|
|
||||||
}
|
|
||||||
executor.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasPendingMessages() {
|
|
||||||
return pendingMessages.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Executor getExecutor() {
|
|
||||||
return executor;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,14 +1,6 @@
|
|||||||
package net.engio.mbassy.bus;
|
package net.engio.mbassy.bus;
|
||||||
|
|
||||||
import net.engio.mbassy.listener.MetadataReader;
|
import java.util.concurrent.*;
|
||||||
import net.engio.mbassy.subscription.SubscriptionFactory;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The bus configuration holds various parameters that can be used to customize the bus' runtime behaviour.
|
* The bus configuration holds various parameters that can be used to customize the bus' runtime behaviour.
|
||||||
@ -16,7 +8,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 12/8/12
|
* Date: 12/8/12
|
||||||
*/
|
*/
|
||||||
public class BusConfiguration {
|
public class BusConfiguration extends SyncBusConfiguration<BusConfiguration> {
|
||||||
|
|
||||||
private static final ThreadFactory DaemonThreadFactory = new ThreadFactory() {
|
private static final ThreadFactory DaemonThreadFactory = new ThreadFactory() {
|
||||||
@Override
|
@Override
|
||||||
@ -37,36 +29,11 @@ public class BusConfiguration {
|
|||||||
|
|
||||||
private int maximumNumberOfPendingMessages;
|
private int maximumNumberOfPendingMessages;
|
||||||
|
|
||||||
private SubscriptionFactory subscriptionFactory;
|
|
||||||
|
|
||||||
private MetadataReader metadataReader;
|
|
||||||
|
|
||||||
private MessagePublication.Factory messagePublicationFactory;
|
|
||||||
|
|
||||||
public BusConfiguration() {
|
public BusConfiguration() {
|
||||||
|
super();
|
||||||
this.numberOfMessageDispatchers = 2;
|
this.numberOfMessageDispatchers = 2;
|
||||||
this.maximumNumberOfPendingMessages = Integer.MAX_VALUE;
|
this.maximumNumberOfPendingMessages = Integer.MAX_VALUE;
|
||||||
this.subscriptionFactory = new SubscriptionFactory();
|
|
||||||
this.executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(), DaemonThreadFactory);
|
this.executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(), DaemonThreadFactory);
|
||||||
this.metadataReader = new MetadataReader();
|
|
||||||
this.messagePublicationFactory = new MessagePublication.Factory();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessagePublication.Factory getMessagePublicationFactory() {
|
|
||||||
return messagePublicationFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessagePublicationFactory(MessagePublication.Factory messagePublicationFactory) {
|
|
||||||
this.messagePublicationFactory = messagePublicationFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MetadataReader getMetadataReader() {
|
|
||||||
return metadataReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BusConfiguration setMetadataReader(MetadataReader metadataReader) {
|
|
||||||
this.metadataReader = metadataReader;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfMessageDispatchers() {
|
public int getNumberOfMessageDispatchers() {
|
||||||
@ -78,6 +45,10 @@ public class BusConfiguration {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default an unbound queuing strategy is used to ensure that no events get lost
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public ExecutorService getExecutor() {
|
public ExecutorService getExecutor() {
|
||||||
return executor;
|
return executor;
|
||||||
}
|
}
|
||||||
@ -98,12 +69,4 @@ public class BusConfiguration {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubscriptionFactory getSubscriptionFactory() {
|
|
||||||
return subscriptionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BusConfiguration setSubscriptionFactory(SubscriptionFactory subscriptionFactory) {
|
|
||||||
this.subscriptionFactory = subscriptionFactory;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package net.engio.mbassy.bus;
|
package net.engio.mbassy.bus;
|
||||||
|
|
||||||
import net.engio.mbassy.IPublicationErrorHandler;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@ -47,56 +44,10 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* @Author bennidi
|
* @Author bennidi
|
||||||
* Date: 2/8/12
|
* Date: 2/8/12
|
||||||
*/
|
*/
|
||||||
public interface IMessageBus<T, P extends IMessageBus.IPostCommand> {
|
public interface IMessageBus<T, P extends IMessageBus.IPostCommand> extends ISyncMessageBus<T,P> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribe all listeners of the given message to receive message publications.
|
* Get the executor service that is used for asynchronous message publications.
|
||||||
* Any message may only be subscribed once (subsequent subscriptions of an already subscribed
|
|
||||||
* message will be silently ignored)
|
|
||||||
*
|
|
||||||
* @param listener
|
|
||||||
*/
|
|
||||||
void subscribe(Object listener);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Immediately remove all registered message handlers (if any) of the given listener. When this call returns all handlers
|
|
||||||
* have effectively been removed and will not receive any message publications (including asynchronously scheduled
|
|
||||||
* publications that have been published when the message listener was still subscribed).
|
|
||||||
* <p/>
|
|
||||||
* A call to this method passing null, an already unsubscribed listener or any object that does not define any message
|
|
||||||
* handlers will not have any effect and is silently ignored.
|
|
||||||
*
|
|
||||||
* @param listener
|
|
||||||
* @return true, if the listener was found and successfully removed
|
|
||||||
* false otherwise
|
|
||||||
*/
|
|
||||||
boolean unsubscribe(Object listener);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param message
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
P post(T message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Publication errors may occur at various points of time during message delivery. A handler may throw an exception,
|
|
||||||
* may not be accessible due to security constraints or is not annotated properly.
|
|
||||||
* In any of all possible cases a publication error is created and passed to each of the registered error handlers.
|
|
||||||
* A call to this method will add the given error handler to the chain
|
|
||||||
*
|
|
||||||
* @param errorHandler
|
|
||||||
*/
|
|
||||||
void addErrorHandler(IPublicationErrorHandler errorHandler);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an immutable collection containing all the registered error handlers
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Collection<IPublicationErrorHandler> getRegisteredErrorHandlers();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the executor service that is used to asynchronous message publication.
|
|
||||||
* The executor is passed to the message bus at creation time.
|
* The executor is passed to the message bus at creation time.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
@ -111,17 +62,20 @@ public interface IMessageBus<T, P extends IMessageBus.IPostCommand> {
|
|||||||
boolean hasPendingMessages();
|
boolean hasPendingMessages();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A post command is used as an intermediate object created by a call to the message bus' post method.
|
* Shutdown the bus such that it will stop delivering asynchronous messages. Executor service and
|
||||||
* It encapsulates the functionality provided by the message bus that created the command.
|
* other internally used threads will be shutdown gracefully. After calling shutdown it is not safe
|
||||||
* Subclasses may extend this interface and add functionality, e.g. different dispatch schemes.
|
* to further use the message bus.
|
||||||
*/
|
*/
|
||||||
interface IPostCommand<T> {
|
void shutdown();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the message publication immediately. This call blocks until every matching message handler
|
* @param message
|
||||||
* has been invoked.
|
* @return
|
||||||
*/
|
*/
|
||||||
void now();
|
P post(T message);
|
||||||
|
|
||||||
|
|
||||||
|
interface IPostCommand extends ISyncPostCommand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the message publication asynchronously. The behaviour of this method depends on the
|
* Execute the message publication asynchronously. The behaviour of this method depends on the
|
||||||
@ -146,4 +100,5 @@ public interface IMessageBus<T, P extends IMessageBus.IPostCommand> {
|
|||||||
*/
|
*/
|
||||||
MessagePublication asynchronously(long timeout, TimeUnit unit);
|
MessagePublication asynchronously(long timeout, TimeUnit unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
77
src/main/java/net/engio/mbassy/bus/ISyncMessageBus.java
Normal file
77
src/main/java/net/engio/mbassy/bus/ISyncMessageBus.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package net.engio.mbassy.bus;
|
||||||
|
|
||||||
|
import net.engio.mbassy.IPublicationErrorHandler;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/29/13
|
||||||
|
*/
|
||||||
|
public interface ISyncMessageBus<T, P extends IMessageBus.ISyncPostCommand> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe all listeners of the given message to receive message publications.
|
||||||
|
* Any message may only be subscribed once (subsequent subscriptions of an already subscribed
|
||||||
|
* message will be silently ignored)
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
void subscribe(Object listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immediately remove all registered message handlers (if any) of the given listener. When this call returns all handlers
|
||||||
|
* have effectively been removed and will not receive any message publications (including asynchronously scheduled
|
||||||
|
* publications that have been published when the message listener was still subscribed).
|
||||||
|
* <p/>
|
||||||
|
* A call to this method passing null, an already unsubscribed listener or any object that does not define any message
|
||||||
|
* handlers will not have any effect and is silently ignored.
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
* @return true, if the listener was found and successfully removed
|
||||||
|
* false otherwise
|
||||||
|
*/
|
||||||
|
boolean unsubscribe(Object listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
P post(T message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publication errors may occur at various points of time during message delivery. A handler may throw an exception,
|
||||||
|
* may not be accessible due to security constraints or is not annotated properly.
|
||||||
|
* In any of all possible cases a publication error is created and passed to each of the registered error handlers.
|
||||||
|
* A call to this method will add the given error handler to the chain
|
||||||
|
*
|
||||||
|
* @param errorHandler
|
||||||
|
*/
|
||||||
|
void addErrorHandler(IPublicationErrorHandler errorHandler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an immutable collection containing all the registered error handlers
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Collection<IPublicationErrorHandler> getRegisteredErrorHandlers();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A post command is used as an intermediate object created by a call to the message bus' post method.
|
||||||
|
* It encapsulates the functionality provided by the message bus that created the command.
|
||||||
|
* Subclasses may extend this interface and add functionality, e.g. different dispatch schemes.
|
||||||
|
*/
|
||||||
|
interface ISyncPostCommand {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the message publication immediately. This call blocks until every matching message handler
|
||||||
|
* has been invoked.
|
||||||
|
*/
|
||||||
|
void now();
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ import java.util.Collection;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
public class MBassador<T> extends AbstractMessageBus<T, SyncAsyncPostCommand<T>> {
|
public class MBassador<T> extends AbstractSyncAsyncMessageBus<T, SyncAsyncPostCommand<T>> {
|
||||||
|
|
||||||
public MBassador(BusConfiguration configuration) {
|
public MBassador(BusConfiguration configuration) {
|
||||||
super(configuration);
|
super(configuration);
|
||||||
|
49
src/main/java/net/engio/mbassy/bus/SyncBusConfiguration.java
Normal file
49
src/main/java/net/engio/mbassy/bus/SyncBusConfiguration.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package net.engio.mbassy.bus;
|
||||||
|
|
||||||
|
import net.engio.mbassy.listener.MetadataReader;
|
||||||
|
import net.engio.mbassy.subscription.SubscriptionFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Todo: Add javadoc
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/29/13
|
||||||
|
*/
|
||||||
|
public class SyncBusConfiguration<Config extends SyncBusConfiguration<Config>> {
|
||||||
|
|
||||||
|
protected SubscriptionFactory subscriptionFactory;
|
||||||
|
protected MetadataReader metadataReader;
|
||||||
|
protected MessagePublication.Factory messagePublicationFactory;
|
||||||
|
|
||||||
|
public SyncBusConfiguration() {
|
||||||
|
this.metadataReader = new MetadataReader();
|
||||||
|
this.subscriptionFactory = new SubscriptionFactory();
|
||||||
|
this.messagePublicationFactory = new MessagePublication.Factory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessagePublication.Factory getMessagePublicationFactory() {
|
||||||
|
return messagePublicationFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessagePublicationFactory(MessagePublication.Factory messagePublicationFactory) {
|
||||||
|
this.messagePublicationFactory = messagePublicationFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetadataReader getMetadataReader() {
|
||||||
|
return metadataReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Config setMetadataReader(MetadataReader metadataReader) {
|
||||||
|
this.metadataReader = metadataReader;
|
||||||
|
return (Config)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubscriptionFactory getSubscriptionFactory() {
|
||||||
|
return subscriptionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Config setSubscriptionFactory(SubscriptionFactory subscriptionFactory) {
|
||||||
|
this.subscriptionFactory = subscriptionFactory;
|
||||||
|
return (Config)this;
|
||||||
|
}
|
||||||
|
}
|
134
src/main/java/net/engio/mbassy/common/AbstractConcurrentSet.java
Normal file
134
src/main/java/net/engio/mbassy/common/AbstractConcurrentSet.java
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package net.engio.mbassy.common;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This data structure is optimized for non-blocking reads even when write operations occur.
|
||||||
|
* Running read iterators will not be affected by add operations since writes always insert at the head of the
|
||||||
|
* structure. Remove operations can affect any running iterator such that a removed element that has not yet
|
||||||
|
* been reached by the iterator will not appear in that iterator anymore.
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 2/12/12
|
||||||
|
*/
|
||||||
|
public abstract class AbstractConcurrentSet<T> implements IConcurrentSet<T> {
|
||||||
|
|
||||||
|
// Internal state
|
||||||
|
private final Object lock = new Object();
|
||||||
|
private final Map<T, ISetEntry<T>> entries; // maintain a map of entries for O(log n) lookup
|
||||||
|
protected Entry<T> head; // reference to the first element
|
||||||
|
|
||||||
|
protected AbstractConcurrentSet(Map<T, ISetEntry<T>> entries) {
|
||||||
|
this.entries = entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Entry<T> createEntry(T value, Entry<T> next);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IConcurrentSet<T> add(T element) {
|
||||||
|
if (element == null || entries.containsKey(element)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
synchronized (lock) {
|
||||||
|
insert(element);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(T element) {
|
||||||
|
ISetEntry<T> entry = entries.get(element);
|
||||||
|
return entry != null && entry.getValue() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insert(T element) {
|
||||||
|
if (entries.containsKey(element)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
head = createEntry(element, head);
|
||||||
|
entries.put(element, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return entries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IConcurrentSet<T> addAll(Iterable<T> elements) {
|
||||||
|
synchronized (lock) {
|
||||||
|
for (T element : elements) {
|
||||||
|
if (element == null || entries.containsKey(element)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
insert(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(T element) {
|
||||||
|
if (!entries.containsKey(element)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
synchronized (lock) {
|
||||||
|
ISetEntry<T> listelement = entries.get(element);
|
||||||
|
if (listelement == null) {
|
||||||
|
return false; //removed by other thread
|
||||||
|
}
|
||||||
|
if (listelement != head) {
|
||||||
|
listelement.remove();
|
||||||
|
} else {
|
||||||
|
ISetEntry<T> oldHead = head;
|
||||||
|
head = head.next();
|
||||||
|
oldHead.clear(); // optimize for GC
|
||||||
|
}
|
||||||
|
entries.remove(element);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public abstract static class Entry<T> implements ISetEntry<T> {
|
||||||
|
|
||||||
|
private Entry<T> next;
|
||||||
|
|
||||||
|
private Entry<T> predecessor;
|
||||||
|
|
||||||
|
protected Entry(Entry<T> next) {
|
||||||
|
this.next = next;
|
||||||
|
next.predecessor = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Entry() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// not thread-safe! must be synchronized in enclosing context
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
if (predecessor != null) {
|
||||||
|
predecessor.next = next;
|
||||||
|
if (next != null) {
|
||||||
|
next.predecessor = predecessor;
|
||||||
|
}
|
||||||
|
} else if (next != null) {
|
||||||
|
next.predecessor = null;
|
||||||
|
}
|
||||||
|
next = null;
|
||||||
|
predecessor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Entry<T> next() {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
next = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,183 +0,0 @@
|
|||||||
package net.engio.mbassy.common;
|
|
||||||
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This data structure is optimized for non-blocking reads even when write operations occur.
|
|
||||||
* Running read iterators will not be affected by add operations since writes always insert at the head of the
|
|
||||||
* structure. Remove operations can affect any running iterator such that a removed element that has not yet
|
|
||||||
* been reached by the iterator will not appear in that iterator anymore.
|
|
||||||
* <p/>
|
|
||||||
* The structure uses weak references to the elements. Iterators automatically perform cleanups of
|
|
||||||
* garbage collected objects during iteration -> no dedicated maintenance operations need to be called or run in background.
|
|
||||||
* <p/>
|
|
||||||
* <p/>
|
|
||||||
* <p/>
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 2/12/12
|
|
||||||
*/
|
|
||||||
public class ConcurrentSet<T> implements Iterable<T> {
|
|
||||||
|
|
||||||
// Internal state
|
|
||||||
private final Object lock = new Object();
|
|
||||||
private WeakHashMap<T, Entry<T>> entries = new WeakHashMap<T, Entry<T>>(); // maintain a map of entries for O(log n) lookup
|
|
||||||
private Entry<T> head; // reference to the first element
|
|
||||||
|
|
||||||
public ConcurrentSet<T> add(T element) {
|
|
||||||
if (element == null || entries.containsKey(element)) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
synchronized (lock) {
|
|
||||||
insert(element);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(T element) {
|
|
||||||
Entry<T> entry = entries.get(element);
|
|
||||||
return entry != null && entry.getValue() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void insert(T element) {
|
|
||||||
if (entries.containsKey(element)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (head == null) {
|
|
||||||
head = new Entry<T>(element);
|
|
||||||
} else {
|
|
||||||
head = new Entry<T>(element, head);
|
|
||||||
}
|
|
||||||
entries.put(element, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size() {
|
|
||||||
return entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConcurrentSet<T> addAll(Iterable<T> elements) {
|
|
||||||
synchronized (lock) {
|
|
||||||
for (T element : elements) {
|
|
||||||
if (element == null || entries.containsKey(element)) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
insert(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(T element) {
|
|
||||||
if (!entries.containsKey(element)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
synchronized (lock) {
|
|
||||||
Entry<T> listelement = entries.get(element);
|
|
||||||
if (listelement == null) {
|
|
||||||
return false; //removed by other thread
|
|
||||||
}
|
|
||||||
if (listelement != head) {
|
|
||||||
listelement.remove();
|
|
||||||
} else {
|
|
||||||
Entry<T> oldHead = head;
|
|
||||||
head = head.next();
|
|
||||||
oldHead.next = null; // optimize for GC
|
|
||||||
}
|
|
||||||
entries.remove(element);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterator<T> iterator() {
|
|
||||||
return new Iterator<T>() {
|
|
||||||
|
|
||||||
private Entry<T> current = head;
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
if (current == null) return false;
|
|
||||||
if (current.getValue() == null) { // auto-removal of orphan references
|
|
||||||
do {
|
|
||||||
remove();
|
|
||||||
} while(current != null && current.getValue() == null);
|
|
||||||
return hasNext();
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T next() {
|
|
||||||
if (current == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
T value = current.getValue();
|
|
||||||
if (value == null) { // auto-removal of orphan references
|
|
||||||
do {
|
|
||||||
remove();
|
|
||||||
} while(current != null && current.getValue() == null);
|
|
||||||
return next();
|
|
||||||
} else {
|
|
||||||
current = current.next();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
if (current == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Entry<T> newCurrent = current.next();
|
|
||||||
ConcurrentSet.this.remove(current.getValue());
|
|
||||||
current = newCurrent;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class Entry<T> {
|
|
||||||
|
|
||||||
private WeakReference<T> value;
|
|
||||||
|
|
||||||
private Entry<T> next;
|
|
||||||
|
|
||||||
private Entry<T> predecessor;
|
|
||||||
|
|
||||||
|
|
||||||
private Entry(T value) {
|
|
||||||
this.value = new WeakReference<T>(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Entry(T value, Entry<T> next) {
|
|
||||||
this(value);
|
|
||||||
this.next = next;
|
|
||||||
next.predecessor = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getValue() {
|
|
||||||
return value.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// not thread-safe! must be synchronized in enclosing context
|
|
||||||
public void remove() {
|
|
||||||
if (predecessor != null) {
|
|
||||||
predecessor.next = next;
|
|
||||||
if (next != null) {
|
|
||||||
next.predecessor = predecessor;
|
|
||||||
}
|
|
||||||
} else if (next != null) {
|
|
||||||
next.predecessor = null;
|
|
||||||
}
|
|
||||||
next = null;
|
|
||||||
predecessor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Entry<T> next() {
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
20
src/main/java/net/engio/mbassy/common/IConcurrentSet.java
Normal file
20
src/main/java/net/engio/mbassy/common/IConcurrentSet.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package net.engio.mbassy.common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Todo: Add javadoc
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/29/13
|
||||||
|
*/
|
||||||
|
public interface IConcurrentSet<T> extends Iterable<T> {
|
||||||
|
|
||||||
|
IConcurrentSet<T> add(T element);
|
||||||
|
|
||||||
|
boolean contains(T element);
|
||||||
|
|
||||||
|
int size();
|
||||||
|
|
||||||
|
IConcurrentSet<T> addAll(Iterable<T> elements);
|
||||||
|
|
||||||
|
boolean remove(T element);
|
||||||
|
}
|
19
src/main/java/net/engio/mbassy/common/ISetEntry.java
Normal file
19
src/main/java/net/engio/mbassy/common/ISetEntry.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package net.engio.mbassy.common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Todo: Add javadoc
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/29/13
|
||||||
|
*/
|
||||||
|
public interface ISetEntry<T> {
|
||||||
|
|
||||||
|
T getValue();
|
||||||
|
|
||||||
|
// not thread-safe! must be synchronized in enclosing context
|
||||||
|
void remove();
|
||||||
|
|
||||||
|
ISetEntry<T> next();
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package net.engio.mbassy.common;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation uses weak references to the elements. Iterators automatically perform cleanups of
|
||||||
|
* garbage collected objects during iteration -> no dedicated maintenance operations need to be called or run in background.
|
||||||
|
* <p/>
|
||||||
|
* <p/>
|
||||||
|
* <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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
98
src/main/java/net/engio/mbassy/common/WeakConcurrentSet.java
Normal file
98
src/main/java/net/engio/mbassy/common/WeakConcurrentSet.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package net.engio.mbassy.common;
|
||||||
|
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation uses weak references to the elements. Iterators automatically perform cleanups of
|
||||||
|
* garbage collected objects during iteration -> no dedicated maintenance operations need to be called or run in background.
|
||||||
|
* <p/>
|
||||||
|
* <p/>
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 2/12/12
|
||||||
|
*/
|
||||||
|
public class WeakConcurrentSet<T> extends AbstractConcurrentSet<T>{
|
||||||
|
|
||||||
|
|
||||||
|
public WeakConcurrentSet() {
|
||||||
|
super(new WeakHashMap<T, ISetEntry<T>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<T> iterator() {
|
||||||
|
return new Iterator<T>() {
|
||||||
|
|
||||||
|
private ISetEntry<T> current = head;
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
if (current == null) return false;
|
||||||
|
if (current.getValue() == null) { // auto-removal of orphan references
|
||||||
|
do {
|
||||||
|
remove();
|
||||||
|
} while(current != null && current.getValue() == null);
|
||||||
|
return hasNext();
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T next() {
|
||||||
|
if (current == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
T value = current.getValue();
|
||||||
|
if (value == null) { // auto-removal of orphan references
|
||||||
|
do {
|
||||||
|
remove();
|
||||||
|
} while(current != null && current.getValue() == null);
|
||||||
|
return next();
|
||||||
|
} else {
|
||||||
|
current = current.next();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
if (current == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ISetEntry<T> newCurrent = current.next();
|
||||||
|
WeakConcurrentSet.this.remove(current.getValue());
|
||||||
|
current = newCurrent;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Entry<T> createEntry(T value, Entry<T> next) {
|
||||||
|
return next != null ? new WeakEntry<T>(value, next) : new WeakEntry<T>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class WeakEntry<T> extends Entry<T> {
|
||||||
|
|
||||||
|
private WeakReference<T> value;
|
||||||
|
|
||||||
|
private WeakEntry(T value, Entry<T> next) {
|
||||||
|
super(next);
|
||||||
|
this.value = new WeakReference<T>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private WeakEntry(T value) {
|
||||||
|
super();
|
||||||
|
this.value = new WeakReference<T>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getValue() {
|
||||||
|
return value.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
package net.engio.mbassy.dispatch;
|
||||||
|
|
||||||
|
import net.engio.mbassy.bus.IMessageBus;
|
||||||
import net.engio.mbassy.subscription.AbstractSubscriptionContextAware;
|
import net.engio.mbassy.subscription.AbstractSubscriptionContextAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8,7 +9,7 @@ import net.engio.mbassy.subscription.AbstractSubscriptionContextAware;
|
|||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 11/23/12
|
* Date: 11/23/12
|
||||||
*/
|
*/
|
||||||
public class AsynchronousHandlerInvocation extends AbstractSubscriptionContextAware implements IHandlerInvocation {
|
public class AsynchronousHandlerInvocation extends AbstractSubscriptionContextAware<IMessageBus> implements IHandlerInvocation<Object,Object,IMessageBus> {
|
||||||
|
|
||||||
private IHandlerInvocation delegate;
|
private IHandlerInvocation delegate;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import net.engio.mbassy.subscription.AbstractSubscriptionContextAware;
|
|||||||
*/
|
*/
|
||||||
public abstract class DelegatingMessageDispatcher extends AbstractSubscriptionContextAware implements IMessageDispatcher {
|
public abstract class DelegatingMessageDispatcher extends AbstractSubscriptionContextAware implements IMessageDispatcher {
|
||||||
|
|
||||||
private IMessageDispatcher delegate;
|
private final IMessageDispatcher delegate;
|
||||||
|
|
||||||
|
|
||||||
public DelegatingMessageDispatcher(IMessageDispatcher delegate) {
|
public DelegatingMessageDispatcher(IMessageDispatcher delegate) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
package net.engio.mbassy.dispatch;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.MessagePublication;
|
import net.engio.mbassy.bus.MessagePublication;
|
||||||
import net.engio.mbassy.common.ConcurrentSet;
|
import net.engio.mbassy.common.IConcurrentSet;
|
||||||
import net.engio.mbassy.subscription.MessageEnvelope;
|
import net.engio.mbassy.subscription.MessageEnvelope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,7 +21,7 @@ public class EnvelopedMessageDispatcher extends DelegatingMessageDispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispatch(MessagePublication publication, Object message, ConcurrentSet listeners) {
|
public void dispatch(MessagePublication publication, Object message, IConcurrentSet listeners) {
|
||||||
getDelegate().dispatch(publication, new MessageEnvelope(message), listeners);
|
getDelegate().dispatch(publication, new MessageEnvelope(message), listeners);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
package net.engio.mbassy.dispatch;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.MessagePublication;
|
import net.engio.mbassy.bus.MessagePublication;
|
||||||
import net.engio.mbassy.common.ConcurrentSet;
|
import net.engio.mbassy.common.IConcurrentSet;
|
||||||
import net.engio.mbassy.listener.IMessageFilter;
|
import net.engio.mbassy.listener.IMessageFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,7 +37,7 @@ public class FilteredMessageDispatcher extends DelegatingMessageDispatcher {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispatch(MessagePublication publication, Object message, ConcurrentSet listeners) {
|
public void dispatch(MessagePublication publication, Object message, IConcurrentSet listeners) {
|
||||||
if (passesFilter(message)) {
|
if (passesFilter(message)) {
|
||||||
getDelegate().dispatch(publication, message, listeners);
|
getDelegate().dispatch(publication, message, listeners);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package net.engio.mbassy.dispatch;
|
||||||
|
|
||||||
|
import net.engio.mbassy.bus.ISyncMessageBus;
|
||||||
|
import net.engio.mbassy.subscription.AbstractSubscriptionContextAware;
|
||||||
|
import net.engio.mbassy.subscription.SubscriptionContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Todo: Add javadoc
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/29/13
|
||||||
|
*/
|
||||||
|
public abstract class HandlerInvocation<Listener, Message> extends AbstractSubscriptionContextAware<ISyncMessageBus> implements IHandlerInvocation<Listener, Message,ISyncMessageBus>{
|
||||||
|
|
||||||
|
|
||||||
|
public HandlerInvocation(SubscriptionContext context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
package net.engio.mbassy.dispatch;
|
||||||
|
|
||||||
|
import net.engio.mbassy.bus.ISyncMessageBus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A handler invocation encapsulates the logic that is used to invoke a single
|
* A handler invocation encapsulates the logic that is used to invoke a single
|
||||||
* message handler to process a given message.
|
* message handler to process a given message.
|
||||||
@ -9,7 +11,7 @@ package net.engio.mbassy.dispatch;
|
|||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 11/23/12
|
* Date: 11/23/12
|
||||||
*/
|
*/
|
||||||
public interface IHandlerInvocation extends ISubscriptionContextAware {
|
public interface IHandlerInvocation<Listener, Message, Bus extends ISyncMessageBus> extends ISubscriptionContextAware<Bus> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke the message delivery logic of this handler
|
* Invoke the message delivery logic of this handler
|
||||||
@ -17,5 +19,5 @@ public interface IHandlerInvocation extends ISubscriptionContextAware {
|
|||||||
* @param listener The listener that will receive the message
|
* @param listener The listener that will receive the message
|
||||||
* @param message The message to be delivered to the listener
|
* @param message The message to be delivered to the listener
|
||||||
*/
|
*/
|
||||||
void invoke(Object listener, Object message);
|
void invoke(Listener listener, Message message);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
package net.engio.mbassy.dispatch;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.IMessageBus;
|
import net.engio.mbassy.bus.ISyncMessageBus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface marks components that have access to the message bus that they belong to.
|
* This interface marks components that have access to the message bus that they belong to.
|
||||||
@ -8,7 +8,7 @@ import net.engio.mbassy.bus.IMessageBus;
|
|||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 3/1/13
|
* Date: 3/1/13
|
||||||
*/
|
*/
|
||||||
public interface IMessageBusAware {
|
public interface IMessageBusAware<Bus extends ISyncMessageBus> {
|
||||||
|
|
||||||
IMessageBus getBus();
|
Bus getBus();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
package net.engio.mbassy.dispatch;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.MessagePublication;
|
import net.engio.mbassy.bus.MessagePublication;
|
||||||
import net.engio.mbassy.common.ConcurrentSet;
|
import net.engio.mbassy.common.IConcurrentSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message dispatcher provides the functionality to deliver a single message
|
* A message dispatcher provides the functionality to deliver a single message
|
||||||
@ -29,7 +29,7 @@ public interface IMessageDispatcher extends ISubscriptionContextAware {
|
|||||||
* @param message The message that should be delivered to the listeners
|
* @param message The message that should be delivered to the listeners
|
||||||
* @param listeners The listeners that should receive the message
|
* @param listeners The listeners that should receive the message
|
||||||
*/
|
*/
|
||||||
void dispatch(MessagePublication publication, Object message, ConcurrentSet listeners);
|
void dispatch(MessagePublication publication, Object message, IConcurrentSet listeners);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the handler invocation that will be used to deliver the
|
* Get the handler invocation that will be used to deliver the
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
package net.engio.mbassy.dispatch;
|
||||||
|
|
||||||
|
import net.engio.mbassy.bus.ISyncMessageBus;
|
||||||
import net.engio.mbassy.subscription.SubscriptionContext;
|
import net.engio.mbassy.subscription.SubscriptionContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8,7 +9,7 @@ import net.engio.mbassy.subscription.SubscriptionContext;
|
|||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 3/1/13
|
* Date: 3/1/13
|
||||||
*/
|
*/
|
||||||
public interface ISubscriptionContextAware extends IMessageBusAware {
|
public interface ISubscriptionContextAware<Bus extends ISyncMessageBus> extends IMessageBusAware<Bus> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the subscription context associated with this object
|
* Get the subscription context associated with this object
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.engio.mbassy.dispatch;
|
package net.engio.mbassy.dispatch;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.MessagePublication;
|
import net.engio.mbassy.bus.MessagePublication;
|
||||||
import net.engio.mbassy.common.ConcurrentSet;
|
import net.engio.mbassy.common.IConcurrentSet;
|
||||||
import net.engio.mbassy.subscription.AbstractSubscriptionContextAware;
|
import net.engio.mbassy.subscription.AbstractSubscriptionContextAware;
|
||||||
import net.engio.mbassy.subscription.SubscriptionContext;
|
import net.engio.mbassy.subscription.SubscriptionContext;
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ import net.engio.mbassy.subscription.SubscriptionContext;
|
|||||||
*/
|
*/
|
||||||
public class MessageDispatcher extends AbstractSubscriptionContextAware implements IMessageDispatcher {
|
public class MessageDispatcher extends AbstractSubscriptionContextAware implements IMessageDispatcher {
|
||||||
|
|
||||||
private IHandlerInvocation invocation;
|
private final IHandlerInvocation invocation;
|
||||||
|
|
||||||
public MessageDispatcher(SubscriptionContext context, IHandlerInvocation invocation) {
|
public MessageDispatcher(SubscriptionContext context, IHandlerInvocation invocation) {
|
||||||
super(context);
|
super(context);
|
||||||
@ -25,7 +25,7 @@ public class MessageDispatcher extends AbstractSubscriptionContextAware implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispatch(MessagePublication publication, Object message, ConcurrentSet listeners) {
|
public void dispatch(final MessagePublication publication, final Object message, final IConcurrentSet listeners) {
|
||||||
publication.markDelivered();
|
publication.markDelivered();
|
||||||
for (Object listener : listeners) {
|
for (Object listener : listeners) {
|
||||||
getInvocation().invoke(listener, message);
|
getInvocation().invoke(listener, message);
|
||||||
|
@ -2,7 +2,6 @@ package net.engio.mbassy.dispatch;
|
|||||||
|
|
||||||
import net.engio.mbassy.IPublicationErrorHandler;
|
import net.engio.mbassy.IPublicationErrorHandler;
|
||||||
import net.engio.mbassy.PublicationError;
|
import net.engio.mbassy.PublicationError;
|
||||||
import net.engio.mbassy.subscription.AbstractSubscriptionContextAware;
|
|
||||||
import net.engio.mbassy.subscription.SubscriptionContext;
|
import net.engio.mbassy.subscription.SubscriptionContext;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@ -15,7 +14,7 @@ import java.util.Collection;
|
|||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 11/23/12
|
* Date: 11/23/12
|
||||||
*/
|
*/
|
||||||
public class ReflectiveHandlerInvocation extends AbstractSubscriptionContextAware implements IHandlerInvocation {
|
public class ReflectiveHandlerInvocation extends HandlerInvocation{
|
||||||
|
|
||||||
public ReflectiveHandlerInvocation(SubscriptionContext context) {
|
public ReflectiveHandlerInvocation(SubscriptionContext context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package net.engio.mbassy.dispatch;
|
||||||
|
|
||||||
|
import net.engio.mbassy.bus.IMessageBus;
|
||||||
|
import net.engio.mbassy.subscription.AbstractSubscriptionContextAware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronizes message handler invocations for all handlers that specify @Synchronized
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/31/13
|
||||||
|
*/
|
||||||
|
public class SynchronizedHandlerInvocation extends AbstractSubscriptionContextAware<IMessageBus> implements IHandlerInvocation<Object,Object,IMessageBus> {
|
||||||
|
|
||||||
|
private IHandlerInvocation delegate;
|
||||||
|
|
||||||
|
public SynchronizedHandlerInvocation(IHandlerInvocation delegate) {
|
||||||
|
super(delegate.getContext());
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void invoke(final Object listener, final Object message) {
|
||||||
|
synchronized (listener){
|
||||||
|
delegate.invoke(listener, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,10 +1,9 @@
|
|||||||
package net.engio.mbassy.listener;
|
package net.engio.mbassy.listener;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import net.engio.mbassy.dispatch.HandlerInvocation;
|
||||||
import java.lang.annotation.Inherited;
|
import net.engio.mbassy.dispatch.ReflectiveHandlerInvocation;
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.*;
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark any method of any object(=listener) as a message handler and configure the handler
|
* Mark any method of any object(=listener) as a message handler and configure the handler
|
||||||
@ -28,7 +27,7 @@ public @interface Handler {
|
|||||||
* Define the mode in which a message is delivered to each listener. Listeners can be notified
|
* Define the mode in which a message is delivered to each listener. Listeners can be notified
|
||||||
* sequentially or concurrently.
|
* sequentially or concurrently.
|
||||||
*/
|
*/
|
||||||
Mode delivery() default Mode.Sequential;
|
Invoke delivery() default Invoke.Synchronously;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handlers are ordered by priority and handlers with higher priority are processed before
|
* Handlers are ordered by priority and handlers with higher priority are processed before
|
||||||
@ -51,4 +50,17 @@ public @interface Handler {
|
|||||||
*/
|
*/
|
||||||
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;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
11
src/main/java/net/engio/mbassy/listener/Invoke.java
Normal file
11
src/main/java/net/engio/mbassy/listener/Invoke.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package net.engio.mbassy.listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA.
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 11/16/12
|
||||||
|
*/
|
||||||
|
public enum Invoke {
|
||||||
|
Synchronously, Asynchronously
|
||||||
|
}
|
24
src/main/java/net/engio/mbassy/listener/Listener.java
Normal file
24
src/main/java/net/engio/mbassy/listener/Listener.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/29/13
|
||||||
|
*/
|
||||||
|
@Retention(value = RetentionPolicy.RUNTIME)
|
||||||
|
@Target(value = {ElementType.TYPE})
|
||||||
|
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,7 +1,8 @@
|
|||||||
package net.engio.mbassy.listener;
|
package net.engio.mbassy.listener;
|
||||||
|
|
||||||
|
import net.engio.mbassy.dispatch.HandlerInvocation;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -11,36 +12,54 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class MessageHandlerMetadata {
|
public class MessageHandlerMetadata {
|
||||||
|
|
||||||
private Method handler;
|
private final Method handler;
|
||||||
|
|
||||||
private IMessageFilter[] filter;
|
private final IMessageFilter[] filter;
|
||||||
|
|
||||||
private Handler handlerConfig;
|
private final Handler handlerConfig;
|
||||||
|
|
||||||
private boolean isAsynchronous = false;
|
private final boolean isAsynchronous;
|
||||||
|
|
||||||
private Enveloped envelope = null;
|
private final Enveloped envelope;
|
||||||
|
|
||||||
private List<Class<?>> handledMessages = new LinkedList<Class<?>>();
|
private final List<Class<?>> handledMessages = new LinkedList<Class<?>>();
|
||||||
|
|
||||||
private boolean acceptsSubtypes = true;
|
private final boolean acceptsSubtypes;
|
||||||
|
|
||||||
|
private final Listener listenerConfig;
|
||||||
|
|
||||||
|
private final boolean isSynchronized;
|
||||||
|
|
||||||
|
|
||||||
public MessageHandlerMetadata(Method handler, IMessageFilter[] filter, Handler handlerConfig) {
|
public MessageHandlerMetadata(Method handler, IMessageFilter[] filter, Handler handlerConfig, Listener listenerConfig) {
|
||||||
|
if(handler == null || handlerConfig == null){
|
||||||
|
throw new IllegalArgumentException("The message handler configuration may not be null");
|
||||||
|
}
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.handlerConfig = handlerConfig;
|
this.handlerConfig = handlerConfig;
|
||||||
this.isAsynchronous = handlerConfig.delivery().equals(Mode.Concurrent);
|
this.isAsynchronous = handlerConfig.delivery().equals(Invoke.Asynchronously);
|
||||||
this.envelope = handler.getAnnotation(Enveloped.class);
|
this.envelope = handler.getAnnotation(Enveloped.class);
|
||||||
this.acceptsSubtypes = !handlerConfig.rejectSubtypes();
|
this.acceptsSubtypes = !handlerConfig.rejectSubtypes();
|
||||||
|
this.listenerConfig = listenerConfig;
|
||||||
|
this.isSynchronized = handler.getAnnotation(Synchronized.class) != null;
|
||||||
if (this.envelope != null) {
|
if (this.envelope != null) {
|
||||||
Collections.addAll(handledMessages, envelope.messages());
|
for(Class messageType : envelope.messages()){
|
||||||
|
handledMessages.add(messageType);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
handledMessages.add(handler.getParameterTypes()[0]);
|
handledMessages.add(handler.getParameterTypes()[0]);
|
||||||
}
|
}
|
||||||
this.handler.setAccessible(true);
|
this.handler.setAccessible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSynchronized(){
|
||||||
|
return isSynchronized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean useStrongReferences(){
|
||||||
|
return listenerConfig != null && listenerConfig.references().equals(References.Strong);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAsynchronous() {
|
public boolean isAsynchronous() {
|
||||||
return isAsynchronous;
|
return isAsynchronous;
|
||||||
@ -70,6 +89,10 @@ public class MessageHandlerMetadata {
|
|||||||
return envelope != null;
|
return envelope != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class<? extends HandlerInvocation> getHandlerInvocation(){
|
||||||
|
return handlerConfig.invocation();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean handlesMessage(Class<?> messageType) {
|
public boolean handlesMessage(Class<?> messageType) {
|
||||||
for (Class<?> handledMessage : handledMessages) {
|
for (Class<?> handledMessage : handledMessages) {
|
||||||
if (handledMessage.equals(messageType)) {
|
if (handledMessage.equals(messageType)) {
|
||||||
|
@ -54,14 +54,12 @@ public class MetadataReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public MessageHandlerMetadata getHandlerMetadata(Method messageHandler) {
|
|
||||||
Handler config = messageHandler.getAnnotation(Handler.class);
|
|
||||||
return new MessageHandlerMetadata(messageHandler, getFilter(config), config);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 List<MessageHandlerMetadata> getMessageHandlers(Class<?> target) {
|
public List<MessageHandlerMetadata> getMessageHandlers(Class<?> target) {
|
||||||
|
Listener listenerConfig = target.getAnnotation(Listener.class);
|
||||||
// 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(AllMessageHandlers, 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)
|
||||||
@ -72,19 +70,18 @@ public class MetadataReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<MessageHandlerMetadata> filteredHandlers = new LinkedList<MessageHandlerMetadata>();
|
List<MessageHandlerMetadata> filteredHandlers = new LinkedList<MessageHandlerMetadata>();
|
||||||
// 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) {
|
||||||
Handler handle = handler.getAnnotation(Handler.class);
|
Handler handlerConfig = handler.getAnnotation(Handler.class);
|
||||||
if (!handle.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 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
|
||||||
MessageHandlerMetadata handlerMetadata = new MessageHandlerMetadata(overriddenHandler == null ? handler : overriddenHandler,
|
MessageHandlerMetadata handlerMetadata = new MessageHandlerMetadata(overriddenHandler == null ? handler : overriddenHandler,
|
||||||
getFilter(handle), handle);
|
getFilter(handlerConfig), handlerConfig, listenerConfig);
|
||||||
filteredHandlers.add(handlerMetadata);
|
filteredHandlers.add(handlerMetadata);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package net.engio.mbassy.listener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created with IntelliJ IDEA.
|
|
||||||
*
|
|
||||||
* @author bennidi
|
|
||||||
* Date: 11/16/12
|
|
||||||
* Time: 10:01 AM
|
|
||||||
* To change this template use File | Settings | File Templates.
|
|
||||||
*/
|
|
||||||
public enum Mode {
|
|
||||||
Sequential, Concurrent
|
|
||||||
}
|
|
10
src/main/java/net/engio/mbassy/listener/References.java
Normal file
10
src/main/java/net/engio/mbassy/listener/References.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package net.engio.mbassy.listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/29/13
|
||||||
|
*/
|
||||||
|
public enum References {
|
||||||
|
Strong,Weak
|
||||||
|
}
|
16
src/main/java/net/engio/mbassy/listener/Synchronized.java
Normal file
16
src/main/java/net/engio/mbassy/listener/Synchronized.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package net.engio.mbassy.listener;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handler marked with this annotation is guaranteed to be invoked in a thread-safe manner, that is, no
|
||||||
|
* other running message publication will be able to invoke this handler as long as it has not done its work.
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/31/13
|
||||||
|
*/
|
||||||
|
@Retention(value = RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
@Target(value = {ElementType.METHOD})
|
||||||
|
public @interface Synchronized {
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package net.engio.mbassy.subscription;
|
package net.engio.mbassy.subscription;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.IMessageBus;
|
import net.engio.mbassy.bus.ISyncMessageBus;
|
||||||
import net.engio.mbassy.dispatch.ISubscriptionContextAware;
|
import net.engio.mbassy.dispatch.ISubscriptionContextAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -9,20 +9,20 @@ import net.engio.mbassy.dispatch.ISubscriptionContextAware;
|
|||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 3/1/13
|
* Date: 3/1/13
|
||||||
*/
|
*/
|
||||||
public class AbstractSubscriptionContextAware implements ISubscriptionContextAware {
|
public class AbstractSubscriptionContextAware<Bus extends ISyncMessageBus> implements ISubscriptionContextAware<Bus> {
|
||||||
|
|
||||||
private SubscriptionContext context;
|
private final SubscriptionContext<Bus> context;
|
||||||
|
|
||||||
public AbstractSubscriptionContextAware(SubscriptionContext context) {
|
public AbstractSubscriptionContextAware(SubscriptionContext<Bus> context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubscriptionContext getContext() {
|
public SubscriptionContext<Bus> getContext() {
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IMessageBus getBus() {
|
public Bus getBus() {
|
||||||
return context.getOwningBus();
|
return context.getOwningBus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.engio.mbassy.subscription;
|
package net.engio.mbassy.subscription;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.MessagePublication;
|
import net.engio.mbassy.bus.MessagePublication;
|
||||||
import net.engio.mbassy.common.ConcurrentSet;
|
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.Comparator;
|
||||||
@ -12,17 +12,18 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
public class Subscription {
|
public class Subscription {
|
||||||
|
|
||||||
private UUID id = UUID.randomUUID();
|
private final UUID id = UUID.randomUUID();
|
||||||
|
|
||||||
protected ConcurrentSet<Object> listeners = new ConcurrentSet<Object>();
|
protected final IConcurrentSet<Object> listeners;
|
||||||
|
|
||||||
private IMessageDispatcher dispatcher;
|
private final IMessageDispatcher dispatcher;
|
||||||
|
|
||||||
private SubscriptionContext context;
|
private final SubscriptionContext context;
|
||||||
|
|
||||||
public Subscription(SubscriptionContext context, IMessageDispatcher dispatcher) {
|
Subscription(SubscriptionContext context, IMessageDispatcher dispatcher, IConcurrentSet<Object> listeners) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.dispatcher = dispatcher;
|
this.dispatcher = dispatcher;
|
||||||
|
this.listeners = listeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.engio.mbassy.subscription;
|
package net.engio.mbassy.subscription;
|
||||||
|
|
||||||
import net.engio.mbassy.bus.IMessageBus;
|
import net.engio.mbassy.bus.ISyncMessageBus;
|
||||||
import net.engio.mbassy.listener.MessageHandlerMetadata;
|
import net.engio.mbassy.listener.MessageHandlerMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,13 +12,13 @@ import net.engio.mbassy.listener.MessageHandlerMetadata;
|
|||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 11/23/12
|
* Date: 11/23/12
|
||||||
*/
|
*/
|
||||||
public class SubscriptionContext {
|
public class SubscriptionContext<Bus extends ISyncMessageBus> {
|
||||||
|
|
||||||
private IMessageBus owningBus;
|
private Bus owningBus;
|
||||||
|
|
||||||
private MessageHandlerMetadata handlerMetadata;
|
private MessageHandlerMetadata handlerMetadata;
|
||||||
|
|
||||||
public SubscriptionContext(IMessageBus owningBus, MessageHandlerMetadata handlerMetadata) {
|
public SubscriptionContext(Bus owningBus, MessageHandlerMetadata handlerMetadata) {
|
||||||
this.owningBus = owningBus;
|
this.owningBus = owningBus;
|
||||||
this.handlerMetadata = handlerMetadata;
|
this.handlerMetadata = handlerMetadata;
|
||||||
}
|
}
|
||||||
@ -28,7 +28,7 @@ public class SubscriptionContext {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public IMessageBus getOwningBus() {
|
public Bus getOwningBus() {
|
||||||
return owningBus;
|
return owningBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user