The Bus User's Guide

Chapter 2. The Message Bus

Table of Contents

Using The Message Bus

Using The Message Bus

The purpose of The Message Bus is to allow components to be loosely coupled, by enabling them to send and receive messages (or events) without knowing what components the messages are intended for or who sent them.

Loose coupling can be seen within Swing using the event listener pattern (also known as the Observer/Observable and Publisher/Subscriber patterns). For example, a JTable does not have to know who is listening to its events, only that there exists one or more components that wish to know when an event occurs.

Unfortunately, Swing doesn't allow for a level of loose coupling many prefer. In reality, if a component nested 3 levels deep offers events that it broadcasts, the interested observer must know how to navigate to that component and add itself as a listener. Otherwise, any interested listeners of the component must register at the time of instantiation to ensure that a handle to the component is available.

Example

Consider a Swing panel composed using the following components:

	Panel
	  |
	  |- Tabbed Pane
	         |
	         |- Tab 1 Panel
	                |
	                |- Split Panel
	                     |
	                     |- Left Tree
	                     |- Right Tree
	    
	

Notice the level of depth that is required to navigate to the either of the tree components. If anyone wants to attach as a listener to this tree after its initial construction, it must know how to navigate to the specific tree via the Swing APIs or via an application-specific API. Not as loosely coupled as people tend to think.

The Bus API solves this problem by enabling each tree component to broadcast messages/events on a specific channel with a specific base message class. Any interested component can subscribe to the tree message via The Bus, without knowing where the component lives, or even that it's a tree!

[Consider a better example here, or a few examples to show not only this problem, but the growth of listeners as things get larger]

Getting Started

Note: To view the complete API of the Message Bus, refer to the Javadoc page for the Message Bus

The Message Bus can be considered a routing hub, which accepts incoming messages and routes them to all interested subscribers. To reduce the amount of overall messages and enable an application to partition its messages for greater flexibility, the concept of channels is used. A message may be published to a channel, where all subscribers to that particular message type within that channel will receive a notification of the event. Although most components will communicate over the 'default' channel, other channels may be created using either a configuration file or via a JMX interface (future).

For each channel, a message dispatching strategy may be defined, called a Dispatcher. Currently, 2 dispatchers are provided: SyncDispatcher and AsyncDispatcher. The default dispatcher for a channel is the SyncDispatcher, unless specified in the configuration resource (see below).

The following examples demonstrate the typical usage of the Message Bus:

Example 1: A Basic Pub/Sub

This is a pretty simple example, where we see 2 components - 1 subscriber and 1 publisher - exchange a message.

	

	

Example 2: Using Filters

Custom Channel Configuration

Channels are created implicitly whenever a component subscribes to a channel that doesn't exist. However, the default settings for a channel may not be the settings desired for the channel. The Message Bus looks for a resource in its CLASSPATH named messagebus-config.xml and uses this to preconfigure channels. New channels may still be created implicity, but this allows the message dispatcher to be declared on a channel-by-channel basis.

The following is an example of a custom configuration:

<bus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="bus-config.xsd">
  <channels>
    <channel-config>
       <channel-name>default</channel-name>
       <channel-type>VM</channel-type>
       <dispatcher>net.sf.bus.spi.SyncDispatcher</dispatcher>
    </channel-config>
    <channel-config>
       <channel-name>MyAsyncChannel</channel-name>
       <channel-type>VM</channel-type>
       <dispatcher>net.sf.bus.spi.AsyncDispatcher</dispatcher>
    </channel-config>
 </channels>
</bus>
	    
	

Additional options are available from within the configuration file, including passing parameters to the dispatchers. Refer to the XSD for the configuration file (found in main/src/spi/resources) for the complete schema. Also, refer to each dispatcher's documentation for supported parameters.