I use Jersey in a Java SE application. HK2 provides dependency injection to the overall application. HK2 RunLevel services are registered in the application service locator, which is the parent to Jerseys service locator.
+ application locator
|\- RunLevel capabilities
| - MyCustomService, @RunLevel(value=1)
\
+ jersey locator
\- jersey resource class
\ @Inject MyCustomService
My problem is that I cannot access runlevel-scoped services from within Jersey. When - in the above example - the jersey resource is opened, injection of MyCustomService
fails:
java.lang.IllegalStateException: Could not find an active context for org.glassfish.hk2.runlevel.RunLevel
The reason for this seems to be that the services behind the HK2 RunLevel feature have visibility LOCAL: The jersey locator cannot access them via its parent locator. See here.
Questions:
Update
To give context to the question, I'm using runlevels in a "System-V" style.
ExecutorServices
for background processing and HTTP services (running jersey) are started. Jersey rejects all incoming requests at this level.MessageListeners
are attached to the broker, feeding requests to the background executors. Jersey accepts and processes HTTP requests.This concept allows granular control over availability and long running requests. When shutting down, the application will be at runlevel 2 until previously accepted HTTP requests are fulfilled and enqueued background tasks completed. However, no new tasks/requests are accepted. Then, runlevel 1, 0, -1, exit.
The solution is to respect the DescriptorVisibility#LOCAL
and inject services dependent on RunLevelContext
only from the service locator that manages them.
It is a bit cumbersome:
get the runlevel-scoped service injected explicitely
ServiceLocator applicationLocator = ServiceLocatorFactory.getInstance().find("applicationLocator");
MyCustomService mcs = applicationLocator.getService(MyCustomService.class);
mcs.doSomething();
To reduce the danger of forgetting to do it this way, and just injecting MyCustomService
into a jersey resource, I've now marked my runlevel-scoped services to be also of DescriptorVisibility#LOCAL
. That way they can't be injected by the jersey locator.