Components registry - Start, stop, restart

This commit is contained in:
Emmanuel BENOîT 2015-09-15 15:41:05 +02:00
parent d083be2676
commit 53128c5e77
5 changed files with 283 additions and 20 deletions

View file

@ -6,7 +6,6 @@ public class ComponentInitialisationException
{ {
private static final long serialVersionUID = 6150762006182320443L; private static final long serialVersionUID = 6150762006182320443L;
private ComponentInitialisationException chain;
public ComponentInitialisationException( ) public ComponentInitialisationException( )
@ -15,34 +14,21 @@ public class ComponentInitialisationException
} }
public ComponentInitialisationException( String message , Throwable cause ) public ComponentInitialisationException( final String message , final Throwable cause )
{ {
super( message , cause ); super( message , cause );
} }
public ComponentInitialisationException( String message ) public ComponentInitialisationException( final String message )
{ {
super( message ); super( message );
} }
public ComponentInitialisationException( Throwable cause ) public ComponentInitialisationException( final Throwable cause )
{ {
super( cause ); super( cause );
} }
ComponentInitialisationException( Throwable cause , ComponentInitialisationException initial )
{
super( "failed to revert incomplete initialisation" , cause );
this.chain = initial;
}
public ComponentInitialisationException getChain( )
{
return chain;
}
} }

View file

@ -40,7 +40,7 @@ public class ComponentRegistry
private boolean failed; private boolean failed;
private boolean initialised; private boolean initialised;
// private boolean active; private boolean active;
public ComponentRegistry( ) public ComponentRegistry( )
@ -63,6 +63,12 @@ public class ComponentRegistry
} }
public boolean isActive( )
{
return active;
}
public ComponentState getState( String name ) public ComponentState getState( String name )
{ {
return this.byName.get( name ); return this.byName.get( name );
@ -157,7 +163,8 @@ public class ComponentRegistry
public ComponentRegistry register( Collection< NewComponentInfo< ? > > components ) public ComponentRegistry register( Collection< NewComponentInfo< ? > > components )
throws ComponentCreationException , DuplicateComponentException , RecursiveDependenciesException , throws ComponentCreationException , DuplicateComponentException , RecursiveDependenciesException ,
DependencyInjectionException , AmbiguousComponentException , ComponentInitialisationException DependencyInjectionException , AmbiguousComponentException , ComponentInitialisationException ,
ComponentStartupException
{ {
if ( this.failed ) { if ( this.failed ) {
throw new IllegalStateException( "register() called on failed registry" ); throw new IllegalStateException( "register() called on failed registry" );
@ -206,7 +213,15 @@ public class ComponentRegistry
} }
} }
// TODO: activate autostart components // Activate autostart components
if ( this.active ) {
for ( int i = 0 ; i < nOld + nAdd ; i++ ) {
ComponentState cmp = this.components.get( i );
if ( cmp.hasAutostart( ) ) {
startComponentWithFailure( cmp );
}
}
}
return this; return this;
} }
@ -232,12 +247,14 @@ public class ComponentRegistry
public boolean destroy( ) public boolean destroy( )
throws IllegalStateException
{ {
return this.destroy( null ); return this.destroy( null );
} }
public boolean destroy( Collection< Throwable > errors ) 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" );
@ -245,6 +262,9 @@ public class ComponentRegistry
if ( !this.initialised ) { if ( !this.initialised ) {
return true; return true;
} }
if ( this.active && !this.stop( errors ) ) {
return false;
}
for ( int i = this.components.size( ) - 1 ; i >= 0 ; i-- ) { for ( int i = this.components.size( ) - 1 ; i >= 0 ; i-- ) {
try { try {
@ -264,6 +284,68 @@ public class ComponentRegistry
} }
public void start( )
throws IllegalStateException , ComponentStartupException
{
if ( this.failed ) {
throw new IllegalStateException( "start() called on failed registry" );
}
if ( !this.initialised ) {
throw new IllegalStateException( "start() called on uninitialised registry" );
}
if ( this.active ) {
return;
}
int nComponents = this.components.size( );
for ( int i = 0 ; i < nComponents ; i++ ) {
ComponentState cmp = this.components.get( i );
if ( cmp.hasAutostart( ) && !cmp.isActive( ) ) {
startComponentWithFailure( cmp );
}
}
this.initialised = true;
}
public boolean stop( )
throws IllegalStateException
{
return this.stop( null );
}
public boolean stop( Collection< Throwable > errors )
throws IllegalStateException
{
if ( this.failed ) {
throw new IllegalStateException( "destroy() called on failed registry" );
}
if ( !this.active ) {
return true;
}
for ( int i = this.components.size( ) - 1 ; i >= 0 ; i-- ) {
try {
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;
return !this.failed;
}
private static int resolveNewDependencies( ArrayList< TempBuildRec > adding , private static int resolveNewDependencies( ArrayList< TempBuildRec > adding ,
ArrayList< ComponentState > nComponents , HashMap< String , ComponentState > byName , ArrayList< ComponentState > nComponents , HashMap< String , ComponentState > byName ,
HashMap< Class< ? > , ArrayList< ComponentState > > byType ) HashMap< Class< ? > , ArrayList< ComponentState > > byType )
@ -391,4 +473,30 @@ public class ComponentRegistry
throw e; throw e;
} }
} }
private void startComponentWithFailure( ComponentState cmp )
throws ComponentStartupException
{
try {
this.startComponent( cmp );
} catch ( ComponentStartupException e ) {
this.failed = true;
throw e;
}
}
private void startComponent( ComponentState cmp )
throws ComponentStartupException
{
try {
cmp.runLifecycleAction( LifecycleStage.START );
} catch ( ComponentStartupException e ) {
throw e;
} catch ( Throwable t ) {
throw new ComponentStartupException( t );
}
cmp.setActive( true );
}
} }

