cz.cuni.amis.pogamut.base.component.controller
Class ComponentController<COMPONENT extends IComponent>

java.lang.Object
  extended by cz.cuni.amis.pogamut.base.component.controller.AbstractComponentControllerBase<COMPONENT>
      extended by cz.cuni.amis.pogamut.base.component.controller.ComponentController<COMPONENT>
All Implemented Interfaces:
IComponentController<COMPONENT>, IComponentControllerBase<COMPONENT>, IComponent

public class ComponentController<COMPONENT extends IComponent>
extends AbstractComponentControllerBase<COMPONENT>
implements IComponentController<COMPONENT>

Provides simple way for components to start/stop automatically based on the status of objects they depends on (e.g. IWorldView may start only if underlying IMediator has been started).

Dependents may be identified by IToken or IComponent.

Component controller ease the burden with starting/stopping the component in the right time and the broadcasting of appropriate events and tracking its ComponentState.

It allows you to specify starting-dependencies of your IComponentControlHelper allowing you to define the moment when the component should start/stop. Moreover - it automatically watching the IComponentBus for IFatalErrorEvent killing your component when a fatal event is caught (but it will call kill only iff fatal error is produced by different component then the controlled one).

Additionally the controller is broadcasting starting/stopping events automatically.

If you wish to manually stop the component for whatever reason - call manualStop() method, it will broadcast IStoppingEvent and IStopeedEvent automatically.

The controlled component goes through various states during its life-cycle.

Initial state of the component ComponentState.RESETED.

Usual life-cycle of the component is:

INSTANTIATED (or RESETED or STOPPED) -> STARTING -> RUNNING -> [PAUSING -> PAUSED -> RESUMING -> RUNNING] -> STOPPING -> STOPPED

Note that the component might be started again from the STOPPED state or may be stopped from PAUSED state.

Also the component might be started to paused state, the lifecycle is then is:

INSTANTIATED (or RESETED or STOPPED) -> STARTING_PAUSED -> PAUSED -> RESUMING -> RUNNING -> ....

If IFatalErrorEvent is got or raised by the component through fatalError(java.lang.String), the state is switched to -> KILLING -> KILLED and may continue only with -> RESETING -> RESETED.

Various corresponding methods from IComponentControlHelper are during state transitions.

INSTANTIATED (or RESETED or STOPPED) -> preStart() -> STARTING -> start() -> RUNNING -> prePause() -> PAUSING -> pause() -> PAUSED -> preResume() -> RESUMING -> resume() -> RUNNING -> preStop() -> STOPPING -> stop() -> STOPPED

(similarly for start-paused) INSTANTIATED (or RESETED or STOPPED) -> preStartPaused() -> STARTING_PAUSED -> startPaused() -> PAUSED -> ...

If IFatalErrorEvent is got (or raised by the controlled component), the state is switched (and methods are called) ... -> KILLING -> kill() (not called in case of fatalError() method invocation) -> KILLED and then it may continue only with -> RESETING -> reset() -> RESETED.

Furthermore corresponding IComponentEvents are broadcast to the underlying IComponentBus. Thus the complete life/event/method-cycle looks like this:

INSTANTIATED (or RESETED) -> STARTING -> IStartingEvent -> start() -> RUNNING -> IStartedEvent -> prePause() -> PAUSING -> IPausingEvent -> pause() -> PAUSED -> IPausedEvent -> RESUMING -> IResumingEvent -> resume() -> RUNNING -> IResumedEvent -> preStop() -> STOPPING -> IStoppingEvent -> stop() -> STOPPED -> IStoppedEvent

Last pieces of information:

1) INSTANTIATED (or RESETED) -> STARTING + STOPPED -> STARTING transition is triggered only if dependencies are starting / has started. 2) RUNNING -> PAUSING transition is triggered whenever some dependency broadcasts IPausingEvent or IPausedEvent.

3) PAUSED -> RESUMING transition is triggered when all dependencies are resuming / has resumed.

4) RUNNING | PAUSED -> STOPPING transition is triggered whenever some dependency broadcasts or IStoppedEvent or when the stop is manually required by calling manualStop(java.lang.String) method.

5) any state -> KILLING transition is triggered whenever some component broadcasts IFatalErrorEvent or the component reports that fatal error has happened through one of ComponentController.fatalError() method.

