As applications become more complex and have multiple components, there becomes a need to coordinate and sequence initialization steps. Consider the following use cases:
A component provides access to a database, however (schema) migration must be performed before any other component attempts to access the data.
A component provides access to data that is cached from an external server, but wants to check for updated data before other components use the out-of-date cached data.
A component that uses both of the previously mentioned components, but can’t be accessed until both dependent components are ready for use.
This article discusses how this is achieved in KOS.
Embedded systems are full of asynchronous initializations and sequencing problems. To alleviate these issues, KOS provides infrastructure that makes dealing with these issues easy.
The basic KOS building block for asynchronous initialization is the ReadyIndicator class. A ReadyIndicator has a concept of being "ready":
isReady() : Returns true when object is ready
setReady() : Sets the ready flag, indicating that the object is ready
The ready indicator also provides callback support based on its ready state:
isReady(callback) : Returns true if ready, but if not, adds the callback to the list
whenReady(callback) : If ready, calls the callback, otherwise adds it to the list
KOS uses this simple indicator object as a building block to provide higher level functionality. Let’s look at a few examples of increasing complexity.
Consider the first two use cases mentioned in the overview section. In these, a component should not be accessed until it completes some task. The component could create a ReadyIndicator and make it visible to other components, or it could simply implement the Ready interface, which exposes it in a standard way.
Furthermore, if the components don’t extend any other class, they are free to extend ReadyBean, which provides the underlying indicator and implements the Ready interface. In this case the component simply needs to call setReady() to indicate that it is ready for use.
The third use case is a bit more complex in that it depends on the first two components and then is only ready once these dependent components are ready. This can be achieved by adding a callback to the child components, but when used in conjunction with the KOS bean context and autowiring the parent component can simply implement ReadyListener and the context will handle attaching all the necessary callbacks.
Since ReadyBean also implements the ReadyListener interface, any components that extend ReadyBean and are used with the KOS bean context will automatically be sequenced based on their dependencies. For components that can’t extend ReadyBean, they can simply implement Ready and ReadyListener interfaces to achieve the same functionality.
For more information about the KOS bean context and how sequencing of Ready objects occur, please refer to Concept: Bean Context.
While KOS provides a great deal of built-in functionality around ReadyIndicator, instances of ReadyIndicator can also be used to coordinate more complex use cases without having to rely on custom interfaces or creating hard couplings between classes.