package ru.vyarus.dropwizard.guice.module.jersey; import com.google.common.base.Preconditions; import com.google.inject.Injector; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.jersey.ServiceLocatorProvider; import ru.vyarus.dropwizard.guice.module.context.stat.StatsTracker; import ru.vyarus.dropwizard.guice.module.installer.scanner.InvisibleForScanner; import ru.vyarus.dropwizard.guice.module.jersey.hk2.GuiceBridgeActivator; import ru.vyarus.dropwizard.guice.module.jersey.hk2.InstallerBinder; import javax.inject.Provider; import javax.ws.rs.core.Feature; import javax.ws.rs.core.FeatureContext; import static ru.vyarus.dropwizard.guice.module.context.stat.Stat.HKTime; /** * Feature activates guice integration. * <p>Guice context is created first and it doesn't depend on jersey start. First of all this allow using guice * in commands and second, guice is ready in time of jersey initialization and so can provide it's own instances * into jersey config.</p> * <p>Feature must be registered in jersey before it's start: * {@code environment.jersey().register(new GuiceFeature())}</p> * <p>During juice context start special jersey bindings module registered * {@link ru.vyarus.dropwizard.guice.module.jersey.hk2.GuiceBindingsModule}, which lazily binds jersey specific * types to guice context. This types could be used in guice only after actual integration * (this feature activation)</p> * <p>HK-guice bridge is activated when {@link ru.vyarus.dropwizard.guice.GuiceyOptions#UseHkBridge} option enabled * (not bi-directional). By default, it's disabled because most cases does not require it: it was * developed for cases when bean is created by HK and only need some injections from guice, but here guice * controls almost everything and prepared instance is passed to guice. But bridge may be useful together with * {@link ru.vyarus.dropwizard.guice.module.installer.feature.jersey.HK2Managed} instances.</p> * <p>Feature installs {@code ru.vyarus.dropwizard.guice.module.jersey.hk2.InstallerBinder}, which is HK module. * Just like with guice ({@code BindingInstaller)}, it asks all {@code JerseyInstaller} to bind extensions into * HK context.</p> * * @author Vyacheslav Rusakov * @see ru.vyarus.dropwizard.guice.module.jersey.support.JerseyComponentProvider * @see ru.vyarus.dropwizard.guice.module.jersey.support.GuiceComponentFactory * @see ru.vyarus.dropwizard.guice.module.jersey.support.LazyGuiceFactory * @since 21.11.2014 */ @InvisibleForScanner public class GuiceFeature implements Feature, Provider<ServiceLocator> { private final Provider<Injector> provider; private final StatsTracker tracker; private final boolean enableBridge; private ServiceLocator locator; public GuiceFeature(final Provider<Injector> provider, final StatsTracker tracker, final boolean enableBridge) { this.provider = provider; this.tracker = tracker; this.enableBridge = enableBridge; } @Override public boolean configure(final FeatureContext context) { tracker.startHkTimer(HKTime); locator = ServiceLocatorProvider.getServiceLocator(context); final Injector injector = this.provider.get(); if (enableBridge) { new GuiceBridgeActivator(locator, injector).activate(); } context.register(new InstallerBinder(injector, tracker)); tracker.stopHkTimer(HKTime); return true; } @Override public ServiceLocator get() { return Preconditions.checkNotNull(locator, "Service locator is not yet available"); } }