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:
Emmanuel BENOîT 2015-09-17 10:57:46 +02:00
parent 81ea62047e
commit 68a337ec6a
3 changed files with 71 additions and 11 deletions

4
TODO
View file

@ -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)

View file

@ -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
{

View file

@ -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( );
}