| <?xml version="1.0" encoding="UTF-8"?> | 
 | <!-- | 
 |  | 
 |     Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. | 
 |  | 
 |     This program and the accompanying materials are made available under the | 
 |     terms of the Eclipse Public License v. 2.0, which is available at | 
 |     http://www.eclipse.org/legal/epl-2.0. | 
 |  | 
 |     This Source Code may also be made available under the following Secondary | 
 |     Licenses when the conditions for such availability set forth in the | 
 |     Eclipse Public License v. 2.0 are satisfied: GNU General Public License, | 
 |     version 2 with the GNU Classpath Exception, which is available at | 
 |     https://www.gnu.org/software/classpath/license.html. | 
 |  | 
 |     SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | 
 |  | 
 | --> | 
 |  | 
 | <!DOCTYPE chapter [<!ENTITY % ents SYSTEM "jersey.ent" > %ents;]> | 
 | <chapter xmlns="http://docbook.org/ns/docbook" | 
 |          version="5.0" | 
 |          xml:lang="en" | 
 |          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | 
 |          xmlns:xi="http://www.w3.org/2001/XInclude" | 
 |          xmlns:xlink="http://www.w3.org/1999/xlink" | 
 |          xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd | 
 |                              http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd" | 
 |          xml:id="ioc"> | 
 |     <title>Custom Injection and Lifecycle Management</title> | 
 |  | 
 |     <para> | 
 |         Since version 2.0, Jersey uses &hk2.link; library for component life cycle management and dependency injection. | 
 |         Rather than spending a lot of effort in maintaining Jersey specific API (as it used to be before Jersey 2.0 version), | 
 |         Jersey defines several extension points where end-user application can directly manipulate Jersey HK2 bindings | 
 |         using the HK2 public API to customize life cycle management and dependency injection of application components. | 
 |     </para> | 
 |  | 
 |     <para> | 
 |         Jersey user guide can by no means supply an exhaustive documentation of HK2 API in its entire scope. | 
 |         This chapter only points out the most common scenarios related | 
 |         to dependency injection in Jersey and suggests possible options to implement these scenarios. | 
 |         It is highly recommended to check out the &hk2.link; website and read HK2 documentation in order to get | 
 |         better understanding of suggested approaches. HK2 documentation should also help in resolving use cases | 
 |         that are not discussed in this writing. | 
 |     </para> | 
 |  | 
 |     <para> | 
 |         There are typically three main use cases, where your application may consider dealing with | 
 |         HK2 APIs exposed in Jersey: | 
 |  | 
 |         <itemizedlist> | 
 |             <listitem><simpara>Implementing a custom injection provider that allows an application to define | 
 |                 additional types to be injectable into Jersey-managed JAX-RS components.</simpara></listitem> | 
 |             <listitem><simpara>Defining a custom injection annotation (other than &jee9.jakarta.inject.Inject; | 
 |                 or &jaxrs.core.Context;) to mark application injection points.</simpara></listitem> | 
 |             <listitem><simpara>Specifying a custom component life cycle management for your application | 
 |                 components.</simpara></listitem> | 
 |         </itemizedlist> | 
 |     </para> | 
 |  | 
 |     <para> | 
 |         Since Jersey 2.26, the injection has been abstracted, so that &hk2.link; can be eventually replaced by the CDI or | 
 |         any other injection framework. In the next chapters, we document possibilities provided directly by &hk2.link; and | 
 |         by Jersey abstraction components. | 
 |     </para> | 
 |  | 
 |     <section xml:id="injection.manager"> | 
 |         <title>InjectionManager</title> | 
 |  | 
 |         <para> | 
 |             Since Jersey 2.26, Jersey comes with the main abstraction interface to communicate with the DI container, the | 
 |             &jersey.common.internal.inject.InjectionManager;. What is <literal>ServiceLocator</literal> for &hk2.link;, or | 
 |             <literal>BeanManager</literal> for CDI, that's &jersey.common.internal.inject.InjectionManager; for Jersey. | 
 |         </para> | 
 |         <para> | 
 |             &jersey.common.internal.inject.InjectionManager; can be injected into the user provided classes instantiated | 
 |             by Jersey. It can also be obtained programmatically by &jersey.client.InjectionManagerClientProvider; | 
 |             and &lit.jersey.common.InjectionManagerProvider; from Jakarta REST components, such as | 
 |             &jaxrs.core.FeatureContext;, or &jaxrs.ext.MessageBodyReader; and &jaxrs.ext.MessageBodyReader;. | 
 |         </para> | 
 |         <para> | 
 |             Customers used to the &hk2.ServiceLocator; can still use it directly; the &hk2.ServiceLocator; can be obtained | 
 |             either directly by injection, or programmatically as <literal>InjectionManager.getInstance(ServiceLocator.class)</literal>. | 
 |         </para> | 
 |     </section> | 
 |  | 
 |     <section> | 
 |         <title>Implementing Custom Injection Provider</title> | 
 |  | 
 |       <para> | 
 |         Relying on Servlet HTTP session concept is not very RESTful. It turns the originally state-less HTTP | 
 |         communication schema into a state-full manner. However, it could serve | 
 |         as a good example that will help me demonstrate implementation of the use cases described above. | 
 |         The following examples should work on top of Jersey Servlet integration module. The approach that will be | 
 |         demonstrated could be further generalized. | 
 |         Below we will show how to make actual Servlet &jee9.servlet.HttpSession; injectable into JAX-RS components | 
 |         and how to make this injection work with a custom inject annotation type. Finally, we will demonstrate | 
 |         how you can write &lit.jee9.servlet.HttpSession;-scoped JAX-RS resources. | 
 |       </para> | 
 |  | 
 |         <para> | 
 |             Jersey implementation allows you to directly inject &jee9.servlet.HttpServletRequest; instance into | 
 |             your JAX-RS components. | 
 |             It is quite straight forward to get the appropriate &lit.jee9.servlet.HttpSession; instance out of the | 
 |             injected request instance. | 
 |             Let say, you want to get &lit.jee9.servlet.HttpSession; instance directly injected into your JAX-RS | 
 |             types like in the code snippet below. | 
 |  | 
 |             <programlisting language="java">@Path("di-resource") | 
 | public class MyDiResource { | 
 |  | 
 |     @Inject HttpSession httpSession; | 
 |  | 
 |     ... | 
 |  | 
 | }</programlisting> | 
 |         </para> | 
 |         <section> | 
 |             <title>Using HK2 classes</title> | 
 |  | 
 |             <para> | 
 |             To make the above injection work, you will need to define an additional HK2 binding in your | 
 |             application &jersey.server.ResourceConfig;. | 
 |             Let's start with a custom HK2 &hk2.Factory; implementation that knows how to extract | 
 |             &lit.jee9.servlet.HttpSession; out of given &lit.jee9.servlet.HttpServletRequest;. | 
 |  | 
 |             <programlisting language="java">import org.glassfish.hk2.api.Factory; | 
 |     ... | 
 |  | 
 |     public class HttpSessionFactory implements Factory<HttpSession> { | 
 |  | 
 |     private final HttpServletRequest request; | 
 |  | 
 |     @Inject | 
 |     public HttpSessionFactory(HttpServletRequest request) { | 
 |         this.request = request; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public HttpSession provide() { | 
 |        return request.getSession(); | 
 |     } | 
 |  | 
 |     @Override | 
 |     public void dispose(HttpSession t) { | 
 |     } | 
 | }</programlisting> | 
 |  | 
 |             Please note that the factory implementation itself relies on having the actual | 
 |             &lit.jee9.servlet.HttpServletRequest; instance injected. | 
 |             In your implementation, you can of course depend on other types (and inject them conveniently) | 
 |             as long as these other types are bound to the actual HK2 service locator by Jersey or by your | 
 |             application. The key notion to remember here is that your HK2 &lit.hk2.Factory; implementation | 
 |             is responsible for implementing the <literal>provide()</literal> method that is used by HK2 | 
 |             runtime to retrieve the injected instance. Those of you who worked with Guice binding API in the | 
 |             past will most likely find this concept very familiar. | 
 |         </para> | 
 |  | 
 |         <para> | 
 |             Once implemented, the factory can be used in a custom HK2 &lit.hk2.Binder; to define the | 
 |             new injection binding for &lit.jee9.servlet.HttpSession;. Finally, the implemented binder | 
 |             can be registered in your &jersey.server.ResourceConfig;: | 
 |  | 
 |             <programlisting language="java">import org.glassfish.hk2.utilities.binding.AbstractBinder; | 
 | ... | 
 |  | 
 | public class MyApplication extends ResourceConfig { | 
 |  | 
 |     public MyApplication() { | 
 |  | 
 |         ... | 
 |  | 
 |         register(new AbstractBinder() { | 
 |             @Override | 
 |             protected void configure() { | 
 |                 bindFactory(HttpSessionFactory.class).to(HttpSession.class) | 
 |                    .proxy(true).proxyForSameScope(false).in(RequestScoped.class); | 
 |             } | 
 |         }); | 
 |     } | 
 | }</programlisting> | 
 |  | 
 |                 Note that if we did not define any explicit injection scope for the new injection binding, | 
 |                 By default, HK2 factories are bound in a HK2 &hk2.PerLookup; scope, which is in most | 
 |                 cases a good choice, and it is suitable also in our example. | 
 |             </para> | 
 |  | 
 |             <para> | 
 |                 To summarize the approach described above, here is a list of steps to follow | 
 |                 when implementing custom injection provider in your Jersey application : | 
 |  | 
 |                 <itemizedlist> | 
 |                     <listitem><simpara>Implement your own HK2 &lit.hk2.Factory; to provide the | 
 |                         injectable instances.</simpara></listitem> | 
 |                     <listitem><simpara>Use the HK2 &lit.hk2.Factory; to define an injection | 
 |                         binding for the injected instance via custom HK2 &lit.hk2.Binder;.</simpara></listitem> | 
 |                     <listitem><simpara>Register the custom HK2 &lit.hk2.Binder; in your application | 
 |                         &lit.jersey.server.ResourceConfig;.</simpara></listitem> | 
 |                 </itemizedlist> | 
 |             </para> | 
 |  | 
 |             <para> | 
 |                 While the &lit.hk2.Factory;-based approach is quite straight-forward and should help you to | 
 |                 quickly prototype or even implement final solutions, you should bear in mind, that your | 
 |                 implementation does not need to be based on factories. You can for instance bind your own | 
 |                 types directly, while still taking advantage of HK2 provided dependency injection. | 
 |                 Also, in your implementation you may want to pay more attention to defining or managing | 
 |                 injection binding scopes for the sake of performance or correctness of your custom injection | 
 |                 extension. | 
 |  | 
 |                 <important> | 
 |                     <para> | 
 |                         While the individual injection binding implementations vary and depend on your use case, | 
 |                         to enable your custom injection extension in Jersey, you must register your custom HK2 &hk2.Binder; | 
 |                         implementation in your application &jersey.server.ResourceConfig;! | 
 |                     </para> | 
 |                 </important> | 
 |             </para> | 
 |         </section> | 
 |         <section> | 
 |             <title>Injection Provider Using Jersey API</title> | 
 |             <para> | 
 |                 To make the <literal>HttpSession</literal> injection work without using HK2 API, | 
 |                 we will need to create a custom supplier that knows how to extract | 
 |                 &lit.jee9.servlet.HttpSession; out of given &lit.jee9.servlet.HttpServletRequest;. | 
 |  | 
 |                 <programlisting language="java">import java.util.function.Supplier | 
 |     ... | 
 |  | 
 | public class HttpSessionSupplier implements Supplier<HttpSession> { | 
 |  | 
 |     private final HttpServletRequest request; | 
 |  | 
 |     @Inject | 
 |     public HttpSessionSupplier(HttpServletRequest request) { | 
 |         this.request = request; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public HttpSession get() { | 
 |         return request.getSession(); | 
 |     } | 
 |  | 
 | }</programlisting> | 
 |  | 
 |                 Once implemented, the supplier can be used in a custom Jersey &jersey.common.internal.inject.AbstractBinder; | 
 |                 to define the new injection binding for &lit.jee9.servlet.HttpSession;. Finally, the implemented binder | 
 |                 can be registered in your &jersey.server.ResourceConfig;: | 
 |  | 
 |                 <programlisting language="java">import org.glassfish.jersey.internal.inject.AbstractBinder; | 
 |     ... | 
 | public class MyApplication extends ResourceConfig { | 
 |  | 
 |     public MyApplication() { | 
 |  | 
 |         ... | 
 |  | 
 |         register(new AbstractBinder() { | 
 |             @Override | 
 |             protected void configure() { | 
 |                 bindFactory(HttpSessionSupplier.class).to(HttpSession.class) | 
 |                     .proxy(true).proxyForSameScope(false).in(RequestScoped.class); | 
 |             } | 
 |         }); | 
 |     } | 
 | }</programlisting> | 
 |                    The default scope for Jersey binder is similarly as for the HK2, the | 
 |                 &jersey.common.internal.inject.PerLookup;. | 
 |             </para> | 
 |             <para> | 
 |                 To summarize the approach described above, here is a list of steps to follow | 
 |                 when implementing custom injection provider in your Jersey application : | 
 |  | 
 |                 <itemizedlist> | 
 |                     <listitem><simpara>Implement your own Supplier to provide the | 
 |                         injectable instances.</simpara></listitem> | 
 |                     <listitem><simpara>Use the Supplier to define an injection | 
 |                         binding for the injected instance via custom &jersey.common.internal.inject.AbstractBinder;. | 
 |                     </simpara></listitem> | 
 |                     <listitem><simpara>Register the custom &jersey.common.internal.inject.AbstractBinder; in your application | 
 |                         &lit.jersey.server.ResourceConfig;.</simpara></listitem> | 
 |                 </itemizedlist> | 
 |  | 
 |                 <important> | 
 |                     <para> | 
 |                         Similarly to the HK2, to enable your custom injection extension in Jersey, | 
 |                         you must register your custom &jersey.common.internal.inject.AbstractBinder; | 
 |                         implementation in your application &jersey.server.ResourceConfig;! | 
 |                     </para> | 
 |                 </important> | 
 |             </para> | 
 |         </section> | 
 |     </section> | 
 |  | 
 |     <section> | 
 |         <title>Defining Custom Injection Annotation</title> | 
 |  | 
 |         <para> | 
 |             Java annotations are a convenient way for attaching metadata to various elements of Java code. | 
 |             Sometimes you may even decide to combine the metadata with additional functionality, such as | 
 |             ability to automatically inject the instances based on the annotation-provided metadata. | 
 |             The described scenario is one of the use cases where having means of defining a custom injection | 
 |             annotation in your Jersey application may prove to be useful. Obviously, this use case applies also | 
 |             to re-used existing, 3rd-party annotation types. | 
 |         </para> | 
 |  | 
 |         <para> | 
 |             In the following example, we will describe how a custom injection annotation can be supported. | 
 |             Let's start with defining a new custom <literal>SessionInject</literal> injection annotation | 
 |             that we will specifically use to inject instances of &jee9.servlet.HttpSession; | 
 |             (similarly to the previous example): | 
 |  | 
 |             <programlisting language="java">@Retention(RetentionPolicy.RUNTIME) | 
 | @Target(ElementType.FIELD) | 
 | public @interface SessionInject { }</programlisting> | 
 |  | 
 |             The above <literal>@SessionInject</literal> annotation should be then used as follows: | 
 |  | 
 |             <programlisting language="java">@Path("di-resource") | 
 | public class MyDiResource { | 
 |  | 
 |     @SessionInject HttpSession httpSession; | 
 |  | 
 |     ... | 
 |  | 
 | }</programlisting> | 
 |  | 
 |             Again, the semantics remains the same as in the example described in the previous section. | 
 |             You want to have the actual HTTP Servlet session instance injected into your | 
 |             <literal>MyDiResource</literal> instance. This time however, you expect that the | 
 |             <literal>httpSession</literal> field to be injected must be annotated with | 
 |             a custom <literal>@SessionInject</literal> annotation. Obviously, in this simplistic case | 
 |             the use of a custom injection annotation is an overkill, however, the simplicity of the | 
 |             use case will help us to avoid use case specific distractions and allow us better focus on | 
 |             the important aspects of the job of defining a custom injection annotation. | 
 |         </para> | 
 |         <section> | 
 |             <title>Custom Injection Annotation using HK2</title> | 
 |  | 
 |         <para> | 
 |             If you remember from the previous section, to make the injection in the code snippet above work, | 
 |             you first need to implement the injection provider (HK2 &hk2.Factory;) as well as define the | 
 |             injection binding for the &lit.jee9.servlet.HttpSession; type. That part we have already | 
 |             done in the previous section. | 
 |             We will now focus on what needs to be done to inform the HK2 runtime about our <literal>@SessionInject</literal> | 
 |             annotation type that we want to support as a new injection point marker annotation. To do that, | 
 |             we need to implement our own HK2 &hk2.InjectionResolver; for the annotation as demonstrated | 
 |             in the following listing: | 
 |  | 
 |             <programlisting language="java">import jakarta.inject.Inject; | 
 | import jakarta.inject.Named; | 
 |  | 
 | import jakarta.servlet.http.HttpSession; | 
 |  | 
 | import org.glassfish.hk2.api.InjectionResolver; | 
 | import org.glassfish.hk2.api.ServiceHandle; | 
 |  | 
 | ... | 
 |  | 
 | public class SessionInjectResolver implements InjectionResolver<SessionInject> { | 
 |  | 
 |     @Inject | 
 |     @Named(InjectionResolver.SYSTEM_RESOLVER_NAME) | 
 |     InjectionResolver<Inject> systemInjectionResolver; | 
 |  | 
 |     @Override | 
 |     public Object resolve(Injectee injectee, ServiceHandle<?> handle) { | 
 |         if (HttpSession.class == injectee.getRequiredType()) { | 
 |             return systemInjectionResolver.resolve(injectee, handle); | 
 |         } | 
 |  | 
 |         return null; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public boolean isConstructorParameterIndicator() { | 
 |         return false; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public boolean isMethodParameterIndicator() { | 
 |         return false; | 
 |     } | 
 | }</programlisting> | 
 |  | 
 |             The <literal>SessionInjectResolver</literal> above just delegates to the default | 
 |             HK2 system injection resolver to do the actual work. | 
 |         </para> | 
 |  | 
 |         <para> | 
 |             You again need to register your injection resolver with your Jersey application, | 
 |             and you can do it the same was as in the previous case. Following listing includes | 
 |             HK2 binder that registers both, the injection provider from the previous step | 
 |             as well as the new HK2 inject resolver with Jersey application &lit.jersey.server.ResourceConfig;. | 
 |             Note that in this case we're explicitly binding the <literal>SessionInjectResolver</literal> | 
 |             to a &jee9.inject.Singleton; scope to avoid the unnecessary proliferation of | 
 |             <literal>SessionInjectResolver</literal> instances in the application: | 
 |  | 
 |             <programlisting language="java">import org.glassfish.hk2.api.TypeLiteral; | 
 | import org.glassfish.hk2.utilities.binding.AbstractBinder; | 
 |  | 
 | import jakarta.inject.Singleton; | 
 |  | 
 | ... | 
 |  | 
 | public class MyApplication extends ResourceConfig { | 
 |  | 
 |     public MyApplication() { | 
 |  | 
 |         ... | 
 |  | 
 |         register(new AbstractBinder() { | 
 |             @Override | 
 |             protected void configure() { | 
 |                 bindFactory(HttpSessionFactory.class).to(HttpSession.class); | 
 |  | 
 |                 bind(SessionInjectResolver.class) | 
 |                     .to(new TypeLiteral<InjectionResolver<SessionInject>>(){}) | 
 |                     .in(Singleton.class); | 
 |             } | 
 |         }); | 
 |     } | 
 | }</programlisting> | 
 |         </para> | 
 |         </section> | 
 |         <section> | 
 |             <title>Custom Injection Annotation using Jersey InjectionResolver</title> | 
 |  | 
 |             <para> | 
 |                 Jersey also comes with its &jersey.common.internal.inject.InjectionResolver; used to translate into | 
 |                 the HK2 &hk2.InjectionResolver; during runtime. The abstraction is important for allowing to support | 
 |                 the custom injection annotation in various DI containers. For instance, the abstraction is used when | 
 |                 supporting injection using &jaxrs.core.Context; in the CDI container (<literal>jersey-cdi2-se</literal> module). | 
 |             </para> | 
 |             <para> | 
 |                 The SessionInjectResolver then looks as follows: | 
 | <programlisting language="java">import jakarta.inject.Inject; | 
 |  | 
 | import jakarta.servlet.http.HttpSession; | 
 |  | 
 | import org.glassfish.jersey.internal.inject.InjectionResolver; | 
 |  | 
 | ... | 
 |  | 
 | public class SessionInjectResolver implements InjectionResolver<SessionInject> { | 
 |  | 
 |     private final InjectionManger injectionManager; | 
 |  | 
 |     public SessionInjectResolver(InjectionManager) { | 
 |         this.injectionManager = injectionManager; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public Object resolve(Injectee injectee) { | 
 |         if (HttpSession.class == injectee.getRequiredType()) { | 
 |             return injectionManager.getInstance(HttpServletRequest.class).getSession(); | 
 |         } | 
 |         return null; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public boolean isConstructorParameterIndicator() { | 
 |         return false; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public boolean isMethodParameterIndicator() { | 
 |         return false; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public Class<SessionInject> getAnnotation() { | 
 |         return SessionInject.class; | 
 |     } | 
 | }</programlisting> | 
 |  | 
 |                 The SessionInjectResolver uses &jersey.common.internal.inject.InjectionManager; described in | 
 |                 <xref linkend="injection.manager"/>. | 
 |             </para> | 
 |             <para> | 
 |                 Unlike with &hk2.link;, Jersey &jersey.common.internal.inject.InjectionResolver; can only be bound | 
 |                 as instance in the &jersey.common.internal.inject.AbstractBinder;. That is why the | 
 |                 &jersey.common.internal.inject.InjectionManager; is used in the <literal>InjectionResolver</literal> | 
 |                 to resolve the <literal>HttpSession</literal> instance. | 
 |             </para> | 
 |             <para> | 
 |                 The &jersey.common.internal.inject.InjectionResolver; can be registered in the with Jersey application | 
 |                 &lit.jersey.server.ResourceConfig; as follows: | 
 |  | 
 | <programlisting language="java">import jakarta.ws.rs.core.Feature; | 
 |  | 
 | import org.glassfish.jersey.InjectionManagerProvider; | 
 | import org.glassfish.jersey.internal.inject.AbstractBinder; | 
 | import org.glassfish.jersey.internal.inject.InjectionManager; | 
 |  | 
 |  | 
 | import jakarta.inject.Singleton; | 
 |  | 
 | ... | 
 |  | 
 | public class MyApplication extends ResourceConfig { | 
 |  | 
 | public MyApplication() { | 
 |  | 
 |     ... | 
 |  | 
 |     register(new Feature() { | 
 |         @Override | 
 |         public boolean configure(FeatureContext context) { | 
 |             final InjectionManager injectionManager = InjectionManagerProvider.getInjectionManager(context); | 
 |             context.register(new AbstractBinder() { | 
 |                 @Override | 
 |                 protected void configure() { | 
 |                     bind(new SessionInjectResolver(injectionManager)).to(HttpSession.class).in(Singleton.class); | 
 |                 } | 
 |             }); | 
 |             return true; | 
 |         } | 
 |     }); | 
 | }</programlisting> | 
 |             </para> | 
 |         </section> | 
 |     </section> | 
 |  | 
 |     <section> | 
 |         <title>Custom Life Cycle Management</title> | 
 |  | 
 |         <para> | 
 |             The last use case discussed in this chapter will cover managing custom-scoped components | 
 |             within a Jersey application. | 
 |             If not configured otherwise, then all JAX-RS resources are by default managed on a per-request basis. A new instance | 
 |             of given resource class will be created for each incoming request that should be handled by that resource class. | 
 |             Let say you want to have your resource class managed in a per-session manner. It means a new instance of your | 
 |             resource class should be created only when a new Servlet &jee9.servlet.HttpSession; is established. | 
 |             (As with previous examples in the chapter, this example assumes the deployment of your application | 
 |             to a Servlet container.) | 
 |         </para> | 
 |  | 
 |         <para> | 
 |             Following is an example of such a resource class that builds on the support for | 
 |             &lit.jee9.servlet.HttpSession; injection from the earlier examples described in this chapter. | 
 |             The <literal>PerSessionResource</literal> class allows you to count the number of requests made within | 
 |             a single client session and provides you a handy sub-resource method to obtain the number via | 
 |             a HTTP &lit.http.GET; method call: | 
 |  | 
 |             <programlisting language="java">@Path("session") | 
 | public class PerSessionResource { | 
 |  | 
 |     @SessionInject HttpSession httpSession; | 
 |  | 
 |     AtomicInteger counter = new AtomicInteger(); | 
 |  | 
 |     @GET | 
 |     @Path("id") | 
 |     public String getSession() { | 
 |         counter.incrementAndGet(); | 
 |         return httpSession.getId(); | 
 |     } | 
 |  | 
 |     @GET | 
 |     @Path("count") | 
 |     public int getSessionRequestCount() { | 
 |         return counter.incrementAndGet(); | 
 |     } | 
 | }</programlisting> | 
 |  | 
 |             Should the above resource be per-request scoped (default option), you would never be able to obtain | 
 |             any other number but 1 from it's getReqs sub-resource method, because then for each request | 
 |             a new instance of our <literal>PerSessionResource</literal> class would get created with a fresh | 
 |             instance <literal>counter</literal> field set to 0. | 
 |             The value of this field would get incremented to 1 in the the <literal>getSessionRequestCount</literal> | 
 |             method before this value is returned. | 
 |             In order to achieve what we want, we have to find a way how to bind the instances of | 
 |             our <literal>PerSessionResource</literal> class to &lit.jee9.servlet.HttpSession; instances and | 
 |             then reuse those bound instances whenever new request bound to the same HTTP client session arrives. | 
 |             Let's see how to achieve this. | 
 |         </para> | 
 |  | 
 |         <para> | 
 |             To get better control over your Jersey component instantiation and life cycle, | 
 |             you need to implement a custom Jersey &jersey.server.spi.ComponentProvider; SPI, | 
 |             that would manage your custom components. | 
 |             Although it might seem quite complex to implement such a thing, | 
 |             the component provider concept in Jersey is in fact very simple. It allows you to define | 
 |             your own HK2 injection bindings for the types that you are interested in, | 
 |             while informing the Jersey runtime at the same time that it should back out and leave | 
 |             the component management to your provider in such a case. | 
 |             By default, if there is no custom component provider found for any given component type, Jersey | 
 |             runtime assumes the role of the default component provider and automatically defines the default | 
 |             HK2 binding for the component type. | 
 |         </para> | 
 |  | 
 |         <para> | 
 |             Following example shows a simple &lit.jersey.server.spi.ComponentProvider; implementation, | 
 |             for our use case. Some comments on the code follow. | 
 |  | 
 |             <programlisting language="java">import jakarta.inject.Inject; | 
 | import jakarta.inject.Provider; | 
 | import jakarta.servlet.http.HttpServletRequest; | 
 | import jakarta.servlet.http.HttpSession; | 
 | ... | 
 | import org.glassfish.hk2.api.DynamicConfiguration; | 
 | import org.glassfish.hk2.api.DynamicConfigurationService; | 
 | import org.glassfish.hk2.api.Factory; | 
 | import org.glassfish.hk2.api.PerLookup; | 
 | import org.glassfish.hk2.api.ServiceLocator; | 
 | import org.glassfish.hk2.utilities.binding.BindingBuilderFactory; | 
 | import org.glassfish.jersey.server.spi.ComponentProvider; | 
 |  | 
 | @jakarta.ws.rs.ext.Provider | 
 | public class PerSessionComponentProvider implements ComponentProvider { | 
 |  | 
 |     private ServiceLocator locator; | 
 |  | 
 |     static class PerSessionFactory implements Factory<PerSessionResource>{ | 
 |         static ConcurrentHashMap<String, PerSessionResource> perSessionMap | 
 |                 = new ConcurrentHashMap<String, PerSessionResource>(); | 
 |  | 
 |  | 
 |         private final Provider<HttpServletRequest> requestProvider; | 
 |         private final ServiceLocator locator; | 
 |  | 
 |         @Inject | 
 |         public PerSessionFactory( | 
 |                 Provider<HttpServletRequest> request, | 
 |                 ServiceLocator locator) { | 
 |  | 
 |             this.requestProvider = request; | 
 |             this.locator = locator; | 
 |         } | 
 |  | 
 |         @Override | 
 |         @PerLookup | 
 |         public PerSessionResource provide() { | 
 |             final HttpSession session = requestProvider.get().getSession(); | 
 |  | 
 |             if (session.isNew()) { | 
 |                 PerSessionResource newInstance = createNewPerSessionResource(); | 
 |                 perSessionMap.put(session.getId(), newInstance); | 
 |  | 
 |                 return newInstance; | 
 |             } else { | 
 |                 return perSessionMap.get(session.getId()); | 
 |             } | 
 |         } | 
 |  | 
 |         @Override | 
 |         public void dispose(PerSessionResource r) { | 
 |         } | 
 |  | 
 |         private PerSessionResource createNewPerSessionResource() { | 
 |             final PerSessionResource perSessionResource = new PerSessionResource(); | 
 |             locator.inject(perSessionResource); | 
 |             return perSessionResource; | 
 |         } | 
 |     } | 
 |  | 
 |     @Override | 
 |     public void initialize(ServiceLocator locator) { | 
 |         this.locator = locator; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public boolean bind(Class<?> component, Set<Class<?>> providerContracts) { | 
 |         if (component == PerSessionResource.class) { | 
 |  | 
 |             final DynamicConfigurationService dynamicConfigService = | 
 |                 locator.getService(DynamicConfigurationService.class); | 
 |             final DynamicConfiguration dynamicConfiguration = | 
 |                 dynamicConfigService.createDynamicConfiguration(); | 
 |  | 
 |             BindingBuilderFactory | 
 |                 .addBinding(BindingBuilderFactory.newFactoryBinder(PerSessionFactory.class) | 
 |                 .to(PerSessionResource.class), dynamicConfiguration); | 
 |  | 
 |             dynamicConfiguration.commit(); | 
 |  | 
 |             return true; | 
 |         } | 
 |         return false; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public void done() { | 
 |     } | 
 | }</programlisting> | 
 |         </para> | 
 |  | 
 |         <para> | 
 |             The first and very important aspect of writing your own &lit.jersey.server.spi.ComponentProvider; | 
 |             in Jersey is to store the actual HK2 &hk2.ServiceLocator; instance that will be passed to you as | 
 |             the only argument of the provider <literal>initialize</literal> method. | 
 |             Your component provider instance will not get injected at all so this is more or less your only chance | 
 |             to get access to the HK2 runtime of your application. Please bear in mind, that at the time when | 
 |             your component provider methods get invoked, the &lit.hk2.ServiceLocator; is not fully configured yet. | 
 |             This limitation applies to all component provider methods, as the main goal of any component provider | 
 |             is to take part in configuring the application's &lit.hk2.ServiceLocator;. | 
 |         </para> | 
 |  | 
 |         <para> | 
 |             Now let's examine the <literal>bind</literal> method, which is where your provider tells the HK2 | 
 |             how to bind your component. | 
 |             Jersey will invoke this method multiple times, once for each type that is registered with the | 
 |             actual application. | 
 |             Every time the <literal>bind</literal> method is invoked, your component provider needs to decide | 
 |             if it is taking control over the component or not. In our case we know exactly which Java type | 
 |             we are interested in (<literal>PerSessionResource</literal> class), | 
 |             so the logic in our <literal>bind</literal> method is quite straightforward. If we see our | 
 |             <literal>PerSessionResource</literal> class it is our turn to provide our custom binding for the class, | 
 |             otherwise we just return false to make Jersey poll other providers and, if no provider kicks in, | 
 |             eventually provide the default HK2 binding for the component. | 
 |             Please, refer to the &hk2.link; documentation for the details of the concrete HK2 APIs used in | 
 |             the <literal>bind</literal> method implementation above. The main idea behind the code is that | 
 |             we register a new HK2 &hk2.Factory; (<literal>PerSessionFactory</literal>), to provide | 
 |             the <literal>PerSessionResource</literal> instances to HK2. | 
 |         </para> | 
 |  | 
 |         <para> | 
 |             The implementation of the <literal>PerSessionFactory</literal> is also included above. | 
 |             Please note that as opposed to a component provider implementation that should never itself rely | 
 |             on an injection support, the factory bound by our component provider would get injected just fine, | 
 |             since it is only instantiated later, once the Jersey runtime for the application is fully | 
 |             initialized including the fully configured HK2 runtime. | 
 |             Whenever a new session is seen, the factory instantiates and injects | 
 |             a new PerSessionResource instance. The instance is then stored in the perSessionMap for later use | 
 |             (for future calls). | 
 |         </para> | 
 |  | 
 |         <para> | 
 |             In a real life scenario, you would want to pay more attention to possible synchronization issues. | 
 |             Also, we do not consider a mechanism that would clean-up any obsolete resources for closed, expired or | 
 |             otherwise invalidated HTTP client sessions. | 
 |             We have omitted those considerations here for the sake of brevity of our example. | 
 |         </para> | 
 |     </section> | 
 | </chapter> |