refcodes-eventbus: Observer + Publish–subscribe = Message broker

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?

… simply speaking, the equation Observer pattern + Publish–subscribe pattern = Message broker solves to refcodes-eventbus” [Publish … subscribe … observe … event-bus?, 01/05/2015]

The refcodes-eventbus 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.

In your application, you subscribe an EventBusObserver (Observer) to an EventBus (EventBusImpl). You assign an BusMatcher 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 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>2.0.3</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.

How do I get started?

First of all you create your EventBus (EventBusImpl) instance:

EventBusImpl theEventBus = new EventBusImpl();

Then you create your event-listener instances being 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
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() + ">" );
	}
};

I created two event-listener instances; one is to be registered for sports related channels and one is to be registered for the politics related channels. So I subscribe them event-listener instances as follows:

1
2
theEventBus.subscribe( theSportsObserver, or( channelEqualWith( "Soccer" ), channelEqualWith( "Football" ) ) );
theEventBus.subscribe( thePoliticsObserver, or( channelEqualWith( "War" ), channelEqualWith( "Education" ) ) );

On purpose, the event-listener code and the the event-matcher doing the filtering (as of the BusMatcher) 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.

Now 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
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 the event-listeners, so you can separate the event-listeners’ business logic from the routing logic practicing the Separation of concerns idea.

You can determine beforehand whether there is an event-listener registered for some given event:

1
2
3
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.

See the EventBusTest unit test for the source code of this example.

Contribution guidelines

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.