A lightweight Java component model and runtime container.
Home | Previous: Step 4: Parameters | Next: Step 6: Advanced Events
You have already used two lifecycle callbacks. This step shows the whole picture: the transitions a component goes through, the callbacks attached to them, and how to drive them yourself.
A managed component goes through seven transitions:
The first six transitions have an associated state: deployed, instantiated,
initialized, activated, passivated and removed. A seventh state, failed,
is reached when a transition fails (see When A Transition Fails).
A component reacts to the transitions of initialization, activation, passivation and removal with callbacks. The simplest way to declare them is with annotations, on any method of the implementation:
@Initialization
public void prepare() {
@Activation
public void open() {
@Passivation
public void close() {
@Removal
public void release() {
Callbacks can also be declared by implementing interfaces (Initializable,
Activable, Passivatable, Removable) or, if you enable it, by naming
convention. See Lifecycle Callbacks.
If a callback throws, the transition fails and the component does not stay half-way:
the whole application composite that owns it goes to the failed state. Covalent
cleans up its ports and instances without calling your passivation or removal
callbacks, and logs the problem. A failed component is skipped by start(), and
Covalent does not restart it by itself.
Once the cause is fixed, resetFailedComponent brings the composite back to
deployed:
lifecycle.resetFailedComponent(Ticker.class);
Reset does not start the component. A later activation creates fresh instances.
container.start() is the simple way to bring everything to activated. When you
need finer control, container.lcs() returns the LifecycleServices, which can
read the state of a component and move it to a target state:
LifecycleServices lifecycle = container.lcs();
lifecycle.initializeComponent(Ticker.class);
System.out.println("State after initializeComponent: " + lifecycle.readComponentState(Ticker.class));
Lifecycle services target the component type (Ticker.class), not the
implementation. Deployment is the exception: it works on implementations and
must be done explicitly, first.
The lifecycle methods are smart: activateComponent initializes the component
first if it is not initialized yet.
package tutorial;
import org.opales.covalent.Covalent;
import org.opales.covalent.container.CovalentContainer;
import org.opales.covalent.container.component.annotations.Component;
import org.opales.covalent.container.component.annotations.Implementation;
import org.opales.covalent.container.lifecycle.Activation;
import org.opales.covalent.container.lifecycle.Initialization;
import org.opales.covalent.container.lifecycle.LifecycleServices;
import org.opales.covalent.container.lifecycle.Passivation;
import org.opales.covalent.container.lifecycle.Removal;
public final class Step5 {
@Component
public interface Ticker {
}
@Implementation
public static final class TickerImpl implements Ticker {
@Initialization
public void prepare() {
System.out.println(" [Ticker] initialization: prepare resources (once)");
}
@Activation
public void open() {
System.out.println(" [Ticker] activation: ports are published");
}
@Passivation
public void close() {
System.out.println(" [Ticker] passivation: ports are unpublished");
}
@Removal
public void release() {
System.out.println(" [Ticker] removal: release resources");
}
}
public static void main(final String[] args) {
CovalentContainer container = Covalent.main;
LifecycleServices lifecycle = container.lcs();
try {
container.deployComponents(TickerImpl.class);
System.out.println("State after deployment: " + lifecycle.readComponentState(Ticker.class));
lifecycle.initializeComponent(Ticker.class);
System.out.println("State after initializeComponent: " + lifecycle.readComponentState(Ticker.class));
container.start();
System.out.println("State after start: " + lifecycle.readComponentState(Ticker.class));
lifecycle.passivateComponent(Ticker.class);
System.out.println("State after passivateComponent: " + lifecycle.readComponentState(Ticker.class));
lifecycle.activateComponent(Ticker.class);
System.out.println("State after activateComponent: " + lifecycle.readComponentState(Ticker.class));
} finally {
if (container.isStarted()) {
container.stop();
}
}
}
}
Its output:
State after deployment: deployed
[Ticker] initialization: prepare resources (once)
State after initializeComponent: initialized
[Ticker] activation: ports are published
State after start: activated
[Ticker] passivation: ports are unpublished
State after passivateComponent: passivated
[Ticker] activation: ports are published
State after activateComponent: activated
[Ticker] passivation: ports are unpublished
[Ticker] removal: release resources
Look at how the callbacks are called:
start(), because the program asked
for it; start() then only has to activate it;stop() passivates the component, then removes it.Tip: To temporarily withdraw a component from the application while the container keeps running, passivate it with
LifecycleServicesand activate it again later. Do not usestop()andstart()for this: they operate on the whole container.
@Initialization, @Activation, @Passivation, @Removal) let it react.LifecycleServices reads the state of a component and moves it, one component at a
time.failed; resetFailedComponent
brings it back to deployed.Reference: Lifecycle (with every failure path), Vertical and Horizontal Start Modes.
Home | Previous: Step 4: Parameters | Next: Step 6: Advanced Events