6) kill() method is called only if OTHER component broadcasts IFatalErrorEvent - the kill() method is not called when the fatal error is raised manually by the component via one of fatalError() methods.

7) KILLED -> RESETING transition is triggered by IResetEvent

8) there is a specific transition (STARTING | RUNNING | PAUSING | PAUSED | RESUMING ) -> STOPPING transition that may be triggered by IStoppingEvent or IStoppedEvent or by manually calling manualStop(String) method from within the component. 9) not mentioned transitions (in the whole javadoc) are non-existing (e.g. there is no such transition such as STARTING -> PAUSED, etc.). Note that some transition can't even happen because IComponenBus is processing one event at time.

The comopnent life-cycle looks complex but it is driven by simple idea that we have to control the process of starting/pausing/resuming/stopping of IComponents. Hopefully it works like you would expect it to work.

The controller is also IComponent but that is just a technical detail - whenever a fatal error happens in the logic of starting/stopping/pausing/resuming/etc. of components the controller raises the fatal error under own id.


Nested Class Summary
 
Nested classes/interfaces inherited from class cz.cuni.amis.pogamut.base.component.controller.AbstractComponentControllerBase
AbstractComponentControllerBase.AwaitState
 
Field Summary
 
Fields inherited from class cz.cuni.amis.pogamut.base.component.controller.AbstractComponentControllerBase
broadcastingEvents, component, componentState, control, controllerId, log
 
