Components registry - Initialisation and destruction

This commit is contained in:
Emmanuel BENOîT 2015-09-15 15:12:44 +02:00
parent d554f02ede
commit d083be2676
3 changed files with 192 additions and 7 deletions

View file

@ -0,0 +1,48 @@
package info.ebenoit.ebul.cmp;
public class ComponentInitialisationException
extends ComponentException
{
private static final long serialVersionUID = 6150762006182320443L;
private ComponentInitialisationException chain;
public ComponentInitialisationException( )
{
super( );
}
public ComponentInitialisationException( String message , Throwable cause )
{
super( message , cause );
}
public ComponentInitialisationException( String message )
{
super( message );
}
public ComponentInitialisationException( Throwable 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

@ -17,7 +17,7 @@ import info.ebenoit.ebul.reflection.Classes;
public class ComponentRegistry
{
private static final class TempBuildRec
private final class TempBuildRec
{
private final NewComponentInfo< ? > info;
private final ComponentState state;
@ -28,7 +28,7 @@ public class ComponentRegistry
private TempBuildRec( NewComponentInfo< ? > info )
{
this.info = info;
this.state = new ComponentState( info );
this.state = new ComponentState( ComponentRegistry.this , info );
this.deps = new HashMap< >( );
}
@ -38,10 +38,11 @@ public class ComponentRegistry
private HashMap< String , ComponentState > byName;
private HashMap< Class< ? > , ArrayList< ComponentState > > byType;
// private boolean initialised;
private boolean failed;
private boolean initialised;
// private boolean active;
public ComponentRegistry( )
{
this.components = new ArrayList< >( );
@ -50,6 +51,18 @@ public class ComponentRegistry
}
public boolean hasFailed( )
{
return failed;
}
public boolean isInitialised( )
{
return initialised;
}
public ComponentState getState( String name )
{
return this.byName.get( name );
@ -144,8 +157,12 @@ public class ComponentRegistry
public ComponentRegistry register( Collection< NewComponentInfo< ? > > components )
throws ComponentCreationException , DuplicateComponentException , RecursiveDependenciesException ,
DependencyInjectionException , AmbiguousComponentException
DependencyInjectionException , AmbiguousComponentException , ComponentInitialisationException
{
if ( this.failed ) {
throw new IllegalStateException( "register() called on failed registry" );
}
// Create "raw" state records for the new components
int nAdd = components.size( );
int nLeft = nAdd;
@ -177,16 +194,76 @@ public class ComponentRegistry
injectDependencies( adding );
// Replace registry contents
int nOld = this.components.size( );
this.components = nComponents;
this.byName = byName;
this.byType = byType;
// TODO: handle initialisation and activation
// Initialise all new components if the registry has been initialised
if ( this.initialised ) {
for ( int i = nOld ; i < nOld + nAdd ; i++ ) {
initComponent( i );
}
}
// TODO: activate autostart components
return this;
}
public void initialise( )
throws ComponentInitialisationException
{
if ( this.failed ) {
throw new IllegalStateException( "initialise() called on failed registry" );
}
if ( this.initialised ) {
return;
}
int nComponents = this.components.size( );
for ( int i = 0 ; i < nComponents ; i++ ) {
initComponent( i );
}
this.initialised = true;
}
public boolean destroy( )
{
return this.destroy( null );
}
public boolean destroy( Collection< Throwable > errors )
{
if ( this.failed ) {
throw new IllegalStateException( "destroy() called on failed registry" );
}
if ( !this.initialised ) {
return true;
}
for ( int i = this.components.size( ) - 1 ; i >= 0 ; i-- ) {
try {
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;
return !this.failed;
}
private static int resolveNewDependencies( ArrayList< TempBuildRec > adding ,
ArrayList< ComponentState > nComponents , HashMap< String , ComponentState > byName ,
HashMap< Class< ? > , ArrayList< ComponentState > > byType )
@ -294,4 +371,24 @@ public class ComponentRegistry
}
}
}
private void initComponent( int i )
throws ComponentInitialisationException
{
try {
ComponentState cmp = this.components.get( i );
try {
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;
throw e;
}
}
}

View file

@ -4,11 +4,13 @@ package info.ebenoit.ebul.cmp;
import java.util.HashSet;
import info.ebenoit.ebul.func.FunctionException;
import info.ebenoit.ebul.func.ThrowingConsumer;
public final class ComponentState
{
private final ComponentRegistry registry;
private final Object component;
private final String name;
@ -19,10 +21,15 @@ public final class ComponentState
private final HashSet< ComponentState > dependencies = new HashSet< >( );
private final HashSet< ComponentState > reverseDependencies = new HashSet< >( );
@SuppressWarnings( "rawtypes" )
private final ThrowingConsumer[] lcActions;
ComponentState( final NewComponentInfo< ? > ci )
ComponentState( ComponentRegistry registry , final NewComponentInfo< ? > ci )
throws ComponentCreationException
{
this.registry = registry;
Object component = ci.getComponent( );
if ( component == null ) {
try {
@ -45,6 +52,11 @@ public final class ComponentState
this.name = name;
this.autostart = ci.getAutostart( );
this.lcActions = new ThrowingConsumer[ 4 ];
for ( LifecycleStage stage : LifecycleStage.values( ) ) {
this.lcActions[ stage.ordinal( ) ] = ci.getLifecycleAction( stage );
}
}
@ -92,10 +104,38 @@ public final class ComponentState
}
void setInitialised( boolean initialised )
{
this.initialised = initialised;
}
void setActive( boolean active )
{
this.active = active;
}
void addDependency( ComponentState dep )
{
this.dependencies.add( dep );
dep.reverseDependencies.add( this );
}
void runLifecycleAction( LifecycleStage stage )
throws Throwable
{
@SuppressWarnings( "unchecked" )
ThrowingConsumer< Object > tc = this.lcActions[ stage.ordinal( ) ];
if ( tc != null ) {
try {
tc.accept( this.component );
} catch ( FunctionException e ) {
throw e.getCause( );
}
}
}
}