Component state and registry - Drivers support
A component with "drivers" will initialise/start its drivers after it is initialised/started itself. It will also stop/destroy non-driver reverse dependencies before stopping/destroying its drivers.
This commit is contained in:
parent
81ea62047e
commit
68a337ec6a
3 changed files with 71 additions and 11 deletions
4
TODO
4
TODO
|
@ -1,8 +1,7 @@
|
||||||
To Do:
|
To Do:
|
||||||
* Test for ComponentState.{init,destroy}
|
* Test for ComponentState.{init,destroy} and driver-related stuff
|
||||||
* Registry tests
|
* Registry tests
|
||||||
* Registry doc
|
* Registry doc
|
||||||
* Implement "DriverFor" support
|
|
||||||
* General usage documentation
|
* General usage documentation
|
||||||
* Uncouple component-provided names from the library
|
* Uncouple component-provided names from the library
|
||||||
* Automatically-updated singletons
|
* Automatically-updated singletons
|
||||||
|
@ -12,3 +11,4 @@ To Do:
|
||||||
Other ideas (maybe later if needed):
|
Other ideas (maybe later if needed):
|
||||||
* Unregistering components
|
* Unregistering components
|
||||||
* Hierarchy of registries
|
* Hierarchy of registries
|
||||||
|
* Driver-related helpers (e.g. determine type of driver components, register/unregister drivers with main)
|
|
@ -197,6 +197,15 @@ public class ComponentRegistry
|
||||||
nLeft -= found;
|
nLeft -= found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up driver components
|
||||||
|
for ( int i = 0 ; i < nAdd ; i++ ) {
|
||||||
|
TempBuildRec c = adding.get( i );
|
||||||
|
String df = c.info.getDriverFor( );
|
||||||
|
if ( df != null ) {
|
||||||
|
c.state.setDriverFor( byName.get( df ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Inject and track dependencies
|
// Inject and track dependencies
|
||||||
injectDependencies( adding );
|
injectDependencies( adding );
|
||||||
|
|
||||||
|
@ -446,6 +455,7 @@ public class ComponentRegistry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void destroyComponent( int index )
|
private void destroyComponent( int index )
|
||||||
throws ComponentDestructionException
|
throws ComponentDestructionException
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,6 +44,11 @@ public final class ComponentState
|
||||||
/** State records for the component's reverse dependencies */
|
/** State records for the component's reverse dependencies */
|
||||||
private final HashSet< ComponentState > reverseDependencies = new HashSet< >( );
|
private final HashSet< ComponentState > reverseDependencies = new HashSet< >( );
|
||||||
|
|
||||||
|
/** State records for the component's drivers */
|
||||||
|
private final HashSet< ComponentState > drivers = new HashSet< >( );
|
||||||
|
/** Main component (i.e. component this component is a driver for) */
|
||||||
|
private ComponentState mainComponent;
|
||||||
|
|
||||||
/** Lifecycle actions for the current component */
|
/** Lifecycle actions for the current component */
|
||||||
@SuppressWarnings( "rawtypes" )
|
@SuppressWarnings( "rawtypes" )
|
||||||
private final ThrowingConsumer[] lcActions;
|
private final ThrowingConsumer[] lcActions;
|
||||||
|
@ -217,7 +222,8 @@ public final class ComponentState
|
||||||
* If the component is already active, nothing is done. If it is inactive, the method will try starting the
|
* If the component is already active, nothing is done. If it is inactive, the method will try starting the
|
||||||
* component's dependencies, then call the startup action if one is configured.
|
* component's dependencies, then call the startup action if one is configured.
|
||||||
* <p>
|
* <p>
|
||||||
* If the method succeeds, the component will be marked as active.
|
* If these actions succeed, the component will be marked as active. Then, if the component has drivers, they will
|
||||||
|
* be started as well.
|
||||||
*
|
*
|
||||||
* @throws ComponentStartupException
|
* @throws ComponentStartupException
|
||||||
* if an exception occurs while running the startup action for this component or for one of its
|
* if an exception occurs while running the startup action for this component or for one of its
|
||||||
|
@ -246,8 +252,8 @@ public final class ComponentState
|
||||||
* Stops the component
|
* Stops the component
|
||||||
* <p>
|
* <p>
|
||||||
* This method attempts to shut down the component. If the component has reverse dependencies, it will start by
|
* This method attempts to shut down the component. If the component has reverse dependencies, it will start by
|
||||||
* shutting them down. Then it will call the configured shutdown action, if there is one. If both steps succeed, it
|
* shutting them down (stopping "normal" reverse dependencies first, then shutting down drivers). Then it will call
|
||||||
* will mark the component as inactive.
|
* the configured shutdown action, if there is one. If both steps succeed, it will mark the component as inactive.
|
||||||
* <p>
|
* <p>
|
||||||
* If the method is called on an inactive component, nothing will happen.
|
* If the method is called on an inactive component, nothing will happen.
|
||||||
*
|
*
|
||||||
|
@ -269,7 +275,12 @@ public final class ComponentState
|
||||||
assert this.initialised;
|
assert this.initialised;
|
||||||
|
|
||||||
for ( final ComponentState rdepState : this.reverseDependencies ) {
|
for ( final ComponentState rdepState : this.reverseDependencies ) {
|
||||||
rdepState.stop( );
|
if ( !this.drivers.contains( rdepState ) ) {
|
||||||
|
rdepState.stop( );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( final ComponentState drvState : this.drivers ) {
|
||||||
|
drvState.stop( );
|
||||||
}
|
}
|
||||||
this.runLifecycleAction( LifecycleStage.STOP );
|
this.runLifecycleAction( LifecycleStage.STOP );
|
||||||
this.active = false;
|
this.active = false;
|
||||||
|
@ -301,7 +312,8 @@ public final class ComponentState
|
||||||
* Initialises the component
|
* Initialises the component
|
||||||
* <p>
|
* <p>
|
||||||
* This method attempts to initialise a component. It makes sure that all of the component's dependencies have been
|
* This method attempts to initialise a component. It makes sure that all of the component's dependencies have been
|
||||||
* initialised, then executes the lifecycle action for the {@link LifecycleStage#INITIALISE INITIALISE} stage.
|
* initialised, then executes the lifecycle action for the {@link LifecycleStage#INITIALISE INITIALISE} stage. Then,
|
||||||
|
* if the component has drivers, it initialises them.
|
||||||
*
|
*
|
||||||
* @throws ComponentInitialisationException
|
* @throws ComponentInitialisationException
|
||||||
* if an error occurs while executing an initialisation action
|
* if an error occurs while executing an initialisation action
|
||||||
|
@ -323,6 +335,9 @@ public final class ComponentState
|
||||||
}
|
}
|
||||||
this.runLifecycleAction( LifecycleStage.INITIALISE );
|
this.runLifecycleAction( LifecycleStage.INITIALISE );
|
||||||
this.initialised = true;
|
this.initialised = true;
|
||||||
|
for ( final ComponentState drvState : this.drivers ) {
|
||||||
|
drvState.init( );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -330,7 +345,8 @@ public final class ComponentState
|
||||||
* Destroys the component
|
* Destroys the component
|
||||||
* <p>
|
* <p>
|
||||||
* This method attempts to destroy a component. It makes sure that all of the component's reverse dependencies have
|
* This method attempts to destroy a component. It makes sure that all of the component's reverse dependencies have
|
||||||
* been destroyed, then executes the lifecycle action for the {@link LifecycleStage#DESTROY DESTROY} stage.
|
* been destroyed (starting with "normal" reverse dependencies, then processing the drivers), then executes the
|
||||||
|
* lifecycle action for the {@link LifecycleStage#DESTROY DESTROY} stage.
|
||||||
*
|
*
|
||||||
* @throws ComponentDestructionException
|
* @throws ComponentDestructionException
|
||||||
* if an error occurs while executing a destruction action
|
* if an error occurs while executing a destruction action
|
||||||
|
@ -351,7 +367,12 @@ public final class ComponentState
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( final ComponentState rdepState : this.reverseDependencies ) {
|
for ( final ComponentState rdepState : this.reverseDependencies ) {
|
||||||
rdepState.destroy( );
|
if ( !this.drivers.contains( rdepState ) ) {
|
||||||
|
rdepState.destroy( );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( final ComponentState drvState : this.drivers ) {
|
||||||
|
drvState.destroy( );
|
||||||
}
|
}
|
||||||
this.runLifecycleAction( LifecycleStage.DESTROY );
|
this.runLifecycleAction( LifecycleStage.DESTROY );
|
||||||
this.initialised = false;
|
this.initialised = false;
|
||||||
|
@ -375,6 +396,23 @@ public final class ComponentState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a component as the one this component is a driver for.
|
||||||
|
* <p>
|
||||||
|
* This will also update the main component to add this component as a driver.
|
||||||
|
*
|
||||||
|
* @param main
|
||||||
|
* the main component
|
||||||
|
*/
|
||||||
|
void setDriverFor( final ComponentState main )
|
||||||
|
{
|
||||||
|
assert main.registry == this.registry;
|
||||||
|
assert this.mainComponent == null;
|
||||||
|
this.mainComponent = main;
|
||||||
|
main.drivers.add( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes a lifecycle action.
|
* Executes a lifecycle action.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -438,15 +476,24 @@ public final class ComponentState
|
||||||
for ( final ComponentState depState : this.dependencies ) {
|
for ( final ComponentState depState : this.dependencies ) {
|
||||||
depState.startNoChecks( );
|
depState.startNoChecks( );
|
||||||
}
|
}
|
||||||
|
if ( this.active ) {
|
||||||
|
// If the current component is a driver, it will have been started by its main component, so we need to
|
||||||
|
// avoid re-executing the start action.
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.runLifecycleAction( LifecycleStage.START );
|
this.runLifecycleAction( LifecycleStage.START );
|
||||||
this.active = true;
|
this.active = true;
|
||||||
|
for ( final ComponentState drvState : this.drivers ) {
|
||||||
|
drvState.startNoChecks( );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal component restart method
|
* Internal component restart method
|
||||||
* <p>
|
* <p>
|
||||||
* Attempts to restart a component if it was active before {@link #restart()} was called.
|
* Attempts to restart a component if it was active before {@link #restart()} was called. Calls the start action
|
||||||
|
* first, then restart the drivers, then other reverse dependencies.
|
||||||
*
|
*
|
||||||
* @throws ComponentStartupException
|
* @throws ComponentStartupException
|
||||||
* if an exception occurs while running the startup action for this component or for one of its reverse
|
* if an exception occurs while running the startup action for this component or for one of its reverse
|
||||||
|
@ -457,6 +504,9 @@ public final class ComponentState
|
||||||
{
|
{
|
||||||
if ( this.wasActive ) {
|
if ( this.wasActive ) {
|
||||||
this.runLifecycleAction( LifecycleStage.START );
|
this.runLifecycleAction( LifecycleStage.START );
|
||||||
|
for ( final ComponentState drvState : this.drivers ) {
|
||||||
|
drvState.startIfPreviouslyActive( );
|
||||||
|
}
|
||||||
for ( final ComponentState rDepState : this.reverseDependencies ) {
|
for ( final ComponentState rDepState : this.reverseDependencies ) {
|
||||||
rDepState.startIfPreviouslyActive( );
|
rDepState.startIfPreviouslyActive( );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue