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
|
public class ComponentRegistry
|
||||||
{
|
{
|
||||||
private static final class TempBuildRec
|
private final class TempBuildRec
|
||||||
{
|
{
|
||||||
private final NewComponentInfo< ? > info;
|
private final NewComponentInfo< ? > info;
|
||||||
private final ComponentState state;
|
private final ComponentState state;
|
||||||
|
@ -28,7 +28,7 @@ public class ComponentRegistry
|
||||||
private TempBuildRec( NewComponentInfo< ? > info )
|
private TempBuildRec( NewComponentInfo< ? > info )
|
||||||
{
|
{
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this.state = new ComponentState( info );
|
this.state = new ComponentState( ComponentRegistry.this , info );
|
||||||
this.deps = new HashMap< >( );
|
this.deps = new HashMap< >( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +38,11 @@ public class ComponentRegistry
|
||||||
private HashMap< String , ComponentState > byName;
|
private HashMap< String , ComponentState > byName;
|
||||||
private HashMap< Class< ? > , ArrayList< ComponentState > > byType;
|
private HashMap< Class< ? > , ArrayList< ComponentState > > byType;
|
||||||
|
|
||||||
|
private boolean failed;
|
||||||
// private boolean initialised;
|
private boolean initialised;
|
||||||
// private boolean active;
|
// private boolean active;
|
||||||
|
|
||||||
|
|
||||||
public ComponentRegistry( )
|
public ComponentRegistry( )
|
||||||
{
|
{
|
||||||
this.components = new ArrayList< >( );
|
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 )
|
public ComponentState getState( String name )
|
||||||
{
|
{
|
||||||
return this.byName.get( name );
|
return this.byName.get( name );
|
||||||
|
@ -144,8 +157,12 @@ 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
|
DependencyInjectionException , AmbiguousComponentException , ComponentInitialisationException
|
||||||
{
|
{
|
||||||
|
if ( this.failed ) {
|
||||||
|
throw new IllegalStateException( "register() called on failed registry" );
|
||||||
|
}
|
||||||
|
|
||||||
// Create "raw" state records for the new components
|
// Create "raw" state records for the new components
|
||||||
int nAdd = components.size( );
|
int nAdd = components.size( );
|
||||||
int nLeft = nAdd;
|
int nLeft = nAdd;
|
||||||
|
@ -177,16 +194,76 @@ public class ComponentRegistry
|
||||||
injectDependencies( adding );
|
injectDependencies( adding );
|
||||||
|
|
||||||
// Replace registry contents
|
// Replace registry contents
|
||||||
|
int nOld = this.components.size( );
|
||||||
this.components = nComponents;
|
this.components = nComponents;
|
||||||
this.byName = byName;
|
this.byName = byName;
|
||||||
this.byType = byType;
|
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;
|
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 ,
|
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 )
|
||||||
|
@ -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 java.util.HashSet;
|
||||||
|
|
||||||
import info.ebenoit.ebul.func.FunctionException;
|
import info.ebenoit.ebul.func.FunctionException;
|
||||||
|
import info.ebenoit.ebul.func.ThrowingConsumer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public final class ComponentState
|
public final class ComponentState
|
||||||
{
|
{
|
||||||
|
private final ComponentRegistry registry;
|
||||||
private final Object component;
|
private final Object component;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
@ -19,10 +21,15 @@ public final class ComponentState
|
||||||
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< >( );
|
||||||
|
|
||||||
|
@SuppressWarnings( "rawtypes" )
|
||||||
|
private final ThrowingConsumer[] lcActions;
|
||||||
|
|
||||||
ComponentState( final NewComponentInfo< ? > ci )
|
|
||||||
|
ComponentState( ComponentRegistry registry , final NewComponentInfo< ? > ci )
|
||||||
throws ComponentCreationException
|
throws ComponentCreationException
|
||||||
{
|
{
|
||||||
|
this.registry = registry;
|
||||||
|
|
||||||
Object component = ci.getComponent( );
|
Object component = ci.getComponent( );
|
||||||
if ( component == null ) {
|
if ( component == null ) {
|
||||||
try {
|
try {
|
||||||
|
@ -45,6 +52,11 @@ public final class ComponentState
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
||||||
this.autostart = ci.getAutostart( );
|
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 )
|
void addDependency( ComponentState dep )
|
||||||
{
|
{
|
||||||
this.dependencies.add( dep );
|
this.dependencies.add( dep );
|
||||||
dep.reverseDependencies.add( this );
|
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