Current situation

Currently the broker is configured via a config.xml. This file is read on startup and the system responds by creating objects that form the Broker. The current system has a number of shortcomings:

  • the config.xml is poorly structured and inconsistent
  • the approach taken to producing the objects from the configuration is poorly structure. This makes the Broker difficult to change and test.
  • the config system is such that there is no ability to change the configuration at runtime (from the management layer). For instance it is currently very hard to support the dynamic addition and removal of virtualhosts at runtime. This means the user currently has to hand-edit a complex xml document and restart the Broker.

Brief Overview of Broker Architecture

The Broker currently consists of a tree of ConfiguredObjects, each representing a functional-area of the Broker that the user may wish to manage. The Broker is the top of the tree and has children such as Ports, AuthenticationManagers etc. In addition to children, configured objects also have a series of attributes. For instance, a Port has a portNumber attribute.

This tree is created on Broker start-up from Broker configuration.

Design Proposal

The main features of the design are as follows:

  • Introduce a ConfigurationEntry class and ConfigurationEntryStore interface to abstract the Broker from the details of how the configuration is stored. This will allow the configuration to be stored in different stores (flat-file, Derby, Oracle-BDB, SQL, etc) and remove the hard dependencies on Commons Config.
  • Allow for changes to be made dynamically (through management interfaces) to be reflected immediately in the stored configuration. This will do away with the need for the user to hand-edit configuration files.
  • Improve the mechanism used to construct the Broker from its configuration.

Key Interfaces

ConfigurationEntry

POJO holding the configuration for the ConfiguredObject. It also has a reference to the ConfigurationEntryStore in order to be able to load its children configuration entries.

ConfigurationEntryStore

The ConfigurationEntryStore is responsible for reading and saving of ConfigurationEntries.
Command line arguments and default settings should be also represented as ConfigurationEntryStores. The CompositeConfigurationEntryStore will be responsible for the loading and merging of the configuration from underlyaing stores (command line arguments store, persistent configuration store and default settings)

BrokerCreator and ConfiguredObjectCreators

The BrokerCreator constructs the tree of the ConfiguredObjects representing the Broker from the ConfigurationEntry. It will delegate the creation of broker children (VirtualHosts, AuthenticationProviders, Ports etc) to their own Creators. Also BrokerCreator is responsible for setting of "parent-child" relationships between Broker and its children configured object.

ConfigurationChangeMonitor

Has three responsibilities:

  • given a ConfiguredObject, it registers itself as a ConfigurationChangeListener with the ConfiguredObject and its supported children (and descendents).
  • as more supported children are added to the tree, if must register itself with the new child so that any future updates to the child are heard.
  • cause changes to be reflected in the store by using the ConfigurationEntryStore

The ConfigurationChangeMonitor will avoid listening for events of children of VirtualHosts, nor will it register itself with children beneath the virtualhosts within the tree.

UML

The following UML diagrams document the design.

Class Diagram

Sequence Diagram - Broker Startup

Sequence diagram depicting Broker start-up, loading of configuration, the forming of the ConfiguredObject tree
and the registering of listeners to hear changes/updates.

Sequence Diagram - Adding a new child from the management interface

Sequence diagram depicting the adding of the new child from the management interface. This shows how the new child is persisted into the store, and how the ConfigurationChangeMonitor registers itself with the new child.

Sequence Diagram - Changing of attributes from management interfaces

Json configuration store and Json configuration format.

On first stages (until ConfiguredObject relationships are introduced) the ConfiguredObject will be stored in the stores using ConfigurationEntry representation. Thus all attributes including references to the other ConfiguredObjects (which are not children) will be stored in the attributes and children will stored as hierarchy.

For example, the Port will be stored in JSON format as follows

{
  id: "c7038ed9-9ba9-4db1-bc56-ab6c3ab27273",
  type: "Port",
  attributes: {
    port: 5671,
    transport: "SSL",
    bindingAddress: "0.0.0.0",
    protocols: [ "AMQP1-0", ... ],
    socketReceiveBuffer: 262144,  // optional
    socketSendBuffer: 262144,     // optional
    defaultSupportedProtocolReply:  "AMQP0-9"  // optional,
    tcpNoDelay: true,             // optional
    frameSize: 65536,             // optional
    trustStore: "c7038ed9-9ba9-4db1-bc56-ab6c3ab27279",
    keyStore: "c7038ed9-9ba9-4db1-bc56-ab6c3ab27278",
    clientCertificateAuthType:  "NEED" //NEED|WANT|NONE,
  }
}

In the snippet above, the port is declared with 12 attributes. The attributes "trustStore" and "keyStore" are actually point to the configured objects having IDs "c7038ed9-9ba9-4db1-bc56-ab6c3ab27279" and "c7038ed9-9ba9-4db1-bc56-ab6c3ab27278" accordingly. The "type" field carries the string identifier of the model interface. It will be used by the ConfiguredObjectFactory to find the interface class in order to invoke createChild method on a Broker object.

The full example of broker JSON configuration is provided here.

  • No labels