public abstract class AbstractAgent extends Object implements IAgent
Agent has fully implemented lifecycle methods such as start()
, startPaused()
or stop()
. It also listens for IFatalErrorEvent
on its bus in order to terminate itself
in case of any errors. Also, if all components of the agent stops themselves, the agent is stopped as well.
If you do not like this behavior, email me to jakub.gemrot@gmail.com and I will make this optional.
Note that the Pogamut agent is designed to be a multicomponent beast. And by component we're meaning objects
that implements IComponent
registers itself into getEventBus()
owned by the agent
and adhering to the lifecycle provided either by ComponentController
or
ILifecycleBus#addLifecycleManagement(IToken, cz.cuni.amis.pogamut.base.component.controller.IComponentControlHelper, cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies)
.
These components (if correctly configured, which all native components are) starts together with the call of start()
or startPaused()
, as well as stopping themselves in the case of stop()
.
This model seems to defy the OOP, in fact it is its very incarnation applying principles or "separation of concerns", "modular design", whatever you would like to call it. Many native components are designed the way they interact with each other only via interfaces, they do not depend on each other directly thus greatly enabling anybody to hack inside any internal component of any Pogamut agent.
JMX
We're purposely using neither inheritance here nor decorator (or such wrappers) because we need JMX to be usable by every descendant of the class (so we don't want to have another JMX class branch, nor wrapper that denies the inheritance by its nature).
To keep the JMX-specific methods at minimum in the agent class we're grouping them into the private inner class object JMXComponents that can be accessed via getJMX() method. This object maintain also a list of IJMXEnabled components that should be enabled when the whole JMX feature is being enabled.
Usage:
To start JMX on the agent: getJMX().enableJMX(mBeanServer, domain)
To add another JMX component to the agent: getJMX().addComponent(component)
Modifier and Type | Field and Description |
---|---|
protected AgentEvents |
events
Gateway for sending events into the event bus.
|
static String |
INTROSPECTION_ROOT_NAME
Name of the root introspection folder.
|
protected LogCategory |
log
Agent's log category, goes under category name
LOG_CATEGORY_NAME . |
static String |
LOG_CATEGORY_NAME
Log category name used for
log . |
Constructor and Description |
---|
AbstractAgent(IAgentId agentId,
IComponentBus eventBus,
IAgentLogger logger)
Introspection folder with properties and other subfolders obtained from
this agent.
|
Modifier and Type | Method and Description |
---|---|
protected void |
addDependency(Class componentClass) |
protected void |
addDependency(IComponent component) |
protected void |
addDependency(cz.cuni.amis.utils.token.IToken componentId) |
protected void |
addJMXComponents()
Called when AgentJMX (field jmx) is instantiated to populate it with
agent's JMX enabled components.
|
IAgentState |
awaitState(Class awaitAgentState)
This method is designed to wait for the agent to reach state 'awaitAgentState' (usually used with
IAgentStateUp . |
IAgentState |
awaitState(Class awaitAgentState,
long timeoutMillis)
This method is designed to wait for the agent's initialization until till 'timeoutMillis'.
|
protected void |
componentFatalError(IFatalErrorEvent event)
Called whenever some comopnent broadcasts
IFatalErrorEvent . |
protected void |
componentStarted(IPausedEvent event)
Called whenever some component that was not started before broadcasts
IPausedEvent |
protected void |
componentStarted(IStartedEvent event)
Called whenever some component that was not started before broadcasts
IStartedEvent |
protected void |
componentStopped(IStoppedEvent event)
Called whenever component that was running broadcasts
IStoppedEvent . |
protected void |
componentStopping(IStoppingEvent event)
Called whenever some component broadcasts
IStoppingEvent |
protected AgentJMXComponents |
createAgentJMX() |
protected cz.cuni.amis.introspection.Folder |
createIntrospection()
Create introspection root object.
|
boolean |
equals(Object other) |
IAgentId |
getComponentId()
Returns agent id - contains also a human-readable name that can be changed
|
IComponentBus |
getEventBus()
IComponentBus that the instance is working with. |
cz.cuni.amis.introspection.Folder |
getIntrospection()
Returns folder with introspection information.
|
AgentJMXComponents |
getJMX()
Returns support class for the JMX feature of the agent.
|
LogCategory |
getLog()
Returns log category of the agent, used by agent lifecycle management methods itself.
|
IAgentLogger |
getLogger()
Returns AgentLogger for the instance allowing creating new log categories
or adding new handlers to them.
|
String |
getName()
Returns human-readable agent's name.
|
cz.cuni.amis.utils.flag.ImmutableFlag<IAgentState> |
getState()
Returns the state of the agent (whether it's running / dead / etc.).
|
int |
hashCode() |
boolean |
inState(Class<?>... states)
Returns true if the agent is in one of 'states'.
|
void |
kill()
Method that requests the agent to be killed - this counts as fatal error as well.
|
protected void |
killAgent()
Called during kill() method - override to provide custom ruthless stopping (killing) behavior of the agent.
|
boolean |
notInState(Class<?>... states)
Returns true if the agent is not in any of 'states'.
|
void |
pause()
Pauses the agent - working only if the agent is in
IAgentStateRunning |
protected void |
pauseAgent()
Called during pause() method - override to provide custom pausing behavior of the agent.
|
protected void |
preKillAgent()
Called before any
ComponentBusEvents.fatalError(String) event is broadcast. |
protected void |
preStopAgent()
Called before any
ComponentBusEvents.stopping() event is broadcast. |
protected void |
resetAgent()
Called whenever the
IComponentBus broadcast IResetEvent to reset all agent's components as well
as an agent. |
protected void |
resetEvent(IResetEvent event) |
void |
resume()
Resumes the agent - working only if the agent is in
IAgentStatePaused |
protected void |
resumeAgent()
Called during resume() method - override to provide custom resuming behavior of the agent.
|
protected void |
setState(AgentState state)
Sets the state of the agent ...
|
void |
start()
Starts the agent.
|
protected void |
startAgent()
Called during start() method - override to provide custom starting behavior of the agent.
|
void |
startPaused()
Starts the agent into paused state.
|
protected void |
startPausedAgent()
Called during startPaused() method - override to provide custom starting-paused behavior of the agent.
|
void |
stop()
Stops the agent.
|
protected void |
stopAgent()
Called during stop() method - override to provide custom stopping behavior of the agent.
|
String |
toString() |
public static final String INTROSPECTION_ROOT_NAME
public static final String LOG_CATEGORY_NAME
log
.protected LogCategory log
LOG_CATEGORY_NAME
.protected AgentEvents events
public AbstractAgent(IAgentId agentId, IComponentBus eventBus, IAgentLogger logger)
agentId
- unique id of the agenteventBus
- agent's event bus systemlogger
- agent's logger, used to obtain AgentName
instancepublic IAgentLogger getLogger()
IAgent
public cz.cuni.amis.utils.flag.ImmutableFlag<IAgentState> getState()
IAgent
Note that the type AgentState wraps two things:
public boolean inState(Class<?>... states)
states
- public boolean notInState(Class<?>... states)
states
- public IComponentBus getEventBus()
IComponentAware
IComponentBus
that the instance is working with.
Note that by design-choice - the IComponentBus
is a singleton inside AgentScoped
,
therefore you don't have to necessarily obtain the instance through the component, it suffice
to obtain it using injection into your object.
getEventBus
in interface IComponentAware
public String getName()
IAgent
Do not use as unique id of the agent:
1) the name might change during the life of agent
2) we do not ensure it's unique
Use getComponentId().getToken() instead!
Use getComponentId().getName().setFlag() to change the name of the agent.
public IAgentId getComponentId()
IAgent
getComponentId
in interface IAgent
getComponentId
in interface IComponent
public LogCategory getLog()
public final void start() throws ComponentCantStartException
1) switches state to IAgentStateStarting
2) broadcasts IStartingEvent
(transactional)
3) calls startAgent()
3) broadcasts IStartedEvent
(transactional)
4) switches state to IAgentStateStarted
Every agent component that wants to start together with the agent should do so during (2 or 3) and broadcast eventTransactionl(IStartedEvent
/ IPausedEvent
).
Prevents recursion.
start
in interface IAgent
start
in interface IControllable
ComponentCantStartException
public final void startPaused() throws ComponentCantStartException
1) switches state to IAgentStateStartingPaused
2) broadcasts IStartingPausedEvent
(transactional)
3) calls startAgent()
3) broadcasts IPausedEvent
(transactional)
4) switches state to IAgentStatePaused
Every agent component that wants to start together with the agent should do so during (2 or 3) and broadcast eventTransactionl(IStartedEvent
/ IPausedEvent
).
Prevents recursion.
startPaused
in interface IAgent
ComponentCantStartException
protected void preStopAgent()
ComponentBusEvents.stopping()
event is broadcast. Hook that allows you to implement just-before-death stuff
before any of agent component actually dies.public final void stop() throws ComponentCantStopException
1) switches state to IAgentStateStopping
2) broadcasts IStoppingEvent
(transactional)
3) calls stopAgent()
4) checks whether all components has stopped, if not - performs kill().
5) broadcasts IStoppedEvent
(transactional)
6) switches state to IAgentStateStopped
Every agent's component that is still running must stop itself during (2) by broadcasting 'eventTransactional(IStoppedEvent
)'.
If there will be some component that remains started after the propagation of IStoppingEvent
the method
will perform kill() method (counts as fatal error) and throws AgentException
.
Prevents recursion.
stop
in interface IAgent
stop
in interface IControllable
ComponentCantStopException
protected void preKillAgent()
ComponentBusEvents.fatalError(String)
event is broadcast. Hook that allows you to implement just-before-death stuff
before any of agent component actually dies.public final void kill()
1) switches state to IAgentStateFailed
2) broadcast IFatalErrorEvent
3) calls killAgent()
This should be used to ultimately kill the agent in a ruthless way - components will usually perform some dirty tricks to kill themselves.
Prevents recursion.
NEVER THROWS EXCEPTION
kill
in interface IAgent
kill
in interface IControllable
public final void pause() throws ComponentCantPauseException
IAgentStateRunning
1) switches state to IAgentStatePausing
2) broadcasts IPausingEvent
(transactional)
3) calls pauseAgent()
4) broadcasts IPausedEvent
(transactional)
5) switches state to IAgentPaused
Prevents recursion.
pause
in interface IAgent
ComponentCantPauseException
public final void resume() throws ComponentCantResumeException
IAgentStatePaused
1) switches state to IAgentStateResuming
2) broadcasts IResumingEvent
(transactional)
3) calls resumeAgent()
4) broadcasts IResumedEvent
(transactional)
5) switches state to IAgentStateRunning
Prevents recursion.
resume
in interface IAgent
ComponentCantResumeException
public final AgentJMXComponents getJMX()
public IAgentState awaitState(Class awaitAgentState) throws AgentException
IAgentStateUp
.
The call on this method will blocks until this instance of agent switches to the desired state.
Nevertheless - if the agent switches itself to the IAgentStateDown
state, it returns null.
(if it is not the state you are awaiting for of course). If you find this unsuitable, use WaitForAgentStateChange
directly.
awaitAgentState
- AgentException
public IAgentState awaitState(Class awaitAgentState, long timeoutMillis) throws AgentException
The call on this method will blocks until this instance of agent switches to the IAgentStateUp
.
Nevertheless - if the agent switches itself to the IAgentStateDown
state, it returns null. If you find this unsuitable, use WaitForAgentStateChange
directly.
The method also returns null in the case of timeout.
awaitAgentState
- timeoutMillis
- how long we should wait for the agent to iniAgentException
cz.cuni.amis.utils.exception.PogamutInterruptedException
public final cz.cuni.amis.introspection.Folder getIntrospection()
IAgent
getIntrospection
in interface IAgent
protected cz.cuni.amis.introspection.Folder createIntrospection()
protected void startAgent()
WARNING: DO NOT CALL ON YOUR OWN, ALWAYS USE PUBLIC INTERFACE (start()), but that should not be needed!
If you override this method don't forget to call super.startAgent() as the first method.
protected void startPausedAgent()
WARNING: DO NOT CALL ON YOUR OWN, ALWAYS USE PUBLIC INTERFACE (startPaused()), but that should not be needed!
If you override this method don't forget to call super.startPausedAgent() as the first method.
protected void stopAgent()
WARNING: DO NOT CALL ON YOUR OWN, ALWAYS USE PUBLIC INTERFACE (stop()).
If you override this method don't forget to call super.stopAgent() as the first method.
protected void killAgent()
WARNING: DO NOT CALL ON YOUR OWN, ALWAYS USE PUBLIC INTERFACE (kill()).
If you override this method don't forget to call super.killAgent() as the first method.
protected void pauseAgent()
WARNING: DO NOT CALL ON YOUR OWN, ALWAYS USE PUBLIC INTERFACE (pause()).
If you override this method don't forget to call super.pauseAgent() as the first method.
protected void resumeAgent()
WARNING: DO NOT CALL ON YOUR OWN, ALWAYS USE PUBLIC INTERFACE (resume()).
If you override this method don't forget to call super.resumeAgent() as the first method.
protected void resetAgent()
IComponentBus
broadcast IResetEvent
to reset all agent's components as well
as an agent. Clean up your private data structure, get ready to be started again.
WARNING: DO NOT CALL ON YOUR OWN, CALLED FROM THE resetEvent(IResetEvent)
AUTOMATICALLY.
If you override this method don't forget to call super.resetAgent() as the first method.
protected void componentStarted(IStartedEvent event)
IStartedEvent
If you override this method don't forget to call super.componentStarted(event) as the first method.
event
- protected void componentStarted(IPausedEvent event)
IPausedEvent
If you override this method don't forget to call super.componentStarted(event) as the first method.
event
- protected void componentStopping(IStoppingEvent event)
IStoppingEvent
If you override this method don't forget to call super.componentStopping(event) as the first method.
event
- protected void componentStopped(IStoppedEvent event)
IStoppedEvent
.
If you override this method don't forget to call super.componentStopped(event) as the first method.
event
- protected void componentFatalError(IFatalErrorEvent event)
IFatalErrorEvent
.
If you override this method don't forget to call super.fatalError(event) as the first method.
event
- protected void resetEvent(IResetEvent event)
protected AgentJMXComponents createAgentJMX()
protected void addDependency(IComponent component)
protected void addDependency(Class componentClass)
protected void addDependency(cz.cuni.amis.utils.token.IToken componentId)
protected void setState(AgentState state)
state
- protected void addJMXComponents()
Currently two components are added:
If you override this method don't forget to call super.addJMXComponents() as the first method.
Note that you don't need to override this method to introduce new jmx components if and only if:
1) you do not need the component before the agent starts up
2) your JMX component is also an IComponent
that starts together with the agent
If (2) holds, the component will be added to the 'jmx' by the agent automatically and if jmx is already started it will start it as well.
Copyright © 2012 AMIS research group, Faculty of Mathematics and Physics, Charles University in Prague, Czech Republic. All Rights Reserved.