View file

@ -0,0 +1,34 @@
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 );
}
}

View file

@ -0,0 +1,34 @@
package info.ebenoit.ebul.cmp;
public class ComponentStartupException
extends ComponentException
{
private static final long serialVersionUID = -8010582342593242803L;
public ComponentStartupException( )
{
super( );
}
public ComponentStartupException( final String message , final Throwable cause )
{
super( message , cause );
}
public ComponentStartupException( final String message )
{
super( message );
}
public ComponentStartupException( final Throwable cause )
{
super( cause );
}
}

View file

@ -17,6 +17,7 @@ public final class ComponentState
private final boolean autostart; private final boolean autostart;
private boolean initialised; private boolean initialised;
private boolean active; private boolean active;
private boolean wasActive;
private final HashSet< ComponentState > dependencies = new HashSet< >( ); private final HashSet< ComponentState > dependencies = new HashSet< >( );
private final HashSet< ComponentState > reverseDependencies = new HashSet< >( ); private final HashSet< ComponentState > reverseDependencies = new HashSet< >( );
@ -104,6 +105,106 @@ public final class ComponentState
} }
public void start( )
throws ComponentStartupException , IllegalStateException
{
if ( !this.initialised ) {
throw new IllegalStateException( "attempting to start uninitialised component" );
}
if ( this.registry.hasFailed( ) ) {
throw new IllegalStateException( "registry has failed" );
}
if ( !this.registry.isActive( ) ) {
throw new IllegalStateException( "registry is inactive" );
}
startNoChecks( );
}
public Throwable stop( )
throws IllegalStateException
{
if ( this.registry.hasFailed( ) ) {
throw new IllegalStateException( "registry has failed" );
}
this.wasActive = this.active;
if ( this.active ) {
return null;
}
for ( ComponentState rdepState : this.reverseDependencies ) {
Throwable t = rdepState.stop( );
if ( t != null ) {
return t;
}
}
try {
this.runLifecycleAction( LifecycleStage.START );
} catch ( Throwable t ) {
return t;
}
this.active = false;
return null;
}
public void restart( )
throws IllegalStateException , ComponentRestartException
{
if ( this.registry.hasFailed( ) ) {
throw new IllegalStateException( "registry has failed" );
}
Throwable t = this.stop( );
if ( t != null ) {
throw new ComponentRestartException( "failed to stop" , t );
}
this.startIfPreviouslyActive( );
}
private void startNoChecks( )
throws ComponentStartupException
{
if ( this.active ) {
return;
}
for ( ComponentState depState : this.dependencies ) {
depState.startNoChecks( );
}
try {
this.runLifecycleAction( LifecycleStage.START );
} catch ( ComponentStartupException e ) {
throw e;
} catch ( Throwable t ) {
throw new ComponentStartupException( t );
}
this.active = true;
}
private void startIfPreviouslyActive( )
throws ComponentRestartException
{
if ( this.wasActive ) {
try {
this.startNoChecks( );
} catch ( ComponentStartupException e ) {
throw new ComponentRestartException( "failed to restart " + this , e );
}
for ( ComponentState rDepState : this.reverseDependencies ) {
rDepState.startIfPreviouslyActive( );
}
}
}
void setInitialised( boolean initialised ) void setInitialised( boolean initialised )
{ {
this.initialised = initialised; this.initialised = initialised;