README
The
REFCODES.ORG
codes represent a group of artifacts consolidating parts of my work in the past years. Several topics are covered which I consider useful for you, programmers, developers and software engineers.
What is this repository for?
This artifacts implements a lightweight infrastructure for event based decoupled communication. This is achieved by implementing the Observer pattern combined with the Publish–subscribe pattern, ending up being a Message broker for events.
Quick start archetype
For a jump start into developing Java driven command line tools, I created some fully pre-configured Maven Archetypes available on Maven Central. Those Maven Archetypes already provide means to directly create native executables, bundles as well as launchers and support out of the box command line argument parsing as well as out of the box property file handling.
Use the refcodes-archetype-alt-eventbus
archetype to create a bare metal event driven
driven Java service:
Please adjust
my.corp
with your actualGroup-ID
andmyapp
with your actualArtifact-ID
:
mvn archetype:generate \
-DarchetypeGroupId=org.refcodes \
-DarchetypeArtifactId=refcodes-archetype-alt-eventbus \
-DarchetypeVersion=3.3.9 \
-DgroupId=my.corp \
-DartifactId=myapp \
-Dversion=0.0.1
Using the defaults, this will generate an event driven
application harnessing the refcodes-eventbus
toolkit whilst providing a command line interface by harnessing the refcodes-cli
toolkit.
How do I get set up?
To get up and running, include the following dependency (without the three dots “…”) in your pom.xml
:
1
2
3
4
5
6
7
8
9
<dependencies>
...
<dependency>
<groupId>org.refcodes</groupId>
<artifactId>refcodes-eventbus</artifactId>
<version>3.3.9</version>
</dependency>
...
</dependencies>
The artifact is hosted directly at Maven Central. Jump straight to the source codes at Bitbucket. Read the artifact’s javadoc at javadoc.io.
Introduction
“… simply speaking, the equation
Observer pattern
+Publish/Subscribe pattern
=Message broker
solves torefcodes-eventbus
…” (see Publish … subscribe … observe … event-bus?)
In your application, you subscribe an EventBusObserver
(Observer
) to an EventBus
(EventBusImpl
). You assign an EventBusEventMatcher
for a Channel
, a Group
and some other attributes to your EventBusObserver
. In case a MetaDataEvent
is published with a matching attribute (such as Channel
or Group
), then your EventBusObserver
is signaled (is passed the MetaDataEvent
) … voilà, the publisher is fully decoupled from the subscriber.
How do I get started?
First of all you create your EventBus
(EventBusImpl
) instance:
...
EventBus theEventBus = new EventBusImpl();
...
Now you have everything you need to subscribe your listeners and publish your events (as seen below).
Snippets of interest
Below find some code snippets which demonstrate the various aspects of using the refcodes-eventbus
artifact (and , if applicable, its offsprings). See also the example source codes of this artifact for further information on the usage of this artifact.
Syntactic sugar
The below snippets make use of the EventBusSugar
class which’s methods are imported statically:
1
2
3
...
import static org.refcodes.eventbus.EventBusSugar.*;
...
Defining subscribers
To add subscribers, we create event-listener
instances of type EventBusObserver
:
For the sake of simplicity: I declared the
event-listener
types “on the fly” as inner classes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
EventBusObserver theSportsObserver = new EventBusObserver() {
@Override
public void onEvent( MetaDataEvent aEvent ) {
LOGGER.debug( "Got a sports event on channel <" + aEvent.getMetaData().getChannel() + ">" );
}
};
EventBusObserver thePoliticsObserver = new EventBusObserver() {
@Override
public void onEvent( MetaDataEvent aEvent ) {
LOGGER.debug( "Got a politics event on channel <" + aEvent.getMetaData().getChannel() + ">" );
}
};
...
Subscribing for events
The two event-listener
instances created above are to be registered for the sports related channels
and for the politics related channels
. The sports channels cover Soccer
and Football
, the politics channels cover War
and Education
. So I subscribe them event-listener
instances as follows:
1
2
3
4
...
theEventBus.subscribe( or( channelEqualWith( "Soccer" ), channelEqualWith( "Football" ) ), theSportsObserver );
theEventBus.subscribe( or( channelEqualWith( "War" ), channelEqualWith( "Education" ) ), thePoliticsObserver );
...
On purpose, the event-listener
code and the the event-matcher
doing the filtering (as of the EventBusEventMatcher
) of the events
is separated: It is not up to the event-listener
to decide which events
it finds interesting because there could be top-secret events
to which it must not have access. Also before processing an event
, the event-bus
can determine whether there actually are any matchers
letting that event
pass to an event-listener
.
Publishing events
As of the setup above, let’s see how to publish a plain event
(you can and actually should create your own event
sub-classes):
1
2
3
4
5
6
7
8
...
theEventBus.publishEvent( new MetaDataEventImpl( "Soccer", this ) );
theEventBus.publishEvent( new MetaDataEventImpl( "Education", this ) );
theEventBus.publishEvent( new MetaDataEventImpl( "Football", this ) );
theEventBus.publishEvent( new MetaDataEventImpl( "War", this ) );
theEventBus.publishEvent( new MetaDataEventImpl( "Formular 1", this ) );
theEventBus.publishEvent( new MetaDataEventImpl( "Top Secret", this ) );
...
Below see the output of this example:
1
2
3
4
19:43:25,084 DEBUG [EventBusTest] Got a sports event on channel <Soccer>
19:43:25,085 DEBUG [EventBusTest] Got a politics event on channel <Education>
19:43:25,085 DEBUG [EventBusTest] Got a sports event on channel <Football>
19:43:25,086 DEBUG [EventBusTest] Got a politics event on channel <War>
As you can see, the “Top Secret”
event
was not passed to any of theevent-listeners
, so you can separate theevent-listeners
’ business logic from the routing logic practicing theSeparation of concerns
idea.
Probing for listeners
You can determine beforehand whether there is an event-listener
registered for some given event
:
1
2
3
4
5
...
assertFalse( theEventBus.isMatching( new MetaDataEventImpl( "Top Secret", this ) ) );
assertTrue( theEventBus.isMatching( new MetaDataEventImpl( "Soccer", this ) ) );
assertTrue( theEventBus.isMatching( new MetaDataEventImpl( "Education", this ) ) );
...
Here I used the unit-test’s assertion functionality to proof that the matching mechanism works correctly.
Matcher schema
To introspect your event matcher syntax, the EventBusEventMatcher
type
provides means to generate a MatcherSchema
object, recursively including all the tree node’s MatcherSchema
objects. The MatcherSchema
gives insights on the construction and the current state of all the nodes building up your matcher syntax. Creating a MatcherSchema
is a helpful tool to analyze more complex command line syntax constructions:
1
2
3
4
...
EventBusEventMatcher theSportsMatcher = or( channelEqualWith( "Soccer" ), channelEqualWith( "Football" ) );
System.out.println( theSportsMatcher.toSchema() );
...
The above snippet defines a syntax for anything published for channels Soccer
or Football
(line 1) and prints out the according MatcherSchema
(line 2). The result of the printable version of the MatcherSchema
then looks as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
OrMatcher: {
ALIAS: "OR",
DESCRIPTION: "At least one nested matcher must match (OR).",
TYPE: "org.refcodes.matcher.OrMatcher",
ChannelEqualWithEventBusMatcher: {
ALIAS: "CHANNEL_EQUAL_WITH",
DESCRIPTION: "Matches the given channel <Soccer> with the channel stored in an event's meta data (CHANNEL EQUAL WITH).",
TYPE: "org.refcodes.eventbus.EventBusSugar$ChannelEqualWithEventBusMatcher",
VALUE: "Soccer"
},
ChannelEqualWithEventBusMatcher: {
ALIAS: "CHANNEL_EQUAL_WITH",
DESCRIPTION: "Matches the given channel <Football> with the channel stored in an event's meta data (CHANNEL EQUAL WITH).",
TYPE: "org.refcodes.eventbus.EventBusSugar$ChannelEqualWithEventBusMatcher",
VALUE: "Football"
}
}
As you can see, the text output format uses a
JSON
alike notation for easy further processing.
Examples
Please refer to the example source code for more examples on the usage of this artifact.
Contribution guidelines
- Report issues
- Finding bugs
- Helping fixing bugs
- Making code and documentation better
- Enhance the code
Who do I talk to?
- Siegfried Steiner (steiner@refcodes.org)
Terms and conditions
The REFCODES.ORG
group of artifacts is published under some open source licenses; covered by the refcodes-licensing
(org.refcodes
group) artifact - evident in each artifact in question as of the pom.xml
dependency included in such artifact.