package ru.vyarus.dropwizard.guice.module; import com.google.inject.AbstractModule; import io.dropwizard.Configuration; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; import ru.vyarus.dropwizard.guice.module.context.ConfigurationContext; import ru.vyarus.dropwizard.guice.module.context.ConfigurationInfo; import ru.vyarus.dropwizard.guice.module.context.option.Options; import ru.vyarus.dropwizard.guice.module.context.option.OptionsInfo; import ru.vyarus.dropwizard.guice.module.context.stat.StatsInfo; import ru.vyarus.dropwizard.guice.module.installer.InstallerModule; import ru.vyarus.dropwizard.guice.module.installer.scanner.ClasspathScanner; import ru.vyarus.dropwizard.guice.module.jersey.Jersey2Module; import ru.vyarus.dropwizard.guice.module.support.BootstrapAwareModule; import ru.vyarus.dropwizard.guice.module.support.ConfigurationAwareModule; import ru.vyarus.dropwizard.guice.module.support.EnvironmentAwareModule; import javax.inject.Singleton; import static ru.vyarus.dropwizard.guice.GuiceyOptions.BindConfigurationInterfaces; /** * Bootstrap integration guice module. * <ul> * <li>Registers bootstrap, configuration and environment in injector</li> * <li>Installs jersey guice extension (to register resources instantiated with guice into jersey) and registers * guice filter</li> * <li>Starts auto scanning, if enabled (for automatic features installation)</li> * </ul> * Configuration is mapped as: * <ul> * <li>Root configuration class (e.g. {@code MyAppConfiguration extends Configuration})</li> * <li>Dropwizard {@link Configuration} class</li> * <li>All classes in hierarchy between root and {@link Configuration} (e.g. * {@code MyAppConfiguration extends MyBaseConfiguration extends Configuration}</li> * <li>All interfaces implemented directly by classes in configuration hierarchy except interfaces from * 'java' package (e.g. {@code MyBaseConfiguration implements HasMyOtherConfig})</li> * </ul> * Interface binding could be disabled using {@code bindConfigurationInterfaces} bundle option. * * @param <T> configuration type * @author Vyacheslav Rusakov * @since 31.08.2014 */ public class GuiceSupportModule<T extends Configuration> extends AbstractModule implements BootstrapAwareModule<T>, EnvironmentAwareModule, ConfigurationAwareModule<T> { private final ClasspathScanner scanner; private final ConfigurationContext context; private Bootstrap<T> bootstrap; private T configuration; private Environment environment; public GuiceSupportModule(final ClasspathScanner scanner, final ConfigurationContext context) { this.scanner = scanner; this.context = context; } @Override public void setBootstrap(final Bootstrap<T> bootstrap) { this.bootstrap = bootstrap; } @Override public void setConfiguration(final T configuration) { this.configuration = configuration; } @Override public void setEnvironment(final Environment environment) { this.environment = environment; } @Override protected void configure() { bindEnvironment(); install(new InstallerModule(scanner, context)); install(new Jersey2Module(bootstrap.getApplication(), environment, context)); // let guice beans use options the same way as bundles (with usage tracking) bind(Options.class).toInstance(new Options(context.options())); // provide access for configuration info collected during startup bind(ConfigurationInfo.class).toInstance(new ConfigurationInfo(context)); bind(StatsInfo.class).toInstance(new StatsInfo(context.stat())); bind(OptionsInfo.class).toInstance(new OptionsInfo(context.options())); bind(GuiceyConfigurationInfo.class).in(Singleton.class); } /** * Bind bootstrap, configuration and environment objects to be able to use them * as injectable. */ private void bindEnvironment() { bind(Bootstrap.class).toInstance(bootstrap); bind(Environment.class).toInstance(environment); bindConfig(configuration.getClass()); } /** * Bind configuration hierarchy: all superclasses and direct interfaces for each level (except interfaces * from java package). * * @param type configuration type */ @SuppressWarnings("unchecked") private void bindConfig(final Class type) { bind(type).toInstance(configuration); if (type == Configuration.class) { return; } if (context.option(BindConfigurationInterfaces)) { for (Class iface : type.getInterfaces()) { final String pkg = iface.getPackage().getName(); if (pkg.startsWith("java.") || pkg.startsWith("groovy.")) { continue; } bind(iface).toInstance(configuration); } } bindConfig(type.getSuperclass()); } }