org.jvnet.hk2.component.internal.runlevel
Class DefaultRunLevelService

java.lang.Object
  extended by org.jvnet.hk2.component.internal.runlevel.DefaultRunLevelService
All Implemented Interfaces:
java.util.EventListener, Enableable, HabitatListener, InhabitantActivator, InhabitantListener, InhabitantSorter, RunLevelService<java.lang.Void>, RunLevelState<java.lang.Void>

public class DefaultRunLevelService
extends java.lang.Object
implements RunLevelService<java.lang.Void>, Enableable, RunLevelState<java.lang.Void>, InhabitantListener, HabitatListener, InhabitantSorter, InhabitantActivator

The default RunLevelService implementation for Hk2. See the RunLevelService javadoc for general details regarding this service. Here is a brief example of the behavior of this service:
Imagine services ServiceA, ServiceB, and ServiceC are all in the same RunLevel X and the dependencies are ServiceA -> ServiceB -> ServiceC:

 @RunLevel(X)
 @Service
public class ServiceA {
 @Inject ServiceB b;
}

 @RunLevel(X)
 @Service
public class ServiceB {
 @Inject ServiceC c;
}

 @RunLevel(X)
 @Service
public class ServiceC {
}

When the DefaultRunLevelService is asked to proceedTo(X), the expected start order is: ServiceC, ServiceB, ServiceA, and the expected shutdown order is: ServiceA, ServiceB, ServiceC

RunLevel-annotated services correspond to RunLevelInhabitant's and they hook into the PostConstruct activation sequence to record the activation order of inhabitants within each RunLevel.

Note that no model of dependencies between services are kept in the habitat to make the implementation work. Any inhabitant in RunLevel X is arbitrarily picked to start with upon activation, and Inhabitant.get() is issued.

Consider the cases of possible activation orderings:

Case 1: A, B, then C by RLS. get ServiceA (called by RLS) Start ServiceA: get ServiceB Start ServiceB: get ServiceC Start ServiceC wire ServiceC PostConstruct ServiceC wire ServiceB PostConstruct ServiceB wire ServiceA PostConstruct ServiceA get ServiceB (called by RLS) get ServiceC (called by RLS)

Case 2: B, C, then A by RLS. get ServiceB (called by RLS) Start ServiceB: get ServiceC Start ServiceC wire ServiceC PostConstruct ServiceC wire ServiceB PostConstruct ServiceB get ServiceC (called by RLS) get ServiceA (called by RLS) Start ServiceA: get ServiceB wire ServiceA PostConstruct ServiceA

Case 3: B, A, then C by RLS. get ServiceB (called by RLS) Start ServiceB: get ServiceC Start ServiceC wire ServiceC PostConstruct ServiceC wire ServiceB PostConstruct ServiceB get ServiceA (called by RLS) Start ServiceA: get ServiceB wire ServiceA PostConstruct ServiceA get ServiceC (called by RLS)

Case 4: C, B, then A by RLS. get ServiceC (called by RLS) Start ServiceC: wire ServiceC PostConstruct ServiceC get ServiceB (called by RLS) Start ServiceB: get ServiceC wire ServiceB PostConstruct ServiceB get ServiceA (called by RLS) Start ServiceA: get ServiceB wire ServiceA PostConstruct ServiceA get ServiceA (called by RLS)

You can see that the order is always correct without needing to keep the model of dependencies.

~~~

Note that the implementation performs some level of constraint checking during injection. For example,

- It is an error to have a RunLevel-annotated service at RunLevel X to depend on (i.e., be injected with) a RunLevel-annotated service at RunLevel Y when Y > X.

- It is an error to have a non-RunLevel-annotated service to depend on a RunLevel-annotated service at any RunLevel.

Note that the implementation does not handle Holder and Collection injection constraint validations.

~~~

The implementation will automatically proceedTo(-1) after the habitat has been initialized. The value of "-1" is symbolic of the kernel run level.

Note that all RunLevel values less than -1 will be ignored.

~~~

The implementation is written to support two modes of operation, asynchronous / threaded, and synchronous / single threaded. The DefaultRunLevelService implementation mode is pre-configured to be synchronous. The DefaultRunLevelService is thread safe.

In the synchronous mode, calls can be made to proceedTo() to interrupt processing of any currently executing proceedTo() operation. This might occur: in another thread, in the RunLevelListener handlers, or in a RunLevel annotated service's PostConstruct method call.

