JBStrap message bus

In reactive systems, several techniques are used to decouple parts of the program from each other. In a program developed using traditional concepts, a component triggers a change in another component, provided that the target component is available and not overloaded by other requests. Message-driven systems transmit a message while only addressing its recipient and ignoring its availability. Event-driven systems take it to the next level: they only have fixed senders, data is sent "to whom it may concern." Message-driven and event-driven systems are often contrasted. However, the event-driven paradigm is really just an organizing principle, while message-driven systems can be considered an implementation technique.

What does the JBStrap MessageBus do?

In JBStrap, message buses are used to implement the message-driven programming paradigm. The MessageBus layer is responsible for creating a multi-tier hierarchy that consists of different channels. A global channel is available for every component in the application, whereas a client-level channel transmits only within a single client. Component-level channels work only in the scope of one single component. These channels, also called message buses, receive messages. Every subscribed and available component -- and only these components -- can receive these messages.

We distinguish between global channels that are available throughout the application and span across clients, client-level channels that are accessible only within a single client and span across pages, and component-level channels. The operation of these channels is explained in detail in the following sections.

Regardless of type, each channel must be opened before you can use it. You can send messages to an open channel after opening it. A message reaches only those endpoints that subscribed to the given channel when the message was sent. A source code part can subscribe to more than one channel at a time, as well as being able to unsubscribe from a channel. Once a program section unsubscribes from a channel, it won't receive more messages from that the channel after unsubscribing. Each channel is automatically closed and subscribers are automatically unsubscribed when channel owners (objects in which the channel was created) unsubscribe. Thus, global channels will be automatically closed when the application is shut down, client-level channels are closed when the client disconnects, component-level channels are closed when the component no longer exists, i.e. when the page is closed, and all program sections monitored for that channel will be disconnected from the channel.

Global message bus

A top-level MessageBus is called a global bus. A global bus can be "seen" from any part of the application, so you only need to open it once and keep it open until you stop the application. Messages sent via such a bus can be received at any point in the application, and each message spans across clients. Buses of this kind can be used, for example, to implement a chat interface, since every client listening to the channel receives a message sent from each client.

Global message buses are created in the JBStrap framework, so they will only be automatically terminated when the application stops. In case the program logic wants to terminate a global channel, then it must be done by closing the channel.

Global buses are identified by name, which name must be entered when opening the bus. The bus name must be unique throughout the entire application, thus we cannot create two global buses with the same name. Doing so will result in an error.

Creating a global message bus:
Terminating a global message bus:
Checking whether a message bus is open:

Client-level message bus

The next level of MessageBus is the client-level message bus. This channel must be created on a specific client and will be owned by the client. Only components and pages that are displayed on that client can subscribe to a client-level channel. Pages or components displayed on another client cannot see the channel and thus the messages on that channel, so they will not receive messages from that channel.

Because you create a client-level bus in a specific client, the bus will be automatically terminated when the client itself disconnects from the server. If you destroy the channel, all listener components will also be unsubscribed.

Client-level channels are also identified by name, which must be entered when opening the channel. Accordingly, the channel name must be unique within the client, so it is not possible to open two channels with the same name within a client. However, the name of a client-level may be the same as the name of the global channel. This is called channel hierarchy. For an explanation of channel hierarchy and a detailed description of how it works is provided in the section Message bus hierarchy .

Creating a client-level message bus:
Terminating a client-level message bus:
Checking whether a message bus is open:

Component-level message bus

The lowest level of the MessageBus is the component-level message bus. This channel must be created on a component, including pages and UIs, and the component on which it was created. Only the component and can subscribe to a component-level channel. Components that are child components of another component will not see the channel and will not receive messages sent by the channel.

Because component-level buses are owned by a specific component, they are automatically terminated when the specific component and all listeners subscribed to that particular bus are automatically unsubscribed.

If a child component of a component subscribes to a channel and then the child component is removed from the parent component, it will automatically result in the channel being unsubscribed. If the child component is created again, it will automatically re-subscribe to that channel. If the removed child component is placed on another parent component and the channel with the same name is open in the other parent component, the child component will be automatically subscribed to the parent's channel.

Component-level channels are also identified by a name, which must be specified when the channel, and must be unique within the component. Thus, two components with the same name cannot be opened on one component. A component with the same name as a global or client-level channel can be opened in the component, thus creating a hierarchy between the channels. An explanation of channel hierarchy and a detailed description of how it works is provided in the Message bus hierarchy section.

Since all JBStrap components are allowed to open a channel, sometimes you may open a channel in a child component that already exists in the parent component. In these cases, channel hierarchy decides the specific channel when you subscribe to it.

An example of creating a component-level message bus:
Terminating a component-level message bus:
Checking if a component-level message bus is open:

Message bus hierarchy

Each message bus level has a role in a hierarchy. From top to down, we have global channels, then the client-level, and finally component-level buses. When a component attempts to subscribe to a channel, it always subscribes to the open channel closest to the component. So, with the name you provide when you subscribe, the component is the first to search for the channel by itself. If it does find a channel, it will subscribe to it. If it cannot find a channel, it looks for the channel in its parent component. This process is repeated up to the top level. That is to say, when there are no more parent components, the page, then the UI, the client and finally, the global channels follow. If you find an open channel with the specific name at any level, then it will be subscribed to. If not, the component will not receive the messages. The component looks for the nearest channel on the hierarchy levels above itself.

If you remove a component from the parent component, the component will unsubscribe from all channels, as the hierarchy that defines channel visibility is broken. If the component is placed on the parent again, all the channels it listens to will be re-subscribed. This new subscription is done based on the component's position in the hierarchy. So, if you place a component on a parent component other than its original parent, the channel will listen to other channels.

If you do not want to subscribe to a component on MessageBus , you cannot make use of channel hierarchy, so only global message buses can be used. Channels at other levels can only be used by components or their children. If you make your own component, it will be able to use all channels at all levels because the service is supported by the framework using the parent classes.