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

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 EventBusMatcher 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 <dependencies>
2   ...
3   <dependency>
4     <groupId>org.refcodes</groupId>
5     <artifactId>refcodes-eventbus</artifactId>
6     <version>1.1.7</version>
7   </dependency>
8   ...
9 </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 EventBusObserver theSportsObserver = new EventBusObserver() {
 2   @Override
 3   public void onEvent( MetaDataEvent aEvent ) {
 4     LOGGER.debug( "Got a sports event on channel <" + aEvent.getMetaData().getChannel() + ">" );
 5   }
 6 };
 7 
 8 EventBusObserver thePoliticsObserver = new EventBusObserver() {
 9   @Override
10   public void onEvent( MetaDataEvent aEvent ) {
11     LOGGER.debug( "Got a politics event on channel <" + aEvent.getMetaData().getChannel() + ">" );
12   }
13 };

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 theEventBus.subscribe( theSportsObserver, or( channelEqualWith( "Soccer" ), channelEqualWith( "Football" ) ) );
2 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 EventBusMatcher) 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 theEventBus.publishEvent( new MetaDataEventImpl( "Soccer", this ) );
2 theEventBus.publishEvent( new MetaDataEventImpl( "Education", this ) );
3 theEventBus.publishEvent( new MetaDataEventImpl( "Football", this ) );
4 theEventBus.publishEvent( new MetaDataEventImpl( "War", this ) );
5 theEventBus.publishEvent( new MetaDataEventImpl( "Formular 1", this ) );
6 theEventBus.publishEvent( new MetaDataEventImpl( "Top Secret", this ) );

Below see the output of this example:

1 19:43:25,084 DEBUG [EventBusTest] Got a sports event on channel <Soccer>
2 19:43:25,085 DEBUG [EventBusTest] Got a politics event on channel <Education>
3 19:43:25,085 DEBUG [EventBusTest] Got a sports event on channel <Football>
4 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 assertFalse( theEventBus.isMatching( new MetaDataEventImpl( "Top Secret", this ) ) );
2 assertTrue( theEventBus.isMatching( new MetaDataEventImpl( "Soccer", this ) ) );
3 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.

comments powered by Disqus