org.glassfish.hk2.runlevel.utilities
Class RunLevelControllerImpl

java.lang.Object
  extended by org.glassfish.hk2.runlevel.utilities.RunLevelControllerImpl
All Implemented Interfaces:
Activator, RunLevelController

@Service
public class RunLevelControllerImpl
extends Object
implements RunLevelController, Activator

The default RunLevelController implementation for Hk2. See the RunLevelController 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 DefaultRunLevelController is asked to proceedTo(X), the expected start order is: ServiceC, ServiceB, ServiceA, and the expected shutdown order is: ServiceA, ServiceB, ServiceC

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 ActiveDescriptor.create(org.glassfish.hk2.api.ServiceHandle) 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 DefaultRunLevelController implementation mode is pre-configured to be synchronous. The DefaultRunLevelController 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 DefaultRunLevelController in synchronous mode.

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

Important Note:
The proceedTo() method will throw unchecked exceptions 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 RunLevelListener 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.

~~~

Author:
jtrent, tbeerbower

Nested Class Summary
static class RunLevelControllerImpl.Interrupt
           
 
Field Summary
static long DEFAULT_ASYNC_WAIT
          The default timeout in milliseconds (to wait for async service types).
 
Fields inherited from interface org.glassfish.hk2.runlevel.RunLevelController
RUNLEVEL_CONTROLLER_DEFAULT_NAME
 
Constructor Summary
RunLevelControllerImpl()
           
 
Method Summary
protected  boolean accept(Descriptor descriptor, int activeRunLevel)
          Returns true if the RunLevel for the given descriptor in question should be processed by this RunLevelController instance.
 void activate(ActiveDescriptor<?> descriptor)
          Activate the run level service associated with given descriptor.
 void awaitCompletion()
          Wait for completion of run level progression.
 void awaitCompletion(long timeout, TimeUnit unit)
          Wait for completion of run level progression.
 void deactivate(ActiveDescriptor<?> descriptor)
          Deactivate the run level service associated with given descriptor.
protected  void event(org.glassfish.hk2.runlevel.utilities.RunLevelControllerImpl.Worker worker, org.glassfish.hk2.runlevel.utilities.RunLevelControllerImpl.ListenerEvent event, Throwable error, boolean isHardInterrupt)
           
protected  Activator getActivator()
          Get the best Activator.
 Integer getCurrentRunLevel()
          The current run level state.
 String getDescription(boolean extended)
           
protected  Collection<RunLevelListener> getListeners()
          Get all of the RunLevelListeners.
 String getName()
          Get the name of this RunLevelController.
 Integer getPlannedRunLevel()
          The planned run level state.
 HashMap<Integer,Stack<ActiveDescriptor<?>>> getRecorders()
           
protected  List<Integer> getRecordersToRelease(int runLevel)
           
protected  Sorter getSorter()
          Get the best Sorter.
 void interrupt()
          Causes this RunLevelController to attempt to stop any in-flight proceedTo() operation.
 void postConstruct()
           
 void proceedTo(int runLevel)
          Causes this RunLevelController to move to the specified run level for all RunLevel instances (identified by RunLevelControllerIndicator), orchestrating the appropriate lifecycle events.
protected  void proceedTo(Integer runLevel, boolean isHardInterrupt)
          Proceed to the given run level.
 void recordActivation(ActiveDescriptor<?> descriptor)
          Record the activation the run level service associated with the given descriptor.
 String toString()
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

DEFAULT_ASYNC_WAIT

public static final long DEFAULT_ASYNC_WAIT
The default timeout in milliseconds (to wait for async service types).

See Also:
Constant Field Values
Constructor Detail

RunLevelControllerImpl

public RunLevelControllerImpl()
Method Detail

postConstruct

@PostConstruct
public void postConstruct()

getName

public String getName()
Description copied from interface: RunLevelController
Get the name of this RunLevelController.

Specified by:
getName in interface RunLevelController
Returns:
the name

getCurrentRunLevel

public Integer getCurrentRunLevel()
Description copied from interface: RunLevelController
The current run level state. This represents the last run level successfully achieved by the underlying RunLevelController responsible for this scope.

Specified by:
getCurrentRunLevel in interface RunLevelController
Returns:
the current run level, or null if no run level has been been achieved

getPlannedRunLevel

public Integer getPlannedRunLevel()
Description copied from interface: RunLevelController
The planned run level state.

Specified by:
getPlannedRunLevel in interface RunLevelController
Returns:
the planned run level, or null if there is no planned level

recordActivation

public void recordActivation(ActiveDescriptor<?> descriptor)
Description copied from interface: RunLevelController
Record the activation the run level service associated with the given descriptor.

Specified by:
recordActivation in interface RunLevelController
Parameters:
descriptor - the descriptor

proceedTo

public void proceedTo(int runLevel)
Description copied from interface: RunLevelController
Causes this RunLevelController to move to the specified run level for all RunLevel instances (identified by RunLevelControllerIndicator), orchestrating the appropriate lifecycle events.

If the run level specified is the same as the current run level then the RunLevelController 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.

Specified by:
proceedTo in interface RunLevelController
Parameters:
runLevel - the run level to move to

interrupt

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

Specified by:
interrupt in interface RunLevelController

activate

public void activate(ActiveDescriptor<?> descriptor)
Description copied from interface: Activator
Activate the run level service associated with given descriptor.

Specified by:
activate in interface Activator
Parameters:
descriptor - the descriptor

deactivate

public void deactivate(ActiveDescriptor<?> descriptor)
Description copied from interface: Activator
Deactivate the run level service associated with given descriptor.

Specified by:
deactivate in interface Activator
Parameters:
descriptor - the descriptor

awaitCompletion

public void awaitCompletion()
                     throws InterruptedException,
                            ExecutionException,
                            TimeoutException
Description copied from interface: Activator
Wait for completion of run level progression.

Specified by:
awaitCompletion in interface Activator
Throws:
InterruptedException - if the current thread was interrupted while waiting
ExecutionException - if the completion code threw an exception
TimeoutException - if the wait timed out

awaitCompletion

public void awaitCompletion(long timeout,
                            TimeUnit unit)
                     throws InterruptedException,
                            TimeoutException,
                            ExecutionException
Description copied from interface: Activator
Wait for completion of run level progression.

Specified by:
awaitCompletion in interface Activator
Parameters:
timeout - the timeout value
unit - the time unit
Throws:
InterruptedException - if the current thread was interrupted while waiting
TimeoutException - if the wait timed out
ExecutionException - if the completion code threw an exception

toString

public String toString()
Overrides:
toString in class Object

getDescription

public String getDescription(boolean extended)

getRecorders

public HashMap<Integer,Stack<ActiveDescriptor<?>>> getRecorders()

accept

protected boolean accept(Descriptor descriptor,
                         int activeRunLevel)
Returns true if the RunLevel for the given descriptor in question should be processed by this RunLevelController instance.

Parameters:
descriptor - the descriptor
activeRunLevel - the current runLevel
Returns:
true if the RunLevel for the given descriptor in question should be processed by this RunLevelController instance

getRecordersToRelease

protected List<Integer> getRecordersToRelease(int runLevel)

event

protected void event(org.glassfish.hk2.runlevel.utilities.RunLevelControllerImpl.Worker worker,
                     org.glassfish.hk2.runlevel.utilities.RunLevelControllerImpl.ListenerEvent event,
                     Throwable error,
                     boolean isHardInterrupt)

proceedTo

protected void proceedTo(Integer runLevel,
                         boolean isHardInterrupt)
Proceed to the given run level.

Parameters:
runLevel - the run level
isHardInterrupt - indicates a hard interrupt

getActivator

protected Activator getActivator()
Get the best Activator.

Returns:
the best actvator; defaulting to this

getListeners

protected Collection<RunLevelListener> getListeners()
Get all of the RunLevelListeners.

Returns:
the listeners

getSorter

protected Sorter getSorter()
Get the best Sorter.

Returns:
the best sorter; null if none exists


Copyright © 2013 Oracle Corporation. All Rights Reserved.