Hello everyone,
Many of my group's applications make use of Jersey's @RequestScoped lifecycle for HK2-managed objects. In particular, a wide-spread practice is to inject a Provider instance for a request scoped object into a @Singleton object. This is common for ContainerRequestFilter implementations but is used elsewhere too, for instance in "service" objects shared throughout the application's subsystems.
On occasion, it is desirable to execute asynchronous tasks (i.e. tasks run in another thread) as a result of a request. These tasks are not used in creating a response but are rather side-effects of the request. This can lead to problems when invoking a Provider in the forked thread, namely the "java.lang.IllegalStateException: Not inside a request scope" error. If the providers are all top-level, it is easy enough to invoke them manually in the calling thread and pass the values to the forked thread directly; however, when the providers are nested inside other objects, this becomes difficult or impossible without substantial changes to the underlying code. Worse still, if any kind of object finalization is performed (e.g. in the dispose(...) method of an HK2 factory) then the previous workaround will not be sufficient: even if the object can be obtained in the forked thread, it may have been closed or otherwise invalidated by the finalization process.
A natural way to solve this is to fork the request scope along with the asynchronous task, releasing it (and its managed objects) once both the task and originating request have finished. The org.glassfish.jersey.process.internal.RequestScope class provides methods to do exactly this, specifically the referenceCurrent() and runInScope(...) methods. My initial testing shows that they function as expected. I have a few concerns that give me pause about this approach:
1. The various RequestScope classes are located in an "internal" Jersey package. Is it safe to rely on these as part of the public API of the Jersey project?
2. Is there a better way to accomplish this task? I was a bit surprised to find no mention of this API in the documentation (see point #1) and little discussion about this sort of dilemma on the web. This makes me think that I'm missing something obvious, but perhaps my use-cases are more esoteric than I realize.
Thanks for any guidance you can provide.
Sincerely,
Tom Boettcher
CONFIDENTIALITY NOTICE This message and any included attachments are from Cerner Corporation and are intended only for the addressee. The information contained in this message is confidential and may constitute inside or non-public information under international, federal, or state securities laws. Unauthorized forwarding, printing, copying, distribution, or use of such information is strictly prohibited and may be unlawful. If you are not the addressee, please promptly delete this message and notify the sender of the delivery error by e-mail or you may call Cerner's corporate offices in Kansas City, Missouri, U.S.A at (+1) (816)221-1024.