Constructor Summary
ComponentController(COMPONENT component, IComponentControlHelper componentControlHelper, IComponentBus bus, java.util.logging.Logger log, ComponentDependencies dependencies)
          If you use only IComponentBus (not ILifecycleBus, you must create this ComponentController before any of 'dependencies' is started as there is no way how to retrieve state of component from 'dependencies' so we will assume that all are in state ComponentState.INSTANTIATED.
ComponentController(COMPONENT component, IComponentControlHelper componentControlHelper, IComponentBus bus, java.util.logging.Logger log, ComponentDependencyType dependencyType, java.lang.Object... dependencies)
          If you use only IComponentBus (not ILifecycleBus, you must create this ComponentController before any of 'dependencies' is started as there is no way how to retrieve state of component from 'dependencies' so we will assume that all are in state ComponentState.INSTANTIATED.
ComponentController(COMPONENT component, IComponentControlHelper componentControlHelper, ILifecycleBus bus, java.util.logging.Logger log, ComponentDependencies dependencies)
          If you're using ILifecycleBus (not only IComponentBus, you may create this ComponentController even after some 'dependencies' has started as ILifecycleBus allows us to retrieve current state of dependencies, so we're able to start the component during the construction if dependencies are already met.
ComponentController(COMPONENT component, IComponentControlHelper componentControlHelper, ILifecycleBus bus, java.util.logging.Logger log, ComponentDependencyType dependencyType, java.lang.Object... dependencies)
          If you're using ILifecycleBus (not only IComponentBus, you may create this ComponentController even after some 'dependencies' has started as ILifecycleBus allows us to retrieve current state of dependencies, so we're able to start the component during the construction if dependencies are already met.
 
Method Summary
 void fatalError(java.lang.String message)
          Broadcasts fatal error with controlled component as source.
 void fatalError(java.lang.String message, java.lang.Throwable e)
          Broadcasts fatal error with controlled component as source.
 IFatalErrorEvent getFatalError()
          Returns last fatal error event that has triggered the system failure.
 boolean isDependent(IComponent component)
          Whether the controlled component is dependent on 'component'.
 boolean isDependent(IToken token)
          Whether the controlled component is dependent on the component identified by 'componentId'.
 void manualKill(java.lang.String reason)
          Provides the way to kill the component (constructor of this controller).
 void manualPause(java.lang.String reason)
          Provides the way to pause the component (constructor of this controller).
 void manualResume(java.lang.String reason)
          Provides the way to pause the component (constructor of this controller).
 void manualStart(java.lang.String reason)
          Provides the way to manually start the component.
 void manualStartPaused(java.lang.String reason)
          Provides the way to manually start the component into paused state.
 void manualStop(java.lang.String reason)
          Provides the way to stop the component (constructor of this controller).
 void setBroadcastingEvents(boolean broadcastingEvents)
          Enables (== true) / Disables (== false) sending events about the state of the component, i.e., whether it should automatically send starting/stopping events or not.
 
Methods inherited from class cz.cuni.amis.pogamut.base.component.controller.AbstractComponentControllerBase
awaitState, awaitState, getComponent, getComponentControl, getComponentId, getLog, getState, id, inState, isBroadcastingEvents, isPaused, isRunning, notInState, setState, toString
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface cz.cuni.amis.pogamut.base.component.controller.IComponentControllerBase
awaitState, awaitState, getComponent, getComponentControl, getState, inState, isBroadcastingEvents, isPaused, isRunning, notInState
 
Methods inherited from interface cz.cuni.amis.pogamut.base.component.IComponent
getComponentId
 

Constructor Detail

ComponentController

public ComponentController(COMPONENT component,
                           IComponentControlHelper componentControlHelper,
                           ILifecycleBus bus,
                           java.util.logging.Logger log,
                           ComponentDependencyType dependencyType,
                           java.lang.Object... dependencies)
If you're using ILifecycleBus (not only IComponentBus, you may create this ComponentController even after some 'dependencies' has started as ILifecycleBus allows us to retrieve current state of dependencies, so we're able to start the component during the construction if dependencies are already met.

Parameters:
component - controlled component
componentControlHelper - object controlling the 'component' (contains lifecycle methods which controls the component)
bus - bus of the component
log - logger for the class
dependencyType - type of the dependency (YOU MUST KNOW THE SEMANTICS OF THIS ENUM, see ComponentDependencyType)
dependencies - IToken or Class of components the 'component' depends on

ComponentController

public ComponentController(COMPONENT component,
                           IComponentControlHelper componentControlHelper,
                           ILifecycleBus bus,
                           java.util.logging.Logger log,
                           ComponentDependencies dependencies)
If you're using ILifecycleBus (not only IComponentBus, you may create this ComponentController even after some 'dependencies' has started as ILifecycleBus allows us to retrieve current state of dependencies, so we're able to start the component during the construction if dependencies are already met.

Parameters:
component - controlled component
componentControlHelper - object controlling the 'component' (contains lifecycle methods which controls the component)
bus - bus of the component
log - logger for the class
dependencies - dependencies of the component

ComponentController

public ComponentController(COMPONENT component,
                           IComponentControlHelper componentControlHelper,
                           IComponentBus bus,
                           java.util.logging.Logger log,
                           ComponentDependencyType dependencyType,
                           java.lang.Object... dependencies)
If you use only IComponentBus (not ILifecycleBus, you must create this ComponentController before any of 'dependencies' is started as there is no way how to retrieve state of component from 'dependencies' so we will assume that all are in state ComponentState.INSTANTIATED.

Parameters:
component - controlled component
componentControlHelper - object controlling the 'component' (contains lifecycle methods which controls the component)
bus - bus of the component
log - logger to be used by this class
dependencyType - type of the dependency (YOU MUST KNOW THE SEMANTICS OF THIS ENUM, see ComponentDependencyType)
dependencies - IToken or Class of components the 'component' depends on

ComponentController

public ComponentController(COMPONENT component,
                           IComponentControlHelper componentControlHelper,
                           IComponentBus bus,
                           java.util.logging.Logger log,
                           ComponentDependencies dependencies)
If you use only IComponentBus (not ILifecycleBus, you must create this ComponentController before any of 'dependencies' is started as there is no way how to retrieve state of component from 'dependencies' so we will assume that all are in state ComponentState.INSTANTIATED.

Parameters:
component - controlled component
componentControlHelper - object controlling the 'component' (contains lifecycle methods which controls the component)
bus - bus of the component
log - logger to be used by this class
dependencies - dependencies of the component
Method Detail

setBroadcastingEvents

public void setBroadcastingEvents(boolean broadcastingEvents)
Description copied from interface: IComponentControllerBase
Enables (== true) / Disables (== false) sending events about the state of the component, i.e., whether it should automatically send starting/stopping events or not.

Exception: IComponentControllerBase.fatalError(String) and IComponentControllerBase.fatalError(String, Throwable) must always send fatal error!

Specified by:
setBroadcastingEvents in interface IComponentControllerBase<COMPONENT extends IComponent>
Overrides:
setBroadcastingEvents in class AbstractComponentControllerBase<COMPONENT extends IComponent>
Parameters:
broadcastingEvents - Enables (== true) / Disables (== false)

getFatalError

public IFatalErrorEvent getFatalError()
Description copied from interface: IComponentControllerBase
Returns last fatal error event that has triggered the system failure.

Specified by:
getFatalError in interface IComponentControllerBase<COMPONENT extends IComponent>

manualStart

public void manualStart(java.lang.String reason)
Description copied from interface: IComponentControllerBase
Provides the way to manually start the component.

Specified by:
manualStart in interface IComponentControllerBase<COMPONENT extends IComponent>

manualStartPaused

public void manualStartPaused(java.lang.String reason)
Description copied from interface: IComponentControllerBase
Provides the way to manually start the component into paused state.

Specified by:
manualStartPaused in interface IComponentControllerBase<COMPONENT extends IComponent>

manualStop

public void manualStop(java.lang.String reason)
Description copied from interface: IComponentControllerBase
Provides the way to stop the component (constructor of this controller).

Note that you should not use IComponentControlHelper.stop() alone to stop your component as it won't produce IStoppingEvent and IStoppedEvent.

If you require your component to stop prematurely - call this method.

Specified by:
manualStop in interface IComponentControllerBase<COMPONENT extends IComponent>
Parameters:
reason - why the component is stopping

manualKill

public void manualKill(java.lang.String reason)
Description copied from interface: IComponentControllerBase
Provides the way to kill the component (constructor of this controller).

Note that you should not use IComponentControlHelper.kill() alone to stop your component as it won't produce IFatalErrorEvent.

If you require your component to stop prematurely - call this method.

Specified by:
manualKill in interface IComponentControllerBase<COMPONENT extends IComponent>
Parameters:
reason - why the component is stopping

manualPause

public void manualPause(java.lang.String reason)
Description copied from interface: IComponentControllerBase
Provides the way to pause the component (constructor of this controller).

Note that you should not use IComponentControlHelper.pause() alone to stop your component as it won't produce IPausingEvent and IPausedEvent.

Specified by:
manualPause in interface IComponentControllerBase<COMPONENT extends IComponent>
Parameters:
reason - why the component is pausing

manualResume

public void manualResume(java.lang.String reason)
Description copied from interface: IComponentControllerBase
Provides the way to pause the component (constructor of this controller).

Note that you should not use IComponentControlHelper.pause() alone to stop your component as it won't produce IPausingEvent and IPausedEvent.

Specified by:
manualResume in interface IComponentControllerBase<COMPONENT extends IComponent>
Parameters:
reason - why the component is pausing

fatalError

public void fatalError(java.lang.String message)
Description copied from interface: IComponentControllerBase
Broadcasts fatal error with controlled component as source.

Sets state to KILLING, broadcasts IFatalErrorEvent and then sets the state to KILLED.

WARNING: Note that the ComponentController assumes that you will kill your component yourself before or after you call this method. Therefore the components kill() method won't be called. That's because whenever fatal error occurs, the component is in undefined state and you have to decide what to do based on that fatal error.

Specified by:
fatalError in interface IComponentControllerBase<COMPONENT extends IComponent>

fatalError

public void fatalError(java.lang.String message,
                       java.lang.Throwable e)
Description copied from interface: IComponentControllerBase
Broadcasts fatal error with controlled component as source.

Sets state to KILLING, broadcasts IFatalErrorEvent and then sets the state to KILLED.

WARNING: Note that the ComponentController assumes that you will kill your component yourself before or after you call this method. Therefore the components kill() method won't be called. That's because whenever fatal error occurs, the component is in undefined state and you have to decide what to do based on that fatal error.

Specified by:
fatalError in interface IComponentControllerBase<COMPONENT extends IComponent>

isDependent

public boolean isDependent(IToken token)
Description copied from interface: IComponentController
Whether the controlled component is dependent on the component identified by 'componentId'.

Specified by:
isDependent in interface IComponentController<COMPONENT extends IComponent>
Returns:

isDependent

public boolean isDependent(IComponent component)
Description copied from interface: IComponentController
Whether the controlled component is dependent on 'component'.

Specified by:
isDependent in interface IComponentController<COMPONENT extends IComponent>
Returns: