 
This application note explores how KOS objects can communicate with each other using KOS listeners.
You should have completed the First One application note, as it builds the framework used in this and other app notes.
It’s common in software design for objects to communicate with each other. The most obvious way is through direct method calls. However, this approach can lead to an overly coupled solution that becomes difficult to maintain.
An alternative is to use messages. KOS provides an excellent mechanism to both send and receive messages using its ListenerList class.
 
With this technique, senders are unaware of which objects are receiving, and receivers are unaware of which objects are sending. Producers simply say "I send this type of message", while consumers say "I want to receive this type of message". This loose coupling between objects leads to easier development and maintenance.
| Message A message is simply a unit of communication that a source sends to one or more recipients. A message may or may not contain a data payload. Messages are also referred to as events. | 
In this section, we’ll add code to our app note framework developed in the First One page.
We need to do three things:
Define what message is to be sent and what (if any) payload does it have
Define the receiver class or classes (the "listeners")
Define the sender class
| Source code for this and most other Java reference pages is available on GitHub. | 
We are going to create two messages:
one without a payload : somethingHappened(), and
one with a payload : somethingHappenedWithData(SomeData someData).
Both are defined inside a single listener interface:
MessageListener interfacepackage com.example.listeners;
public interface MessageListener {
    void somethingHappened();
    void somethingHappenedWithData(SomeData someData);
}Here’s our payload, which is a simple data bean:
SomeData payload beanpackage com.example.listeners;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SomeData {
    private int id;
    private String firstName;
    private String lastName;
}For our example, we are going to set up two receivers, Listener1 and Listener2. Here’s the first listener:
Listener1 classpackage com.example.listeners;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Listener1 implements MessageListener { (1)
    @Override
    public void somethingHappened() { (2)
        log.info("> Listener1.somethingHappened()");
    }
    @Override
    public void somethingHappenedWithData(SomeData someData) { (3)
        log.info("> Listener1.somethingHappenedWithData()");
        log.info("> {}", someData);
    }
}| 1 | Implement the message listener interface | 
| 2 | Override the first message | 
| 3 | Override the second message | 
As you can see, we are simply logging information when those methods are executed.
The second listener is identical to the first except for a couple log statements:
Listener2 classpackage com.example.listeners;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Listener2 implements MessageListener {
    @Override
    public void somethingHappened() {
        log.info("> Listener2.somethingHappened()");
    }
    @Override
    public void somethingHappenedWithData(SomeData someData) {
        log.info("> Listener2.somethingHappenedWithData()");
        log.info("> {}", someData);
    }
}These two listeners will now get called whenever any sender sends those messages.
Next, we create a message sender that we name Speaker. Here it is:
Speaker classpackage com.example.listeners;
import com.tccc.kos.commons.core.context.annotations.Autowired;
import com.tccc.kos.commons.util.ListenerList;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Speaker {
    @Autowired
    private ListenerList<MessageListener> listenerList; (1)
    public void saySomething() {
        log.info("> Speaker.saySomething()");
        listenerList.fireEvent(MessageListener::somethingHappened); (2)
    }
    public void saySomethingWithData() {
        log.info("> Speaker.saySomethingWithData()");
        SomeData someData = new SomeData(23, "Fred", "Flintstone");
        listenerList.fireEvent(listener -> listener.somethingHappenedWithData(someData)); (3)
    }
    public void saySomethingWithDataToSpecificClass() {
        log.info("> Speaker.saySomethingWithDataToSpecificClass()");
        SomeData someData1 = new SomeData(24, "Wilma", "Flintstone");
        listenerList.fireEvent(Listener1.class, listener -> listener.somethingHappenedWithData(someData1)); (4)
        SomeData someData2 = new SomeData(25, "Barney", "Rubble");
        listenerList.fireEvent(Listener2.class, listener -> listener.somethingHappenedWithData(someData2)); (5)
    }
}| 1 | Autowire a ListenerList indicating the type of message it will handle (KOS instantiates this object) | 
| 2 | Send the message that contains no payload to all listeners | 
| 3 | Send the message with given payload to all listeners | 
| 4 | Send a message to only the Listener1class | 
| 5 | Send a message to only the Listener2class | 
In order to execute our code, we need to modify our KOS application by adding a ListenerModule class and making a tweak to MyKosApp.
The ListenerModule class initializes our application and then runs its code:
ListenerModule classpackage com.example.listeners;
import com.example.Module;
import com.tccc.kos.commons.core.context.BeanContext;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ListenerModule implements Module {
    @Override
    public void init(BeanContext ctx) {
        log.info("> ListenerModule.init()");
        ctx.add(new Speaker()); (1)
        ctx.add(new Listener1());
        ctx.add(new Listener2());
    }
    @Override
    @SneakyThrows
    public void run() {
        log.info("> ListenerModule.run()");
        Speaker speaker = Objects.requireNonNull(ctx.getBean(Speaker.class)); (2)
        Thread.sleep(1000);
        speaker.saySomething(); (3)
        Thread.sleep(1000);
        speaker.saySomethingWithData(); (3)
        Thread.sleep(1000);
        speaker.saySomethingWithDataToSpecificClass(); (3)
    }
}| 1 | Create each of our objects and add them to the context | 
| 2 | Grab a reference to the speaker class | 
| 3 | Issue the three different calls to test our messaging | 
Change the one line in our KOS application class as indicated below:
MyKosApp classpackage com.example;
public class MyKosApp extends SystemApplication<BaseAppConfig> {
    private Module module;
    public void initModule() {
        module = new ListenerModule(getCtx()); (1)
    }
    // . . .
}| 1 | Modify this line to instantiate the ListenerModule | 
Debug this program in your IDE and monitor the log output.
The application log output should look something like this (blank lines inserted for clarity):
ListernerModule output> ====== BEGIN =========================================
> MyKosApp.load()
> ListenerModule.init()
> MyKosApp.start()
> ListenerModule.run()
> Speaker.saySomething() (1)
> Listener2.somethingHappened() (2)
> Listener1.somethingHappened()
> Speaker.saySomethingWithData() (3)
> Listener2.somethingHappenedWithData() (4)
> SomeData(id=23, firstName=Fred, lastName=Flintstone)
> Listener1.somethingHappenedWithData()
> SomeData(id=23, firstName=Fred, lastName=Flintstone)
> Speaker.saySomethingWithDataToSpecificClass() (5)
> Listener1.somethingHappenedWithData()
> SomeData(id=24, firstName=Wilma, lastName=Flintstone) (6)
> Listener2.somethingHappenedWithData()
> SomeData(id=25, firstName=Barney, lastName=Rubble)
> ====== END ===========================================| 1 | The SpeakerclasssaySomething()method is executed, which fires thesomethingHappended()event | 
| 2 | Both listeners receive that message (note the receive order is not guaranteed) | 
| 3 | The SpeakerclasssaySomethingWithData()method is executed, which fires thesomethingHappenedWithData()event | 
| 4 | Both listeners receive that message and display the same data | 
| 5 | The Speakerclass now sends a message only toListener1 | 
| 6 | The Speakerclass now sends a message only toListener2 |