messaging_infrastructure.md: Cleanup and updates

This commit is contained in:
Karol Lewandowski 2023-08-10 15:44:22 +02:00
parent 39f9bb2e79
commit c342ec0fb0
3 changed files with 81 additions and 174 deletions

View File

@ -6,14 +6,14 @@ left to right direction
' Define the objects in the diagram
class "com.intellij.util.messages.Topic" as Topic {
+displayName()
+broadcastDirection()
}
+getDisplayName()
+getBroadcastDirection()
}
class ListenerClass {
+method1()
{method} ...
+methodN()
}
}
' Define the class relationships
Topic o--> "1 " ListenerClass

View File

@ -1,85 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="109px" preserveAspectRatio="none" style="width:414px;height:109px;background:#FFFFFF;" version="1.1" viewBox="0 0 414 109" width="414px" zoomAndPan="magnify">
<style>@import url('https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono&amp;display=swap');</style>
<defs><filter height="300%" id="f1n3w915scn4a5" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--MD5=[1d7f89d46fe5890de77e49145f8259d3]
class Topic--><rect codeLine="25" fill="#F8F8F8" filter="url(#f1n3w915scn4a5)" height="71.5999" id="Topic" style="stroke:#383838;stroke-width:1.5;" width="219" x="7" y="15"/><ellipse cx="21" cy="30" fill="#C2C2C2" rx="10" ry="10" style="stroke:#383838;stroke-width:1.0;"/><path d="M21.625,33.0469 Q22.2813,33.0469 22.75,32.8906 Q23.2188,32.7188 23.4063,32.5313 Q23.6094,32.3438 23.8125,32.1875 Q24.0156,32.0313 24.2031,32.0313 Q24.4688,32.0313 24.6719,32.2344 Q24.8906,32.4375 24.8906,32.7188 Q24.8906,33.3281 23.9375,33.8906 Q22.9844,34.4531 21.5781,34.4531 Q19.7969,34.4531 18.625,33.4063 Q17.4688,32.3594 17.4688,30.7656 L17.4688,29.8438 Q17.4688,28.1563 18.5469,27.0313 Q19.6406,25.8906 21.2656,25.8906 Q22.25,25.8906 23.2656,26.375 L23.3906,26.4219 Q23.6406,26.0938 23.9844,26.0938 Q24.3906,26.0938 24.5313,26.3281 Q24.6875,26.5625 24.6875,27.0156 L24.6875,28.1875 Q24.6875,29.1094 23.9844,29.1094 Q23.7344,29.1094 23.5625,28.9688 Q23.4063,28.8281 23.375,28.7188 Q23.3438,28.5938 23.2969,28.375 Q23.2188,27.9531 22.7813,27.7031 Q22.3594,27.4375 22,27.375 Q21.6406,27.2969 21.3281,27.2969 Q20.2656,27.2969 19.5625,28.0156 Q18.8594,28.7344 18.8594,29.8438 L18.8594,30.7344 Q18.8594,31.7813 19.6094,32.4219 Q20.3594,33.0469 21.625,33.0469 Z " fill="#000000"/><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="189" x="34" y="35.6">com.intellij.util.messages.Topic</text><line style="stroke:#383838;stroke-width:1.5;" x1="8" x2="225" y1="45" y2="45"/><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="98" x="13" y="62.9999">+displayName()</text><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="134" x="13" y="79.7999">+broadcastDirection()</text><!--MD5=[8eaccf46e44cd9185ecd868a6bcfa3ae]
class ListenerClass--><rect codeLine="29" fill="#F8F8F8" filter="url(#f1n3w915scn4a5)" height="88.3998" id="ListenerClass" style="stroke:#383838;stroke-width:1.5;" width="114" x="286" y="7"/><ellipse cx="300" cy="22" fill="#C2C2C2" rx="10" ry="10" style="stroke:#383838;stroke-width:1.0;"/><path d="M300.625,25.0469 Q301.2813,25.0469 301.75,24.8906 Q302.2188,24.7188 302.4063,24.5313 Q302.6094,24.3438 302.8125,24.1875 Q303.0156,24.0313 303.2031,24.0313 Q303.4688,24.0313 303.6719,24.2344 Q303.8906,24.4375 303.8906,24.7188 Q303.8906,25.3281 302.9375,25.8906 Q301.9844,26.4531 300.5781,26.4531 Q298.7969,26.4531 297.625,25.4063 Q296.4688,24.3594 296.4688,22.7656 L296.4688,21.8438 Q296.4688,20.1563 297.5469,19.0313 Q298.6406,17.8906 300.2656,17.8906 Q301.25,17.8906 302.2656,18.375 L302.3906,18.4219 Q302.6406,18.0938 302.9844,18.0938 Q303.3906,18.0938 303.5313,18.3281 Q303.6875,18.5625 303.6875,19.0156 L303.6875,20.1875 Q303.6875,21.1094 302.9844,21.1094 Q302.7344,21.1094 302.5625,20.9688 Q302.4063,20.8281 302.375,20.7188 Q302.3438,20.5938 302.2969,20.375 Q302.2188,19.9531 301.7813,19.7031 Q301.3594,19.4375 301,19.375 Q300.6406,19.2969 300.3281,19.2969 Q299.2656,19.2969 298.5625,20.0156 Q297.8594,20.7344 297.8594,21.8438 L297.8594,22.7344 Q297.8594,23.7813 298.6094,24.4219 Q299.3594,25.0469 300.625,25.0469 Z " fill="#000000"/><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="84" x="313" y="27.6">ListenerClass</text><line style="stroke:#383838;stroke-width:1.5;" x1="287" x2="399" y1="37" y2="37"/><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="71" x="292" y="54.9999">+method1()</text><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="12" x="292" y="71.7999">...</text><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="73" x="292" y="88.5998">+methodN()</text><!--MD5=[ac22afb7b8a06c286e18092d44f495e3]
link Topic to ListenerClass--><path codeLine="36" d="M238.13,51 C238.13,51 262.01,51 272.72,51 " fill="none" id="Topic-ListenerClass" style="stroke:#383838;stroke-width:1.0;"/><polygon fill="#383838" points="285.92,51,276.92,47,280.92,51,276.92,55,285.92,51" style="stroke:#383838;stroke-width:1.0;"/><line style="stroke:#383838;stroke-width:1.0;" x1="280.92" x2="272.92" y1="51" y2="51"/><polygon fill="#FFFFFF" points="226.13,51,232.13,55,238.13,51,232.13,47,226.13,51" style="stroke:#383838;stroke-width:1.0;"/><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="8" x="265.8379" y="66.0506">1</text><!--MD5=[c1d22561c4e8be728dfd59033d5e7522]
@startuml
' https://plantuml-documentation.readthedocs.io/en/latest/formatting/all-skin-params.html
skinparam monochrome true
skinparam shadowing true
skinparam DefaultFontName "Roboto,sans-serif"
skinparam DefaultMonospacedFontName "Roboto Mono,monospace"
' https://material.io/design/typography/the-type-system.html
' Body 2
skinparam DefaultFontSize 14
skinparam DefaultTextAlignment center
skinparam NoteTextAlignment left
' default 1.5
skinparam ActivityBorderThickness 1
' default 2
skinparam PartitionBorderThickness 1.5
skinparam classAttributeIconSize 0
hide empty fields
hide empty methods
left to right direction
' Define the objects in the diagram
class "com.intellij.util.messages.Topic" as Topic {
+displayName()
+broadcastDirection()
}
class ListenerClass {
+method1()
{method} ...
+methodN()
}
' Define the class relationships
Topic o- -> "1 " ListenerClass
@enduml
@startuml
skinparam monochrome true
skinparam shadowing true
skinparam DefaultFontName "Roboto,sans-serif"
skinparam DefaultMonospacedFontName "Roboto Mono,monospace"
skinparam DefaultFontSize 14
skinparam DefaultTextAlignment center
skinparam NoteTextAlignment left
skinparam ActivityBorderThickness 1
skinparam PartitionBorderThickness 1.5
skinparam classAttributeIconSize 0
hide empty fields
hide empty methods
left to right direction
class "com.intellij.util.messages.Topic" as Topic {
+displayName()
+broadcastDirection()
}
class ListenerClass {
+method1()
{method} ...
+methodN()
}
Topic o- -> "1 " ListenerClass
@enduml
PlantUML version 1.2021.8(Sat Jun 26 08:20:59 GMT 2021)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: US
--></g></svg>
<?xml version="1.0" encoding="us-ascii" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="106px" preserveAspectRatio="none" style="width:417px;height:106px;background:#FFFFFF;" version="1.1" viewBox="0 0 417 106" width="417px" zoomAndPan="magnify"><defs><filter height="300%" id="fr2jx0uql5s9w" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--class Topic--><g id="elem_Topic"><rect codeLine="7" fill="#F1F1F1" filter="url(#fr2jx0uql5s9w)" height="70.8125" id="Topic" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="224" x="7" y="15"/><ellipse cx="21" cy="30" fill="#C2C2C2" rx="10" ry="10" style="stroke:#181818;stroke-width:1.0;"/><path d="M23.3896,34.7061 Q22.9111,34.9521 22.3848,35.0752 Q21.8584,35.1982 21.2773,35.1982 Q19.2129,35.1982 18.126,33.8379 Q17.0391,32.4775 17.0391,29.9072 Q17.0391,27.3301 18.126,25.9697 Q19.2129,24.6094 21.2773,24.6094 Q21.8584,24.6094 22.3916,24.7324 Q22.9248,24.8555 23.3896,25.1016 L23.3896,27.3438 Q22.8701,26.8652 22.3813,26.6431 Q21.8926,26.4209 21.373,26.4209 Q20.2656,26.4209 19.7017,27.2993 Q19.1377,28.1777 19.1377,29.9072 Q19.1377,31.6299 19.7017,32.5083 Q20.2656,33.3867 21.373,33.3867 Q21.8926,33.3867 22.3813,33.1646 Q22.8701,32.9424 23.3896,32.4639 Z " fill="#000000"/><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="194" x="34" y="34.7852">com.intellij.util.messages.Topic</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="230" y1="45" y2="45"/><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="120" x="13" y="61.9883">+getDisplayName()</text><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="158" x="13" y="78.3945">+getBroadcastDirection()</text></g><!--class ListenerClass--><g id="elem_ListenerClass"><rect codeLine="11" fill="#F1F1F1" filter="url(#fr2jx0uql5s9w)" height="87.2188" id="ListenerClass" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="114" x="291" y="7"/><ellipse cx="305" cy="22" fill="#C2C2C2" rx="10" ry="10" style="stroke:#181818;stroke-width:1.0;"/><path d="M307.3896,26.7061 Q306.9111,26.9521 306.3848,27.0752 Q305.8584,27.1982 305.2773,27.1982 Q303.2129,27.1982 302.126,25.8379 Q301.0391,24.4775 301.0391,21.9072 Q301.0391,19.3301 302.126,17.9697 Q303.2129,16.6094 305.2773,16.6094 Q305.8584,16.6094 306.3916,16.7324 Q306.9248,16.8555 307.3896,17.1016 L307.3896,19.3438 Q306.8701,18.8652 306.3813,18.6431 Q305.8926,18.4209 305.373,18.4209 Q304.2656,18.4209 303.7017,19.2993 Q303.1377,20.1777 303.1377,21.9072 Q303.1377,23.6299 303.7017,24.5083 Q304.2656,25.3867 305.373,25.3867 Q305.8926,25.3867 306.3813,25.1646 Q306.8701,24.9424 307.3896,24.4639 Z " fill="#000000"/><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="84" x="318" y="26.7852">ListenerClass</text><line style="stroke:#181818;stroke-width:0.5;" x1="292" x2="404" y1="37" y2="37"/><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="74" x="297" y="53.9883">+method1()</text><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="12" x="297" y="70.3945">...</text><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="76" x="297" y="86.8008">+methodN()</text></g><!--link Topic to ListenerClass--><g id="link_Topic_ListenerClass"><path codeLine="18" d="M245.21,50.5 C255.9,50.5 266.45,50.5 276.48,50.5 " fill="none" id="Topic-ListenerClass" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="232.69,50.5,238.69,54.5,244.69,50.5,238.69,46.5,232.69,50.5" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="289.23,50.5,280.23,46.5,284.23,50.5,280.23,54.5,289.23,50.5" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="284.23" x2="276.23" y1="50.5" y2="50.5"/><text fill="#000000" font-family="Roboto,sans-serif" font-size="14" lengthAdjust="spacing" textLength="8" x="272.1023" y="64.4747">1</text></g><!--SRC=[LOzDJiD038NtSmgJ3I2K4Rq04j0DKjLDkS1auYGEywUnioXLxyumYGJT-JtBx_Exes3TqYFCNPkS2R9uryg47dKge-8l2ibauy4wm_mgagbR13zi32VwHdXM4vLpz4dEC12wdlyx7cMAnN8u24Y4JECaq5D6AnI3KlUmnu42Ge52xERYCr2eiYSp5hIgQ6Xiz9g2e7CqwqN8QO_CPaJMdp6HRS0mr0ak2k1fHDaJbrRde_7uyBXvRpcQtXeko-sBihfka0EnOC3yNbMDMIliwlrb5LVGMl_jZZNWjieQbz6PNm9Fb5YjlyMsVO5c1yqjx0S0]--></g></svg>

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -4,61 +4,59 @@
<link-summary>Subscribing and publishing messages via message bus.</link-summary>
## Purpose
The purpose of this document is to introduce the messaging infrastructure available in the IntelliJ Platform to developers and plugin writers.
It is intended to answer why, when and how to use it.
## Rationale
So, what is messaging in the IntelliJ Platform and why do we need it? Basically, its implementation of [Publisher Subscriber Pattern](https://w.wiki/5xaV) that provides additional features like _broadcasting on hierarchy_ and special _nested events_ processing (_nested event_ here is a situation when new event is fired (directly or indirectly) from the callback of another event).
IntelliJ Platform's messaging infrastructure is an implementation of [Publisher Subscriber Pattern](https://w.wiki/5xaV) that provides additional features like _broadcasting on hierarchy_ and special _nested events_ processing (a _nested event_ is an event directly or indirectly fired from the callback of another event).
## Design
Here are the main components of the messaging API.
The following sections describe the main components of the messaging API:
- [Topic](#topic)
- [Message Bus](#message-bus)
- [Connection](#connection)
### Topic
This class serves as an endpoint at the messaging infrastructure.
I.e., clients are allowed to subscribe to a specific topic within a bus and send messages to that topic within that particular bus.
The [`Topic`](%gh-ic%/platform/extensions/src/com/intellij/util/messages/Topic.java) class serves as an endpoint at the messaging infrastructure.
Clients are allowed to subscribe to a specific topic within a bus and send messages to that topic within that particular bus.
![Topic](topic.svg)
* *display name* just a human-readable name used for logging/monitoring purposes;
* *broadcast direction* will be explained in details at Broadcasting. Default value is *TO\_CHILDREN*;
* *listener class* that is a business interface for particular topic.
- **Display name** - a human-readable name used for logging/monitoring purposes.
- **Broadcast direction** - see [](#broadcasting) for more details. Default value is `TO_CHILDREN`.
- **Listener class** - a business interface for a particular topic.
Subscribers register an implementation of this interface at the messaging infrastructure.
Publishers later retrieve objects that conform to the interface (IS-A) and call any methods defined on those implementations.
The messaging infrastructure takes care of dispatching the message to all subscribers of the topic by calling the same method with the same arguments on the registered implementation callbacks;
The messaging infrastructure takes care of dispatching the message to all subscribers of the topic by calling the same method with the same arguments on the registered implementation callbacks.
To clarify corresponding message bus, `Topic` field declaration can be annotated with `com.intellij.util.messages.Topic.AppLevel` and `com.intellij.util.messages.Topic.ProjectLevel`, respectively.
To clarify the corresponding message bus, a `Topic` field declaration can be annotated with `com.intellij.util.messages.Topic.AppLevel` or `com.intellij.util.messages.Topic.ProjectLevel`.
> All available listeners/topics are listed on [](extension_point_list.md) under _Listeners_ sections.
>
### Message Bus
Is the core of the messaging system.
Is used at the following scenarios:
[`MessageBus`](%gh-ic%/platform/extensions/src/com/intellij/util/messages/MessageBus.kt) is the core of the messaging system.
It is used in the following scenarios:
![Bus](bus.svg)
### Connection
Manages all subscriptions for particular client within particular bus.
Connection is represented by [`MessageBusConnection`](%gh-ic%/platform/extensions/src/com/intellij/util/messages/MessageBusConnection.kt) class and manages all subscriptions for a particular client within a particular bus.
![Connection](connection.svg)
* keeps number of *topic handler* mappings (callbacks to invoke when message for the target topic is received)
*Note*: not more than one handler per-topic within the same connection is allowed;
* it's possible to specify *default handler* and subscribe to the target topic without explicitly provided callback.
Connection will use that *default handler* when storing *(topic-handler)* mapping;
* it's possible to explicitly release acquired resources (*disconnect()* method).
Also, it can be plugged to standard semi-automatic disposing ([`Disposable`](%gh-ic%/platform/util/src/com/intellij/openapi/Disposable.java));
Connection stores *topic-handler* mappings - callbacks to invoke when message for the target topic is received (not more than one handler per topic within the same connection is allowed).
### Putting Altogether
It's possible to specify *default handler* and subscribe to the target topic without explicitly provided callback.
Connection will use that *default handler* when storing a topic-handler mapping.
*Defining business interface and topic*
It's possible to explicitly release acquired resources (see `disconnect()`).
Also, it can be plugged to standard semi-automatic disposing ([`Disposable`](%gh-ic%/platform/util/src/com/intellij/openapi/Disposable.java)).
## Messaging API Usage
### Defining a Business Interface and a Topic
Create an interface with the business methods and a topic field bound to the business interface:
```java
public interface ChangeActionNotifier {
@ -71,7 +69,7 @@ public interface ChangeActionNotifier {
}
```
*Subscribing*
### Subscribing to a Topic
![Subscribing](subscribe.svg)
@ -80,29 +78,33 @@ public interface ChangeActionNotifier {
{style="note"}
```java
public void init(MessageBus bus) {
bus.connect().subscribe(ActionTopics.CHANGE_ACTION_TOPIC,
new ChangeActionNotifier() {
@Override
public void beforeAction(Context context) {
// Process 'before action' event.
}
@Override
public void afterAction(Context context) {
// Process 'after action' event.
}
});
}
messageBus.connect().subscribe(ActionTopics.CHANGE_ACTION_TOPIC,
new ChangeActionNotifier() {
@Override
public void beforeAction(Context context) {
// Process 'before action' event.
}
@Override
public void afterAction(Context context) {
// Process 'after action' event.
}
});
```
*Publishing*
`MessageBus` instances are available via [`ComponentManager.getMessageBus()`](%gh-ic%/platform/extensions/src/com/intellij/openapi/components/ComponentManager.java).
Many standard interfaces implement returning a message bus, e.g., [`Application.getMessageBus()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/application/Application.java) and [`Project.getMessageBus()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/project/Project.java).
A number of public topics are used by the IntelliJ Platform, e.g., [`AppTopics`](%gh-ic%/platform/platform-api/src/com/intellij/AppTopics.java), [`ProjectTopics`](%gh-ic%/platform/projectModel-api/src/com/intellij/ProjectTopics.java), etc.
So, it's possible to subscribe to them in order to receive information about the processing.
### Publishing Messages
![Publishing](publish.svg)
```java
public void doChange(Context context) {
ChangeActionNotifier publisher =
myBus.syncPublisher(ActionTopics.CHANGE_ACTION_TOPIC);
messageBus.syncPublisher(ActionTopics.CHANGE_ACTION_TOPIC);
publisher.beforeAction(context);
try {
// do action
@ -112,13 +114,6 @@ public void doChange(Context context) {
}
```
*Existing resources*
* *MessageBus* instances are available via [`ComponentManager.getMessageBus()`](%gh-ic%/platform/extensions/src/com/intellij/openapi/components/ComponentManager.java)
Many standard interfaces implement a message bus, e.g., [`Application`](%gh-ic%/platform/core-api/src/com/intellij/openapi/application/Application.java) and [`Project`](%gh-ic%/platform/core-api/src/com/intellij/openapi/project/Project.java).
* A number of public topics are used by the IntelliJ Platform, e.g., [`AppTopics`](%gh-ic%/platform/platform-api/src/com/intellij/AppTopics.java), [`ProjectTopics`](%gh-ic%/platform/projectModel-api/src/com/intellij/ProjectTopics.java), etc.
So, it's possible to subscribe to them in order to receive information about the processing.
## Broadcasting
Message buses can be organised into hierarchies.
@ -128,70 +123,66 @@ Moreover, the IntelliJ Platform has them already:
That allows to notify subscribers registered in one message bus on messages sent to another message bus.
*Example:*
Example setup:
![Parent-child broadcast](parent_child_broadcast.svg)
Here we have a simple hierarchy (*application bus* is a parent of *project bus*) with three subscribers for the same topic.
The example setup presents a simple hierarchy (the *application bus* is a parent of the *project bus*) with three subscribers for the same topic.
We get the following if *topic1* defines broadcast direction as *TO\_CHILDREN*:
1. A message is sent to *topic1* via *application bus*;
2. *handler1* is notified about the message;
3. The message is delivered to the subscribers of the same topic within *project bus* (*handler2* and *handler3*);
If *topic1* defines broadcast direction as `TO_CHILDREN`, we get the following:
1. A message is sent to *topic1* via *application bus*.
2. *handler1* is notified about the message.
3. The message is delivered to the subscribers of the same topic within *project bus* (*handler2* and *handler3*).
*Benefits*
We don't need to bother with memory management of subscribers that are bound to child buses but interested in parent bus-level events.
Consider the example above we may want to have project-specific functionality that reacts to the application-level events.
The main benefit of broadcasting is managing subscribers that are bound to child buses but interested in parent bus-level events.
In the example above, we may want to have project-specific functionality that reacts to the application-level events.
All we need to do is to subscribe to the target topic within the *project bus*.
No hard reference to the project-level subscriber will be stored at application-level then, i.e., we just avoided memory leak on project re-opening.
*Options*
Broadcast configuration is defined per-topic.
The following options are available:
* TO\_CHILDREN_ (default);
* _NONE_;
* _TO\_PARENT_;
- `TO_CHILDREN` (default)
- `TO_DIRECT_CHILDREN`
- `NONE`
- `TO_PARENT`
See [`Topic.BroadcastDirection`](%gh-ic%/platform/extensions/src/com/intellij/util/messages/Topic.java) for detailed description of each option.
## Nested Messages
_Nested message_ is a message sent (directly or indirectly) during another message processing.
The IntelliJ Platform's Messaging infrastructure guarantees that all messages sent to particular topic will be delivered at the sending order.
The IntelliJ Platform's messaging infrastructure guarantees that all messages sent to particular topic will be delivered at the sending order.
*Example:*
Suppose we have the following configuration:
Consider the following configuration:
![Nested messages](nested_config.svg)
Let's see what happens if someone sends a message to the target topic:
When a message is sent to the target topic, the following happens:
* _message1_ is sent;
* _handler1_ receives _message1_ and sends _message2_ to the same topic;
* _handler2_ receives _message1_;
* _handler2_ receives _message2_;
* _handler1_ receives _message2_;
- _message1_ is sent
- _handler1_ receives _message1_ and sends _message2_ to the same topic
- _handler2_ receives _message1_
- _handler2_ receives _message2_
- _handler1_ receives _message2_
## Tips and Tricks
### Relief Listeners Management
[//]: # (TODO: revert link to https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)
Messaging infrastructure is very light-weight, so, it's possible to reuse it at local sub-systems in order to relieve [Subscribers](https://w.wiki/5xaV) construction.
Messaging infrastructure is very light-weight, so it's possible to reuse it at local sub-systems in order to relieve [Subscribers](https://w.wiki/5xaV) construction.
Let's see what is necessary to do then:
1. Define business interface to work with;
2. Create shared message bus and topic that uses the interface above (_shared_ here means that either _subject_ or _subscribers_ know about them);
1. Define business interface to work with.
2. Create shared message bus and topic that uses the interface above (_shared_ here means that either _subject_ or _subscribers_ know about them).
Let's compare that with a manual implementation:
A manual implementation would require:
1. Define listener interface (business interface);
2. Provide reference to the _subject_ to all interested listeners;
3. Add listeners storage and listeners management methods (add/remove) to the _subject_;
4. Manually iterate all listeners and call target callback in all places where new event is fired;
1. Define listener interface (business interface).
2. Provide reference to the _subject_ to all interested listeners.
3. Add listeners storage and listeners management methods (add/remove) to the _subject_.
4. Manually iterate all listeners and call target callback in all places where new event is fired.
### Avoid Shared Data Modification from Subscribers