Component state and registry - fixes and refactoring
* Errors during shutdown or destruction will be thrown as exceptions. Returning the collection of errors was clumsy, at best - if something goes wrong, the registry has failed anyway. * Recursive initialisation and destruction methods in ComponentState * Use ComponentState's methods while initialising, starting up, shutting down or destroying the registry.
This commit is contained in:
parent
7f919349e9
commit
81ea62047e
5 changed files with 174 additions and 237 deletions
3
TODO
3
TODO
|
@ -1,5 +1,5 @@
|
||||||
To Do:
|
To Do:
|
||||||
* Fix initialisation / startup from Registry.register()
|
* Test for ComponentState.{init,destroy}
|
||||||
* Registry tests
|
* Registry tests
|
||||||
* Registry doc
|
* Registry doc
|
||||||
* Implement "DriverFor" support
|
* Implement "DriverFor" support
|
||||||
|
@ -8,7 +8,6 @@ To Do:
|
||||||
* Automatically-updated singletons
|
* Automatically-updated singletons
|
||||||
* Registry: get all component states
|
* Registry: get all component states
|
||||||
* Document exceptions
|
* Document exceptions
|
||||||
* Not too fond of stop()/destroy() returning exceptions
|
|
||||||
|
|
||||||
Other ideas (maybe later if needed):
|
Other ideas (maybe later if needed):
|
||||||
* Unregistering components
|
* Unregistering components
|
||||||
|
|
|
@ -216,10 +216,7 @@ public class ComponentRegistry
|
||||||
// Activate autostart components
|
// Activate autostart components
|
||||||
if ( this.active ) {
|
if ( this.active ) {
|
||||||
for ( int i = 0 ; i < nOld + nAdd ; i++ ) {
|
for ( int i = 0 ; i < nOld + nAdd ; i++ ) {
|
||||||
ComponentState cmp = this.components.get( i );
|
autostartComponent( i );
|
||||||
if ( cmp.hasAutostart( ) ) {
|
|
||||||
startComponentWithFailure( cmp );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,41 +243,21 @@ public class ComponentRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean destroy( )
|
public void destroy( )
|
||||||
throws IllegalStateException
|
throws IllegalStateException , ComponentShutdownException , ComponentDestructionException
|
||||||
{
|
|
||||||
return this.destroy( null );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean destroy( Collection< Throwable > errors )
|
|
||||||
throws IllegalStateException
|
|
||||||
{
|
{
|
||||||
if ( this.failed ) {
|
if ( this.failed ) {
|
||||||
throw new IllegalStateException( "destroy() called on failed registry" );
|
throw new IllegalStateException( "destroy() called on failed registry" );
|
||||||
}
|
}
|
||||||
if ( !this.initialised ) {
|
if ( !this.initialised ) {
|
||||||
return true;
|
return;
|
||||||
}
|
|
||||||
if ( this.active && !this.stop( errors ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.stop( );
|
||||||
for ( int i = this.components.size( ) - 1 ; i >= 0 ; i-- ) {
|
for ( int i = this.components.size( ) - 1 ; i >= 0 ; i-- ) {
|
||||||
try {
|
destroyComponent( i );
|
||||||
ComponentState cmp = this.components.get( i );
|
|
||||||
cmp.runLifecycleAction( LifecycleStage.DESTROY );
|
|
||||||
cmp.setInitialised( false );
|
|
||||||
} catch ( Throwable t ) {
|
|
||||||
if ( errors != null ) {
|
|
||||||
errors.add( t );
|
|
||||||
}
|
|
||||||
this.failed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initialised = false;
|
this.initialised = false;
|
||||||
return !this.failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -299,50 +276,26 @@ public class ComponentRegistry
|
||||||
|
|
||||||
int nComponents = this.components.size( );
|
int nComponents = this.components.size( );
|
||||||
for ( int i = 0 ; i < nComponents ; i++ ) {
|
for ( int i = 0 ; i < nComponents ; i++ ) {
|
||||||
ComponentState cmp = this.components.get( i );
|
autostartComponent( i );
|
||||||
if ( cmp.hasAutostart( ) && !cmp.isActive( ) ) {
|
|
||||||
startComponentWithFailure( cmp );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initialised = true;
|
this.initialised = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean stop( )
|
public void stop( )
|
||||||
throws IllegalStateException
|
throws IllegalStateException , ComponentShutdownException
|
||||||
{
|
|
||||||
return this.stop( null );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean stop( Collection< Throwable > errors )
|
|
||||||
throws IllegalStateException
|
|
||||||
{
|
{
|
||||||
if ( this.failed ) {
|
if ( this.failed ) {
|
||||||
throw new IllegalStateException( "destroy() called on failed registry" );
|
throw new IllegalStateException( "stop() called on failed registry" );
|
||||||
}
|
}
|
||||||
if ( !this.active ) {
|
if ( !this.active ) {
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( int i = this.components.size( ) - 1 ; i >= 0 ; i-- ) {
|
for ( int i = this.components.size( ) - 1 ; i >= 0 ; i-- ) {
|
||||||
try {
|
stopComponent( i );
|
||||||
ComponentState cmp = this.components.get( i );
|
|
||||||
if ( cmp.isActive( ) ) {
|
|
||||||
cmp.runLifecycleAction( LifecycleStage.STOP );
|
|
||||||
cmp.setActive( false );
|
|
||||||
}
|
|
||||||
} catch ( Throwable t ) {
|
|
||||||
if ( errors != null ) {
|
|
||||||
errors.add( t );
|
|
||||||
}
|
|
||||||
this.failed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.active = false;
|
this.active = false;
|
||||||
return !this.failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -455,42 +408,52 @@ public class ComponentRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void initComponent( int i )
|
private void initComponent( int index )
|
||||||
throws ComponentInitialisationException
|
throws ComponentInitialisationException
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
ComponentState cmp = this.components.get( i );
|
this.components.get( index ).init( );
|
||||||
try {
|
} catch ( RuntimeException e ) {
|
||||||
cmp.runLifecycleAction( LifecycleStage.INITIALISE );
|
|
||||||
} catch ( ComponentInitialisationException e ) {
|
|
||||||
throw e;
|
|
||||||
} catch ( Throwable t ) {
|
|
||||||
throw new ComponentInitialisationException( t );
|
|
||||||
}
|
|
||||||
cmp.setInitialised( true );
|
|
||||||
} catch ( ComponentInitialisationException e ) {
|
|
||||||
this.failed = true;
|
this.failed = true;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void startComponentWithFailure( ComponentState cmp )
|
private void autostartComponent( int index )
|
||||||
throws ComponentStartupException
|
throws ComponentStartupException
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
this.startComponent( cmp );
|
ComponentState cmp = this.components.get( index );
|
||||||
} catch ( ComponentStartupException e ) {
|
if ( cmp.hasAutostart( ) ) {
|
||||||
|
cmp.start( );
|
||||||
|
}
|
||||||
|
} catch ( RuntimeException e ) {
|
||||||
this.failed = true;
|
this.failed = true;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void startComponent( ComponentState cmp )
|
private void stopComponent( int index )
|
||||||
throws ComponentStartupException
|
throws ComponentDestructionException
|
||||||
{
|
{
|
||||||
cmp.runStartupAction( );
|
try {
|
||||||
cmp.setActive( true );
|
this.components.get( index ).init( );
|
||||||
|
} catch ( RuntimeException e ) {
|
||||||
|
this.failed = true;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroyComponent( int index )
|
||||||
|
throws ComponentDestructionException
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
this.components.get( index ).init( );
|
||||||
|
} catch ( RuntimeException e ) {
|
||||||
|
this.failed = true;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
package info.ebenoit.ebul.cmp;
|
|
||||||
|
|
||||||
|
|
||||||
public class ComponentRestartException
|
|
||||||
extends ComponentException
|
|
||||||
{
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -6812486665718289373L;
|
|
||||||
|
|
||||||
|
|
||||||
public ComponentRestartException( )
|
|
||||||
{
|
|
||||||
super( );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ComponentRestartException( final String message , final Throwable cause )
|
|
||||||
{
|
|
||||||
super( message , cause );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ComponentRestartException( final String message )
|
|
||||||
{
|
|
||||||
super( message );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ComponentRestartException( final Throwable cause )
|
|
||||||
{
|
|
||||||
super( cause );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
package info.ebenoit.ebul.cmp;
|
package info.ebenoit.ebul.cmp;
|
||||||
|
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -210,7 +211,7 @@ public final class ComponentState
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to start the component
|
* Starts the component
|
||||||
* <p>
|
* <p>
|
||||||
* This method attempts to start the component. The component must be initialised and the registry must be active.
|
* This method attempts to start the component. The component must be initialised and the registry must be active.
|
||||||
* 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
|
||||||
|
@ -242,7 +243,7 @@ public final class ComponentState
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to stop 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. Then it will call the configured shutdown action, if there is one. If both steps succeed, it
|
||||||
|
@ -250,86 +251,110 @@ public final class ComponentState
|
||||||
* <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.
|
||||||
*
|
*
|
||||||
* @return <code>null</code> if the method succeeds, or an exception thrown by a shutdown action.
|
|
||||||
* @throws IllegalStateException
|
* @throws IllegalStateException
|
||||||
* if the registry has failed.
|
* if the registry has failed.
|
||||||
|
* @throws ComponentShutdownException
|
||||||
|
* if an error occurs during shutdown
|
||||||
*/
|
*/
|
||||||
public Throwable stop( )
|
public void stop( )
|
||||||
throws IllegalStateException
|
throws IllegalStateException , ComponentShutdownException
|
||||||
{
|
{
|
||||||
if ( this.registry.hasFailed( ) ) {
|
if ( this.registry.hasFailed( ) ) {
|
||||||
throw new IllegalStateException( "registry has failed" );
|
throw new IllegalStateException( "registry has failed" );
|
||||||
}
|
}
|
||||||
this.wasActive = this.active;
|
this.wasActive = this.active;
|
||||||
if ( !this.active ) {
|
if ( !this.active ) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
assert this.initialised;
|
assert this.initialised;
|
||||||
|
|
||||||
for ( final ComponentState rdepState : this.reverseDependencies ) {
|
for ( final ComponentState rdepState : this.reverseDependencies ) {
|
||||||
final Throwable t = rdepState.stop( );
|
rdepState.stop( );
|
||||||
if ( t != null ) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
this.runLifecycleAction( LifecycleStage.STOP );
|
||||||
try {
|
|
||||||
this.runLifecycleAction( LifecycleStage.STOP );
|
|
||||||
} catch ( final Throwable t ) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.active = false;
|
this.active = false;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to restart the component
|
* Restarts the component
|
||||||
* <p>
|
* <p>
|
||||||
* This method attempts to restart a component. It will stop the component and its reverse dependencies, then start
|
* This method attempts to restart a component. It will stop the component and its reverse dependencies, then start
|
||||||
* all components that were previously active.
|
* all components that were previously active.
|
||||||
*
|
*
|
||||||
* @throws IllegalStateException
|
* @throws IllegalStateException
|
||||||
* if the registry has failed
|
* if the registry has failed
|
||||||
* @throws ComponentRestartException
|
* @throws ComponentShutdownException
|
||||||
* if an error occurred either during shutdown or during startup
|
* if an error occurs during shutdown
|
||||||
|
* @throws ComponentStartupException
|
||||||
|
* if an error occurs while restarting the components
|
||||||
*/
|
*/
|
||||||
public void restart( )
|
public void restart( )
|
||||||
throws IllegalStateException , ComponentRestartException
|
throws IllegalStateException , ComponentShutdownException , ComponentStartupException
|
||||||
{
|
{
|
||||||
final Throwable t = this.stop( );
|
this.stop( );
|
||||||
if ( t != null ) {
|
|
||||||
throw new ComponentRestartException( "failed to stop" , t );
|
|
||||||
}
|
|
||||||
|
|
||||||
this.startIfPreviouslyActive( );
|
this.startIfPreviouslyActive( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the component's initialisation flag. Internal method used by {@link ComponentRegistry}.
|
* Initialises the component
|
||||||
*
|
* <p>
|
||||||
* @param initialised
|
* This method attempts to initialise a component. It makes sure that all of the component's dependencies have been
|
||||||
* <code>true</code> if the component is to be marked as initialised, <code>false</code> if it is to be
|
* initialised, then executes the lifecycle action for the {@link LifecycleStage#INITIALISE INITIALISE} stage.
|
||||||
* marked as uninitialised
|
*
|
||||||
|
* @throws ComponentInitialisationException
|
||||||
|
* if an error occurs while executing an initialisation action
|
||||||
|
* @throws IllegalStateException
|
||||||
|
* if the registry has failed
|
||||||
*/
|
*/
|
||||||
void setInitialised( final boolean initialised )
|
void init( )
|
||||||
|
throws ComponentInitialisationException , IllegalStateException
|
||||||
{
|
{
|
||||||
this.initialised = initialised;
|
if ( this.registry.hasFailed( ) ) {
|
||||||
|
throw new IllegalStateException( "registry has failed" );
|
||||||
|
}
|
||||||
|
if ( this.initialised ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( final ComponentState depState : this.dependencies ) {
|
||||||
|
depState.init( );
|
||||||
|
}
|
||||||
|
this.runLifecycleAction( LifecycleStage.INITIALISE );
|
||||||
|
this.initialised = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the component's activity flag. Internal method used by {@link ComponentRegistry}.
|
* 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.
|
||||||
*
|
*
|
||||||
* @param active
|
* @throws ComponentDestructionException
|
||||||
* <code>true</code> if the component is to be marked as active, <code>false</code> if it is to be marked
|
* if an error occurs while executing a destruction action
|
||||||
* as inactive
|
* @throws IllegalStateException
|
||||||
|
* if the registry has failed or if the component is active
|
||||||
*/
|
*/
|
||||||
void setActive( final boolean active )
|
void destroy( )
|
||||||
|
throws IllegalStateException , ComponentDestructionException
|
||||||
{
|
{
|
||||||
this.active = active;
|
if ( this.registry.hasFailed( ) ) {
|
||||||
|
throw new IllegalStateException( "registry has failed" );
|
||||||
|
}
|
||||||
|
if ( this.active ) {
|
||||||
|
throw new IllegalStateException( "attempting to destroy active component" );
|
||||||
|
}
|
||||||
|
if ( !this.initialised ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( final ComponentState rdepState : this.reverseDependencies ) {
|
||||||
|
rdepState.destroy( );
|
||||||
|
}
|
||||||
|
this.runLifecycleAction( LifecycleStage.DESTROY );
|
||||||
|
this.initialised = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -358,47 +383,42 @@ public final class ComponentState
|
||||||
*
|
*
|
||||||
* @param stage
|
* @param stage
|
||||||
* the lifecycle stage whose action must be executed
|
* the lifecycle stage whose action must be executed
|
||||||
* @throws Throwable
|
* @throws ComponentLifecycleException
|
||||||
* any exception thrown by the lifecycle action
|
* a component lifecycle exception corresponding to the specified stage if anything goes wrong when
|
||||||
|
* executing the action
|
||||||
*/
|
*/
|
||||||
void runLifecycleAction( final LifecycleStage stage )
|
private void runLifecycleAction( final LifecycleStage stage )
|
||||||
throws Throwable
|
throws ComponentLifecycleException
|
||||||
{
|
{
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
final ThrowingConsumer< Object > tc = this.lcActions[ stage.ordinal( ) ];
|
final ThrowingConsumer< Object > tc = this.lcActions[ stage.ordinal( ) ];
|
||||||
|
|
||||||
if ( tc != null ) {
|
if ( tc != null ) {
|
||||||
try {
|
try {
|
||||||
tc.accept( this.component );
|
try {
|
||||||
} catch ( final FunctionException e ) {
|
tc.accept( this.component );
|
||||||
throw e.getCause( );
|
} catch ( final FunctionException e ) {
|
||||||
|
throw e.getCause( );
|
||||||
|
}
|
||||||
|
} catch ( Throwable t ) {
|
||||||
|
if ( t instanceof ComponentLifecycleException ) {
|
||||||
|
throw (ComponentLifecycleException) t;
|
||||||
|
}
|
||||||
|
if ( t instanceof Error ) {
|
||||||
|
throw (Error) t;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
throw stage.exceptionType.getConstructor( Throwable.class ).newInstance( t );
|
||||||
|
} catch ( NoSuchMethodException | InstantiationException | IllegalAccessException
|
||||||
|
| IllegalArgumentException | InvocationTargetException e ) {
|
||||||
|
throw new RuntimeException( "internal error while handling lifecycle action exception" , e );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal method to run the component's startup action
|
|
||||||
* <p>
|
|
||||||
* Runs the action for {@link LifecycleStage#START}, wrapping exceptions that are not
|
|
||||||
* {@link ComponentStartupException} into a {@link ComponentStartupException} instance.
|
|
||||||
*
|
|
||||||
* @throws ComponentStartupException
|
|
||||||
* if the start action throws an exception
|
|
||||||
*/
|
|
||||||
void runStartupAction( )
|
|
||||||
throws ComponentStartupException
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
this.runLifecycleAction( LifecycleStage.START );
|
|
||||||
} catch ( final ComponentStartupException e ) {
|
|
||||||
throw e;
|
|
||||||
} catch ( final Throwable t ) {
|
|
||||||
throw new ComponentStartupException( t );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal component startup method.
|
* Internal component startup method.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -418,7 +438,7 @@ public final class ComponentState
|
||||||
for ( final ComponentState depState : this.dependencies ) {
|
for ( final ComponentState depState : this.dependencies ) {
|
||||||
depState.startNoChecks( );
|
depState.startNoChecks( );
|
||||||
}
|
}
|
||||||
runStartupAction( );
|
this.runLifecycleAction( LifecycleStage.START );
|
||||||
this.active = true;
|
this.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,25 +448,19 @@ public final class ComponentState
|
||||||
* <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.
|
||||||
*
|
*
|
||||||
* @throws ComponentRestartException
|
* @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
|
||||||
* dependencies
|
* dependencies
|
||||||
*/
|
*/
|
||||||
private void startIfPreviouslyActive( )
|
private void startIfPreviouslyActive( )
|
||||||
throws ComponentRestartException
|
throws ComponentStartupException
|
||||||
{
|
{
|
||||||
if ( this.wasActive ) {
|
if ( this.wasActive ) {
|
||||||
try {
|
this.runLifecycleAction( LifecycleStage.START );
|
||||||
runStartupAction( );
|
|
||||||
} catch ( final ComponentStartupException e ) {
|
|
||||||
throw new ComponentRestartException( "failed to restart " + this , e );
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( final ComponentState rDepState : this.reverseDependencies ) {
|
for ( final ComponentState rDepState : this.reverseDependencies ) {
|
||||||
rDepState.startIfPreviouslyActive( );
|
rDepState.startIfPreviouslyActive( );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package info.ebenoit.ebul.cmp;
|
package info.ebenoit.ebul.cmp;
|
||||||
|
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -116,8 +118,20 @@ public class TestComponentState
|
||||||
final boolean initialised , final boolean active )
|
final boolean initialised , final boolean active )
|
||||||
{
|
{
|
||||||
final ComponentState cs = new ComponentState( reg , ci );
|
final ComponentState cs = new ComponentState( reg , ci );
|
||||||
cs.setInitialised( initialised );
|
try {
|
||||||
cs.setActive( active );
|
if ( initialised ) {
|
||||||
|
Field f = ComponentState.class.getDeclaredField( "initialised" );
|
||||||
|
f.setAccessible( true );
|
||||||
|
f.setBoolean( cs , true );
|
||||||
|
}
|
||||||
|
if ( active ) {
|
||||||
|
Field f = ComponentState.class.getDeclaredField( "active" );
|
||||||
|
f.setAccessible( true );
|
||||||
|
f.setBoolean( cs , true );
|
||||||
|
}
|
||||||
|
} catch ( NoSuchFieldException | IllegalAccessException e ) {
|
||||||
|
throw new RuntimeException( e );
|
||||||
|
}
|
||||||
return cs;
|
return cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,27 +264,6 @@ public class TestComponentState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Test: {@link ComponentState} copies lifecycle actions and can execute them */
|
|
||||||
@Test
|
|
||||||
public void testInitialiseLCA( )
|
|
||||||
throws Throwable
|
|
||||||
{
|
|
||||||
final LCATest lca = new LCATest( );
|
|
||||||
final NewComponentInfo< LCATest > ci = new NewComponentInfo< LCATest >( lca );
|
|
||||||
for ( final LifecycleStage stage : LifecycleStage.values( ) ) {
|
|
||||||
ci.setLifecycleAction( stage , ( o ) -> {
|
|
||||||
o.stage = stage;
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
final ComponentState cs = new ComponentState( this.reg , ci );
|
|
||||||
|
|
||||||
for ( final LifecycleStage stage : LifecycleStage.values( ) ) {
|
|
||||||
cs.runLifecycleAction( stage );
|
|
||||||
Assert.assertSame( lca.stage , stage );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Test: {@link ComponentState#toString()} on anonymous components */
|
/** Test: {@link ComponentState#toString()} on anonymous components */
|
||||||
@Test
|
@Test
|
||||||
public void testToStringAnon( )
|
public void testToStringAnon( )
|
||||||
|
@ -327,8 +320,7 @@ public class TestComponentState
|
||||||
public void testStartFailedRegistry( )
|
public void testStartFailedRegistry( )
|
||||||
{
|
{
|
||||||
final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( new Object( ) );
|
final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( new Object( ) );
|
||||||
final ComponentState cs = new ComponentState( this.reg , ci );
|
final ComponentState cs = makeState( ci , reg , true , false );
|
||||||
cs.setInitialised( true );
|
|
||||||
this.reg.failed = true;
|
this.reg.failed = true;
|
||||||
cs.start( );
|
cs.start( );
|
||||||
}
|
}
|
||||||
|
@ -339,8 +331,7 @@ public class TestComponentState
|
||||||
public void testStartInactiveRegistry( )
|
public void testStartInactiveRegistry( )
|
||||||
{
|
{
|
||||||
final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( new Object( ) );
|
final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( new Object( ) );
|
||||||
final ComponentState cs = new ComponentState( this.reg , ci );
|
final ComponentState cs = makeState( ci , reg , true , false );
|
||||||
cs.setInitialised( true );
|
|
||||||
cs.start( );
|
cs.start( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,8 +341,7 @@ public class TestComponentState
|
||||||
public void testStartNoAction( )
|
public void testStartNoAction( )
|
||||||
{
|
{
|
||||||
final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( new Object( ) );
|
final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( new Object( ) );
|
||||||
final ComponentState cs = new ComponentState( this.reg , ci );
|
final ComponentState cs = makeState( ci , reg , true , false );
|
||||||
cs.setInitialised( true );
|
|
||||||
this.reg.active = true;
|
this.reg.active = true;
|
||||||
cs.start( );
|
cs.start( );
|
||||||
Assert.assertTrue( cs.isActive( ) );
|
Assert.assertTrue( cs.isActive( ) );
|
||||||
|
@ -367,8 +357,7 @@ public class TestComponentState
|
||||||
.setLifecycleAction( LifecycleStage.START , ( o ) -> {
|
.setLifecycleAction( LifecycleStage.START , ( o ) -> {
|
||||||
o.stage = LifecycleStage.START;
|
o.stage = LifecycleStage.START;
|
||||||
} );
|
} );
|
||||||
final ComponentState cs = new ComponentState( this.reg , ci );
|
final ComponentState cs = makeState( ci , reg , true , false );
|
||||||
cs.setInitialised( true );
|
|
||||||
this.reg.active = true;
|
this.reg.active = true;
|
||||||
cs.start( );
|
cs.start( );
|
||||||
Assert.assertSame( LifecycleStage.START , lcaTest.stage );
|
Assert.assertSame( LifecycleStage.START , lcaTest.stage );
|
||||||
|
@ -473,7 +462,7 @@ public class TestComponentState
|
||||||
final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( new Object( ) );
|
final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( new Object( ) );
|
||||||
final ComponentState cs = TestComponentState.makeState( ci , this.reg , true , true );
|
final ComponentState cs = TestComponentState.makeState( ci , this.reg , true , true );
|
||||||
this.reg.active = true;
|
this.reg.active = true;
|
||||||
Assert.assertNull( cs.stop( ) );
|
cs.stop( );
|
||||||
Assert.assertFalse( cs.isActive( ) );
|
Assert.assertFalse( cs.isActive( ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,25 +478,31 @@ public class TestComponentState
|
||||||
} );
|
} );
|
||||||
final ComponentState cs = TestComponentState.makeState( ci , this.reg , true , true );
|
final ComponentState cs = TestComponentState.makeState( ci , this.reg , true , true );
|
||||||
this.reg.active = true;
|
this.reg.active = true;
|
||||||
Assert.assertNull( cs.stop( ) );
|
cs.stop( );
|
||||||
Assert.assertFalse( cs.isActive( ) );
|
Assert.assertFalse( cs.isActive( ) );
|
||||||
Assert.assertSame( LifecycleStage.STOP , lcaTest.stage );
|
Assert.assertSame( LifecycleStage.STOP , lcaTest.stage );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Test: {@link ComponentState#stop()} returns an exception thrown by the configured stop action */
|
/** Test: {@link ComponentState#stop()} transmits an exception thrown by the configured stop action */
|
||||||
@Test
|
@Test
|
||||||
public void testStopActionFailure( )
|
public void testStopActionFailure( )
|
||||||
{
|
{
|
||||||
final Exception failure = new Exception( );
|
final ComponentShutdownException failure = new ComponentShutdownException( );
|
||||||
final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( new Object( ) ) //
|
final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( new Object( ) ) //
|
||||||
.setLifecycleAction( LifecycleStage.STOP , ( o ) -> {
|
.setLifecycleAction( LifecycleStage.STOP , ( o ) -> {
|
||||||
throw failure;
|
throw failure;
|
||||||
} );
|
} );
|
||||||
final ComponentState cs = TestComponentState.makeState( ci , this.reg , true , true );
|
final ComponentState cs = TestComponentState.makeState( ci , this.reg , true , true );
|
||||||
this.reg.active = true;
|
this.reg.active = true;
|
||||||
Assert.assertSame( failure , cs.stop( ) );
|
try {
|
||||||
Assert.assertTrue( cs.isActive( ) );
|
cs.stop( );
|
||||||
|
} catch ( ComponentShutdownException e ) {
|
||||||
|
Assert.assertSame( failure , e );
|
||||||
|
Assert.assertTrue( cs.isActive( ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Assert.fail( "expected ComponentShutdownException" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -523,7 +518,7 @@ public class TestComponentState
|
||||||
cs2.addDependency( cs1 );
|
cs2.addDependency( cs1 );
|
||||||
|
|
||||||
this.reg.active = true;
|
this.reg.active = true;
|
||||||
Assert.assertNull( cs1.stop( ) );
|
cs1.stop( );
|
||||||
Assert.assertFalse( cs2.isActive( ) );
|
Assert.assertFalse( cs2.isActive( ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,7 +560,7 @@ public class TestComponentState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Test: {@link ComponentState#restart()} throws a {@link ComponentRestartException} when stop fails */
|
/** Test: {@link ComponentState#restart()} throws a {@link ComponentShutdownException} when stop fails */
|
||||||
@Test
|
@Test
|
||||||
public void testRestartWhenStopFails( )
|
public void testRestartWhenStopFails( )
|
||||||
{
|
{
|
||||||
|
@ -578,20 +573,20 @@ public class TestComponentState
|
||||||
this.reg.active = true;
|
this.reg.active = true;
|
||||||
try {
|
try {
|
||||||
cs.restart( );
|
cs.restart( );
|
||||||
} catch ( final ComponentRestartException e ) {
|
} catch ( final ComponentShutdownException e ) {
|
||||||
Assert.assertSame( failure , e.getCause( ) );
|
Assert.assertSame( failure , e.getCause( ) );
|
||||||
Assert.assertTrue( cs.isActive( ) );
|
Assert.assertTrue( cs.isActive( ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Assert.fail( "no ComponentRestartException" );
|
Assert.fail( "no ComponentShutdownException" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Test: {@link ComponentState#restart()} throws a {@link ComponentRestartException} when start fails */
|
/** Test: {@link ComponentState#restart()} throws a {@link ComponentStartupException} when start fails */
|
||||||
@Test
|
@Test
|
||||||
public void testRestartWhenStartFails( )
|
public void testRestartWhenStartFails( )
|
||||||
{
|
{
|
||||||
final ComponentStartupException failure = new ComponentStartupException( );
|
final Exception failure = new Exception( );
|
||||||
final NewComponentInfo< RestartTest > ci = RestartTest.getDef( );
|
final NewComponentInfo< RestartTest > ci = RestartTest.getDef( );
|
||||||
ci.setLifecycleAction( LifecycleStage.START , ( o ) -> {
|
ci.setLifecycleAction( LifecycleStage.START , ( o ) -> {
|
||||||
throw failure;
|
throw failure;
|
||||||
|
@ -600,12 +595,12 @@ public class TestComponentState
|
||||||
this.reg.active = true;
|
this.reg.active = true;
|
||||||
try {
|
try {
|
||||||
cs.restart( );
|
cs.restart( );
|
||||||
} catch ( final ComponentRestartException e ) {
|
} catch ( final ComponentStartupException e ) {
|
||||||
Assert.assertSame( failure , e.getCause( ) );
|
Assert.assertSame( failure , e.getCause( ) );
|
||||||
Assert.assertFalse( cs.isActive( ) );
|
Assert.assertFalse( cs.isActive( ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Assert.fail( "no ComponentRestartException" );
|
Assert.fail( "no ComponentStartupException" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue