Components registry - Initialisation and destruction
This commit is contained in:
parent
d554f02ede
commit
d083be2676
3 changed files with 192 additions and 7 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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( );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue