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

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

public class DefaultRunLevelService
extends Object
implements RunLevelService<Void>, Enableable, RunLevelState<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.

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 boolean DEFAULT_ASYNC_ENABLED
           
static long DEFAULT_ASYNC_WAIT
           
static String DEFAULT_NAME
           
static Class<?> DEFAULT_SCOPE
           
static int INITIAL_RUNLEVEL
           
protected  String name
           
 
Constructor Summary
DefaultRunLevelService(SimpleServiceLocator habitat)
           
DefaultRunLevelService(SimpleServiceLocator habitat, boolean async, String name, Class<?> targetScope, HashMap<Integer,org.jvnet.hk2.component.internal.runlevel.Recorder> recorders)
           
 
Method Summary
protected  boolean accept(AbstractInhabitantImpl<?> i, 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 awaitCompletion()
          Await completion for all AsyncPostConstruct service types
 void awaitCompletion(long timeout, TimeUnit unit)
          No-op, since we are not a MultiThreadedInhabitantActivator
 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, 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, Throwable error, boolean isHardInterrupt)
           
 Integer getActivatingRunLevel()
           
 Integer getCurrentRunLevel()
          The current run level state.
 String getDescription(boolean extended)
           
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.
protected  Collection<RunLevelListener> getListeners()
           
 String getName()
           
 RunLevelService<?> getParent()
           
 Integer getPlannedRunLevel()
          The planned run level state.
protected  List<Integer> getRecordersToRelease(HashMap<Integer,org.jvnet.hk2.component.internal.runlevel.Recorder> list, int runLevel)
           
protected  Integer getRunLevel(AbstractInhabitantImpl<?> i)
          Attempts to obtain the RunLevel value from the metadata() instead of from the annotation which requires a class load.
 String getScopeName()
          The scope value for this state.
 RunLevelState<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, String index, String name, 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 isDefault()
           
 boolean isEnabled()
           
protected
<T> Collection<T>
narrow(Collection<Inhabitant<T>> inhabs)
          narrow down and return the collection for those runLevelScopes that match
 void proceedTo(int runLevel)
          Causes this RunLevelService to move to the specified run level for all RunLevel instances (identified by scope), orchestrating the appropriate lifecycle events based on the given implementation strategy.
protected  void proceedTo(Integer runLevel, boolean isHardInterrupt)
           
protected  ServiceContext serviceContext(Exception e, Inhabitant<?> i)
           
 void setInhabitantActivator(InhabitantActivator activator)
          Overrides the default behavior of getting the inhabitant activator from the habitat to use a stand-in activator instead.
 void setInhabitantSorter(InhabitantSorter sorter)
          Overrides the default behavior of getting the inhabitant sorter from the habitat to use a stand-in sorter instead.
 void setListener(RunLevelListener listener)
          Overrides the default behavior of getting all listeners from the habitat to use a stand-in listener instead.
 void setParent(RunLevelService<?> parent)
           
 List<Inhabitant<?>> sort(List<Inhabitant<?>> inhabitants)
          Called when we are responsible for handling the InhabitantSorter work.
 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

DEFAULT_NAME

public static final String DEFAULT_NAME
See Also:
Constant Field Values

DEFAULT_ASYNC_ENABLED

public static final boolean DEFAULT_ASYNC_ENABLED
See Also:
Constant Field Values

DEFAULT_ASYNC_WAIT

public static final long DEFAULT_ASYNC_WAIT
See Also:
Constant Field Values

DEFAULT_SCOPE

public static final Class<?> DEFAULT_SCOPE

name

protected final String name
Constructor Detail

DefaultRunLevelService

public DefaultRunLevelService(SimpleServiceLocator habitat)

DefaultRunLevelService

public DefaultRunLevelService(SimpleServiceLocator habitat,
                              boolean async,
                              String name,
                              Class<?> targetScope,
                              HashMap<Integer,org.jvnet.hk2.component.internal.runlevel.Recorder> recorders)
Method Detail

toString

public String toString()
Overrides:
toString in class Object

isDefault

public boolean isDefault()

getDescription

public String getDescription(boolean extended)

setParent

public void setParent(RunLevelService<?> parent)

getParent

public RunLevelService<?> getParent()

getName

public String getName()

getState

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

Specified by:
getState in interface RunLevelService<Void>

getScopeName

public String getScopeName()
Description copied from interface: RunLevelState
The scope value for this state.

Specified by:
getScopeName in interface RunLevelState<Void>
Returns:
the class type name used to uniquely identify the scope in context.

getCurrentRunLevel

public 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 scope.

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

getPlannedRunLevel

public 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<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 Integer getActivatingRunLevel()

enable

public void enable(boolean enabled)
            throws 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:
IllegalStateException

isEnabled

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

accept

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

Parameters:
i - the inhabitant
activeRunLevel - the current runLevel
Returns:

getRecordersToRelease

protected List<Integer> getRecordersToRelease(HashMap<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,
                     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,
                     Throwable error,
                     boolean isHardInterrupt)

setListener

public void setListener(RunLevelListener listener)
Overrides the default behavior of getting all listeners from the habitat to use a stand-in listener instead. If set to null, the default behavior will be restored.

Parameters:
listener - the alternative, stand-in listener

getListeners

protected Collection<RunLevelListener> getListeners()

narrow

protected <T> Collection<T> narrow(Collection<Inhabitant<T>> inhabs)
narrow down and return the collection for those runLevelScopes that match


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

getRunLevel

protected Integer getRunLevel(AbstractInhabitantImpl<?> i)
Attempts to obtain the RunLevel value from the metadata() instead of from the annotation which requires a class load. If it can't get it from the metadata() it will default to load the class to obtain the RunLevel value.

Parameters:
i - the inhabitant to get the runLevel for
Returns:

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,
                                      String index,
                                      String name,
                                      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 scope), 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<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<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<Void>
Parameters:
runLevel - the run level to move to following the interrupt

proceedTo

protected void proceedTo(Integer runLevel,
                         boolean isHardInterrupt)

sort

public List<Inhabitant<?>> sort(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

awaitCompletion

public void awaitCompletion()
                     throws InterruptedException,
                            ExecutionException,
                            TimeoutException
Await completion for all AsyncPostConstruct service types

Specified by:
awaitCompletion in interface InhabitantActivator
Throws:
InterruptedException
ExecutionException
TimeoutException

awaitCompletion

public void awaitCompletion(long timeout,
                            TimeUnit unit)
                     throws InterruptedException,
                            TimeoutException,
                            ExecutionException
No-op, since we are not a MultiThreadedInhabitantActivator

Specified by:
awaitCompletion in interface InhabitantActivator
Throws:
InterruptedException
TimeoutException
ExecutionException

setInhabitantSorter

public void setInhabitantSorter(InhabitantSorter sorter)
Overrides the default behavior of getting the inhabitant sorter from the habitat to use a stand-in sorter instead. If set to null, the default behavior will be restored.

Parameters:
sorter - the alternative, stand-in sorter

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

setInhabitantActivator

public void setInhabitantActivator(InhabitantActivator activator)
Overrides the default behavior of getting the inhabitant activator from the habitat to use a stand-in activator instead. If set to null, the default behavior will be restored.

Parameters:
activator - the alternative, stand-in activator

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(Exception e,
                                        Inhabitant<?> i)


Copyright © 2011 Oracle Corporation. All Rights Reserved.