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:
|
||||
* Test for ComponentState.{init,destroy}
|
||||
* Test for ComponentState.{init,destroy} and driver-related stuff
|
||||
* Registry tests
|
||||
* Registry doc
|
||||
* Implement "DriverFor" support
|
||||
* General usage documentation
|
||||
* Uncouple component-provided names from the library
|
||||
* Automatically-updated singletons
|
||||
|
@ -12,3 +11,4 @@ To Do:
|
|||
Other ideas (maybe later if needed):
|
||||
* Unregistering components
|
||||
* 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;
|
||||
}
|
||||
|
||||
// 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
|
||||
injectDependencies( adding );
|
||||
|
||||
|
@ -446,6 +455,7 @@ public class ComponentRegistry
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private void destroyComponent( int index )
|
||||
throws ComponentDestructionException
|
||||
{
|
||||
|
|
|
@ -44,6 +44,11 @@ public final class ComponentState
|
|||
/** State records for the component's reverse dependencies */
|
||||
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 */
|
||||
@SuppressWarnings( "rawtypes" )
|
||||
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
|
||||
* component's dependencies, then call the startup action if one is configured.
|
||||
* <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
|
||||
* 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
|
||||
* <p>
|
||||
* 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
|
||||
* will mark the component as inactive.
|
||||
* shutting them down (stopping "normal" reverse dependencies first, then shutting down drivers). Then it will call
|
||||
* the configured shutdown action, if there is one. If both steps succeed, it will mark the component as inactive.
|
||||
* <p>
|
||||
* If the method is called on an inactive component, nothing will happen.
|
||||
*
|
||||
|
@ -269,8 +275,13 @@ public final class ComponentState
|
|||
assert this.initialised;
|
||||
|
||||
for ( final ComponentState rdepState : this.reverseDependencies ) {
|
||||
if ( !this.drivers.contains( rdepState ) ) {
|
||||
rdepState.stop( );
|
||||
}
|
||||
}
|
||||
for ( final ComponentState drvState : this.drivers ) {
|
||||
drvState.stop( );
|
||||
}
|
||||
this.runLifecycleAction( LifecycleStage.STOP );
|
||||
this.active = false;
|
||||
}
|
||||
|
@ -301,7 +312,8 @@ public final class ComponentState
|
|||
* Initialises the component
|
||||
* <p>
|
||||
* 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
|
||||
* if an error occurs while executing an initialisation action
|
||||
|
@ -323,6 +335,9 @@ public final class ComponentState
|
|||
}
|
||||
this.runLifecycleAction( LifecycleStage.INITIALISE );
|
||||
this.initialised = true;
|
||||
for ( final ComponentState drvState : this.drivers ) {
|
||||
drvState.init( );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -330,7 +345,8 @@ public final class ComponentState
|
|||
* Destroys the component
|
||||
* <p>
|
||||
* 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
|
||||
* if an error occurs while executing a destruction action
|
||||
|
@ -351,8 +367,13 @@ public final class ComponentState
|
|||
}
|
||||
|
||||
for ( final ComponentState rdepState : this.reverseDependencies ) {
|
||||
if ( !this.drivers.contains( rdepState ) ) {
|
||||
rdepState.destroy( );
|
||||
}
|
||||
}
|
||||
for ( final ComponentState drvState : this.drivers ) {
|
||||
drvState.destroy( );
|
||||
}
|
||||
this.runLifecycleAction( LifecycleStage.DESTROY );
|
||||
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.
|
||||
* <p>
|
||||
|
@ -438,15 +476,24 @@ public final class ComponentState
|
|||
for ( final ComponentState depState : this.dependencies ) {
|
||||
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.active = true;
|
||||
for ( final ComponentState drvState : this.drivers ) {
|
||||
drvState.startNoChecks( );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal component restart method
|
||||
* <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
|
||||
* 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 ) {
|
||||
this.runLifecycleAction( LifecycleStage.START );
|
||||
for ( final ComponentState drvState : this.drivers ) {
|
||||
drvState.startIfPreviouslyActive( );
|
||||
}
|
||||
for ( final ComponentState rDepState : this.reverseDependencies ) {
|
||||
rDepState.startIfPreviouslyActive( );
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue