Listeners

KOS is built around a lot of asynchronous behavior, where events can happen at any time and multiple components may need to respond. Often, you want to send notifications or updates to multiple listeners automatically whenever something changes. KOS provides a standard pattern for this that makes it very simple: you just implement the appropriate listener interface, and KOS handles all the wiring and notifications for you.

Typically, listening to events requires careful manual management. You have to locate the object you want to listen to, usually in a parent context, register yourself as a listener, and remember to unregister later. In an application-based system, this can be especially tricky because listeners need to dynamically register and unregister as applications load and unload. Forgetting to unregister can lead to memory leaks.

KOS solves this problem with ListenerList<T>, a special list that automatically registers listeners of type Twhen they appear and automatically unregisters them when their context is destroyed. All you have to do is implement the interface T to become a listener, and add the listener to the context after creating an instance. KOS takes care of registration, unregistration, and context management in the background. This pattern works up and down the context hierarchy, unlike standard autowiring: listeners are registered whether they appear in a parent, current, or child context, making it extremely convenient.

Objects are added to and removed from the ListenerList on the fly as they are created and destroyed, so the system always knows which listeners are active without any extra work on the developer’s part.

For example, consider a Document class that notifies its listeners whenever the content changes. The Document class itself doesn’t need to know who is listening, decoupling notification from listening.


Other classes can listen for these events and react. For example, an autosave service:

Notifying Different Types of Listeners

Race conditions can occur where a listener receives events before it is fully initialized. KOS provides the @ListenerPolicy
annotation to explicitly manage this behavior for classes implementing the Ready interface. By specifying a policy, developers
can determine whether:

  • CALLBACK: Receive callbacks immediately, regardless of readiness.
  • NO_CALLBACK: Skip callbacks entirely until the class is ready.
  • WHEN_READY: Queue callbacks until the service is ready, then deliver them.

Classes that have a policy annotation can be subclassed and overridden as expected. If not policy annotation is specified
by the class, or inherited, the policy defaults to CALLBACK.

Single policy overrides can be defined as follows:

While, multiple policies can be defined using the @ListenerPolicies annotation.