Note, however, that even in synchronous mode the proceedTo() operation may exhibit asynchronous behavior. This is the case when the caller has two threads calling proceedTo(), where the second thread is canceling the operation of the first (perhaps due to timeout of a service's PostConstruct, etc.). In this case, an interrupt will be sent to the first running thread to cancel the previous operation, and proceedTo the run level from the second thread's request. This presumes that the first thread is capable of being interrupted. In such a situation, the second proceedTo() call returns immediately and the first proceedTo() is interrupted to continue to the new runLevel requested from the second thread's interrupt.

For this reason, it is strongly advised that InterruptedException is not swallowed by services that can be driven by the DefaultRunLevelService in synchronous mode.

proceedTo invocations from a PostConstruct callback are discouraged. Consider using RunLevelListener instead.

Important Note:
The proceedTo() method will throw unchecked exceptions of type DefaultRunLevelService.Interrupt if it detects that it is being called reentrantly in synchronous mode. Callers should be careful NOT to swallow exceptions of this type as shown in the following example:

try {
 rls.proceedTo(x);
} catch (Exception e) {
 // swallow exception
}

~~~

All calls to the happens synchronously on the same thread that caused the Inhabitant to be activated. Therefore, implementors of this interface should be careful and avoid calling long operations.

~~~

This service implements contracts InhabitantSorter as well as InhabitantActivator. The implementation will first attempt to find a habitat resident singleton for each of these contracts respectively, and failing to find an implementation will handle each itself. This lookup occurs iteratively just prior to a run level progression event. Note, however, that InhabitantSorter is only used as part of activations since the Recorder is chiefly responsible for ensuring release of the inhabitants occur in a consistent order. See earlier notes on this subject.

Since:
3.1
Author:
Jeff Trent
See Also:
RunLevelService

Nested Class Summary
static class DefaultRunLevelService.Interrupt
           
 
Nested classes/interfaces inherited from interface org.jvnet.hk2.component.InhabitantListener
InhabitantListener.EventType
 
Nested classes/interfaces inherited from interface org.jvnet.hk2.component.HabitatListener
HabitatListener.EventType
 
Field Summary
static int INITIAL_RUNLEVEL
           
static int KERNEL_RUNLEVEL
           
protected  java.lang.String name
           
static java.lang.String NAME
           
 
Constructor Summary
  DefaultRunLevelService(Habitat habitat)
           
protected DefaultRunLevelService(Habitat habitat, boolean async, java.lang.String name, java.lang.Class<?> targetEnv, java.util.HashMap<java.lang.Integer,org.jvnet.hk2.component.internal.runlevel.Recorder> recorders)
           
 
Method Summary
protected  boolean accept(Inhabitant<?> i, RunLevel rl, int activeRunLevel)
          Returns true if the RunLevel for the given inhabitant in question should be processed by this RunLevelService instance.
 void activate(Inhabitant inhabitant)
          Called when we are responsible for handling the InhabitantActivator work.
 void deactivate(Inhabitant inhabitant)
          Called when we are responsible for handling the InhabitantActivator work.
 void enable(boolean enabled)
          Toggle the enabled state.
protected  void event(org.jvnet.hk2.component.internal.runlevel.DefaultRunLevelService.Worker worker, org.jvnet.hk2.component.internal.runlevel.DefaultRunLevelService.ListenerEvent event, ServiceContext context, java.lang.Throwable error)
           
protected  void event(org.jvnet.hk2.component.internal.runlevel.DefaultRunLevelService.Worker worker, org.jvnet.hk2.component.internal.runlevel.DefaultRunLevelService.ListenerEvent event, ServiceContext context, java.lang.Throwable error, boolean isHardInterrupt)
           
 java.lang.Integer getActivatingRunLevel()
           
 java.lang.Integer getCurrentRunLevel()
          The current run level state.
 java.lang.String getDescription(boolean extended)
           
 java.lang.Class getEnvironment()
          The environment value for this state.
protected  InhabitantActivator getInhabitantActivator()
          Obtains the "best" InhabitantActivator, first looking up out of the habitat any service registered under the same name as ourself, then defaulting to the first one registered by type alone, followed by ourself.
protected  InhabitantSorter getInhabitantSorter()
          Obtains the "best" InhabitantSorter, first looking up out of the habitat any service registered under the same name as ourself, then defaulting to the first one registered by type alone, followed by ourself.
 java.lang.String getName()
           
 java.lang.Integer getPlannedRunLevel()
          The planned run level state.
protected  java.util.List<java.lang.Integer> getRecordersToRelease(java.util.HashMap<java.lang.Integer,org.jvnet.hk2.component.internal.runlevel.Recorder> list, int runLevel)
           
 RunLevelState<java.lang.Void> getState()
          Returns the current state of this RunLevelService instance.
 boolean inhabitantChanged(HabitatListener.EventType eventType, Habitat habitat, Inhabitant<?> inhabitant)
          Once habitat is initialized we can proceed to boot through to kernel level (-1)
 boolean inhabitantChanged(InhabitantListener.EventType eventType, Inhabitant<?> inhabitant)
          Called when the inhabitant has changed.
 boolean inhabitantIndexChanged(HabitatListener.EventType eventType, Habitat habitat, Inhabitant<?> inhabitant, java.lang.String index, java.lang.String name, java.lang.Object service)
          Called when the habitat index has changed.
 void interrupt()
          Causes this RunLevelService to attempt to stop any in-flight proceedTo() operation.
 void interrupt(int runLevel)
          Same as RunLevelService.interrupt(), with the option to immediately perform a RunLevelService.proceedTo(int) following the interrupt.
 boolean isEnabled()
           
 void proceedTo(int runLevel)
          Causes this RunLevelService to move to the specified run level for all RunLevel instances (identified by environment), orchestrating the appropriate lifecycle events based on the given implementation strategy.
protected  void proceedTo(java.lang.Integer runLevel, boolean isHardInterrupt)
           
protected  ServiceContext serviceContext(java.lang.Exception e, Inhabitant<?> i)
           
 java.util.List<Inhabitant<?>> sort(java.util.List<Inhabitant<?>> inhabitants)
          Called when we are responsible for handling the InhabitantSorter work.
 java.lang.String toString()
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

INITIAL_RUNLEVEL

public static final int INITIAL_RUNLEVEL
See Also:
Constant Field Values

KERNEL_RUNLEVEL

public static final int KERNEL_RUNLEVEL
See Also:
Constant Field Values

NAME

public static final java.lang.String NAME
See Also:
Constant Field Values

name

protected final java.lang.String name
Constructor Detail

DefaultRunLevelService

public DefaultRunLevelService(Habitat habitat)

DefaultRunLevelService

protected DefaultRunLevelService(Habitat habitat,
                                 boolean async,
                                 java.lang.String name,
                                 java.lang.Class<?> targetEnv,
                                 java.util.HashMap<java.lang.Integer,org.jvnet.hk2.component.internal.runlevel.Recorder> recorders)
Method Detail

toString

public java.lang.String toString()
Overrides:
toString in class java.lang.Object

getDescription

public java.lang.String getDescription(boolean extended)

getName

public java.lang.String getName()

getState

public RunLevelState<java.lang.Void> getState()
Description copied from interface: RunLevelService
Returns the current state of this RunLevelService instance.

Specified by:
getState in interface RunLevelService<java.lang.Void>

getEnvironment

public java.lang.Class getEnvironment()
Description copied from interface: RunLevelState
The environment value for this state.

Specified by:
getEnvironment in interface RunLevelState<java.lang.Void>
Returns:
the class type used to uniquely identify the environment in context, or null representing the default environment.

getCurrentRunLevel

public java.lang.Integer getCurrentRunLevel()
Description copied from interface: RunLevelState
The current run level state. This represents the last run level successfully achieved by the underlying RunLevelService responsible for this environment.

Specified by:
getCurrentRunLevel in interface RunLevelState<java.lang.Void>
Returns:
the current run level, or null if no run level has been been achieved.

getPlannedRunLevel

public java.lang.Integer getPlannedRunLevel()
Description copied from interface: RunLevelState
The planned run level state. If this value is different from current run level, this signifies movement of the underlying RunLevelService.

Specified by:
getPlannedRunLevel in interface RunLevelState<java.lang.Void>
Returns:
the planned run level, or null if there is no planned level. This value is established by a call to RunLevelService.proceedTo(int).

getActivatingRunLevel

public java.lang.Integer getActivatingRunLevel()

enable

public void enable(boolean enabled)
            throws java.lang.IllegalStateException
Description copied from interface: Enableable
Toggle the enabled state.

Implementors are encouraged to throw an IllegalStateException if the requested enablement/disablement operation cannot be performed for whatever reason.

Specified by:
enable in interface Enableable
Parameters:
enabled - true to enable, and false to disable
Throws:
java.lang.IllegalStateException

isEnabled

public boolean isEnabled()
Specified by:
isEnabled in interface Enableable
Returns:
true if the service is currently enabled

accept

protected boolean accept(Inhabitant<?> i,
                         RunLevel rl,
                         int activeRunLevel)
Returns true if the RunLevel for the given inhabitant in question should be processed by this RunLevelService instance.

Parameters:
i - the inhabitant
rl - the inhabitan'ts runLevel
activeRunLevel - the current runLevel
Returns:

getRecordersToRelease

protected java.util.List<java.lang.Integer> getRecordersToRelease(java.util.HashMap<java.lang.Integer,org.jvnet.hk2.component.internal.runlevel.Recorder> list,
                                                                  int runLevel)

event

protected void event(org.jvnet.hk2.component.internal.runlevel.DefaultRunLevelService.Worker worker,
                     org.jvnet.hk2.component.internal.runlevel.DefaultRunLevelService.ListenerEvent event,
                     ServiceContext context,
                     java.lang.Throwable error)

event

protected void event(org.jvnet.hk2.component.internal.runlevel.DefaultRunLevelService.Worker worker,
                     org.jvnet.hk2.component.internal.runlevel.DefaultRunLevelService.ListenerEvent event,
                     ServiceContext context,
                     java.lang.Throwable error,
                     boolean isHardInterrupt)

inhabitantChanged

public boolean inhabitantChanged(InhabitantListener.EventType eventType,
                                 Inhabitant<?> inhabitant)
Description copied from interface: InhabitantListener
Called when the inhabitant has changed.

Specified by:
inhabitantChanged in interface InhabitantListener
Returns:
callee should return true to continue receiving notification, false otherwise

inhabitantChanged

public boolean inhabitantChanged(HabitatListener.EventType eventType,
                                 Habitat habitat,
                                 Inhabitant<?> inhabitant)
Once habitat is initialized we can proceed to boot through to kernel level (-1)

Specified by:
inhabitantChanged in interface HabitatListener
Returns:
callee should return true to continue receiving notification, false otherwise

inhabitantIndexChanged

public boolean inhabitantIndexChanged(HabitatListener.EventType eventType,
                                      Habitat habitat,
                                      Inhabitant<?> inhabitant,
                                      java.lang.String index,
                                      java.lang.String name,
                                      java.lang.Object service)
Description copied from interface: HabitatListener
Called when the habitat index has changed.

Specified by:
inhabitantIndexChanged in interface HabitatListener
Returns:
callee should return true to continue receiving notification, false otherwise

proceedTo

public void proceedTo(int runLevel)
Description copied from interface: RunLevelService
Causes this RunLevelService to move to the specified run level for all RunLevel instances (identified by environment), orchestrating the appropriate lifecycle events based on the given implementation strategy. See the javadoc for each implementation for specific details.

If the RunLevel specified is the same as the current RunLevel then the RunLevelService may return immediately.

Note that the underlying implementation may perform this operation asynchronously. Implementors who choose the asynchronous approach are expected to treat a subsequent proceedTo(newRunLevel) call as an implicit cancellation of any currently running proceedTo() that is running on one or more managed threads. Again, see the javadoc for each implementation for details.

Specified by:
proceedTo in interface RunLevelService<java.lang.Void>
Parameters:
runLevel - the run level to move to.

interrupt

public void interrupt()
Description copied from interface: RunLevelService
Causes this RunLevelService to attempt to stop any in-flight proceedTo() operation. This call will not have any any affect if there is no current proceedTo() operation in progress.

See the javadoc for each implementation for specific details

Specified by:
interrupt in interface RunLevelService<java.lang.Void>

interrupt

public void interrupt(int runLevel)
Description copied from interface: RunLevelService
Same as RunLevelService.interrupt(), with the option to immediately perform a RunLevelService.proceedTo(int) following the interrupt.

Specified by:
interrupt in interface RunLevelService<java.lang.Void>
Parameters:
runLevel - the run level to move to following the interrupt

proceedTo

protected void proceedTo(java.lang.Integer runLevel,
                         boolean isHardInterrupt)

sort

public java.util.List<Inhabitant<?>> sort(java.util.List<Inhabitant<?>> inhabitants)
Called when we are responsible for handling the InhabitantSorter work. The implementation returns the inhabitants argument as-is .

Specified by:
sort in interface InhabitantSorter
Parameters:
inhabitants - the inhabitants to sort. This may possibly be an unmodifiable list. Implementors are therefore cautioned to handle this case accordingly.
Returns:
the sorted list --- must not be null

activate

public void activate(Inhabitant inhabitant)
Called when we are responsible for handling the InhabitantActivator work.

Specified by:
activate in interface InhabitantActivator
Parameters:
inhabitant - the inhabitant to activate

deactivate

public void deactivate(Inhabitant inhabitant)
Called when we are responsible for handling the InhabitantActivator work.

Specified by:
deactivate in interface InhabitantActivator
Parameters:
inhabitant - the inhabitant to release

getInhabitantSorter

protected InhabitantSorter getInhabitantSorter()
Obtains the "best" InhabitantSorter, first looking up out of the habitat any service registered under the same name as ourself, then defaulting to the first one registered by type alone, followed by ourself.

Returns:
an InhabitantActivator, defaulting to ourself

getInhabitantActivator

protected InhabitantActivator getInhabitantActivator()
Obtains the "best" InhabitantActivator, first looking up out of the habitat any service registered under the same name as ourself, then defaulting to the first one registered by type alone, followed by ourself.

Returns:
an InhabitantActivator, defaulting to ourself

serviceContext

protected ServiceContext serviceContext(java.lang.Exception e,
                                        Inhabitant<?> i)


Copyright © 2011 Oracle Corporation. All Rights Reserved.