public class FilterSpec {
    public static final Comparator<FilterSpec> PRIORITY_COMPARATOR = new Comparator<FilterSpec>() {
        @Override
        public int compare(FilterSpec o1, FilterSpec o2) {
            return o1.getPriority() - o2.getPriority();
        }
    };

    private final Provider<? extends Filter> filterProvider;
    private final int priority;
    private final String name;
    private final ImmutableList<FilterPattern> patterns;

    FilterSpec(
            Provider<? extends Filter> filterProvider,
            int priority,
            String name,
            ImmutableList<FilterPattern> patterns) {

        this.filterProvider = Preconditions.checkNotNull(filterProvider, "Filter Provider cannot be null.");
        this.priority = Preconditions.checkNotNull(priority, "Priority cannot be null.");
        this.name = Preconditions.checkNotNull(name, "Name cannot be null.");
        this.patterns = Preconditions.checkNotNull(patterns, "Filter Patterns cannot be null.");
    }

    public Filter getFilter() {
        return filterProvider.get();
    }

    /**
     * The priority is used to determine the order of the filters added to the {@link io.dropwizard.setup.Environment}.
     *
     * @return The filter's priority.
     */
    public int getPriority() {
        return priority;
    }

    public String getName() {
        return name;
    }

    public ImmutableList<FilterPattern> getPatterns() {
        return patterns;
    }
} public final class Keys {

    protected Keys() {
        // utility class
    }

    // ===================
    // Guice Injector Keys
    // ===================

    // Managed Objects
    public static final Key<Set<Managed>> ManagedObjects = Key.get(TypeLiterals.ManagedSet, Graceland.class);
    public static final Key<Set<Class<? extends Managed>>> ManagedObjectClasses = Key.get(TypeLiterals.ManagedClassSet, Graceland.class);

    // Jersey Components
    public static final Key<Set<Object>> JerseyComponents = Key.get(TypeLiterals.ObjectSet, Graceland.class);

    // Health Checks
    public static final Key<Set<HealthCheck>> HealthChecks = Key.get(TypeLiterals.HealthCheckSet, Graceland.class);
    public static final Key<Set<Class<? extends HealthCheck>>> HealthCheckClasses = Key.get(TypeLiterals.HealthCheckClassSet, Graceland.class);

    // Tasks
    public static final Key<Set<Task>> Tasks = Key.get(TypeLiterals.TaskSet, Graceland.class);
    public static final Key<Set<Class<? extends Task>>> TaskClasses = Key.get(TypeLiterals.TaskClassSet, Graceland.class);

    // Bundles
    public static final Key<Set<Bundle>> Bundles = Key.get(TypeLiterals.BundleSet, Graceland.class);
    public static final Key<Set<Class<? extends Bundle>>> BundleClasses = Key.get(TypeLiterals.BundleClassSet, Graceland.class);

    // Commands
    public static final Key<Set<Command>> Commands = Key.get(TypeLiterals.CommandSet, Graceland.class);
    public static final Key<Set<Class<? extends Command>>> CommandClasses = Key.get(TypeLiterals.CommandClassSet, Graceland.class);

    // Initializers
    public static final Key<Set<Initializer>> Initializers = Key.get(TypeLiterals.InitializerSet, Graceland.class);
    public static final Key<Set<Class<? extends Initializer>>> InitializerClasses = Key.get(TypeLiterals.InitializerClassSet, Graceland.class);

    // Configurators
    public static final Key<Set<Configurator>> Configurators = Key.get(TypeLiterals.ConfiguratorSet, Graceland.class);
    public static final Key<Set<Class<? extends Configurator>>> ConfiguratorClasses = Key.get(TypeLiterals.ConfiguratorClassSet, Graceland.class);

    // Filter Specs
    public static final Key<Set<FilterSpec>> FilterSpecs = Key.get(TypeLiterals.FilterSpecSet, Graceland.class);
} public class TestBundle implements Bundle {
    @Override
    public void initialize(Bootstrap<?> bootstrap) {
        // do nothing
    }

    @Override
    public void run(Environment environment) {
        // do nothing
    }
} public class TestCommand extends Command {
    public TestCommand() {
        super("name", "description");
    }

    @Override
    public void configure(Subparser subparser) {
        // do nothing
    }

    @Override
    public void run(Bootstrap<?> bootstrap, Namespace namespace) throws Exception {
        // do nothing
    }
} public class TestConfiguration implements Configuration {
} public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // do nothing
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // do nothing
    }

    @Override
    public void destroy() {
        // do nothing
    }
} public class TestHealthCheck extends HealthCheck {
    @Override
    protected Result check() throws Exception {
        return Result.healthy();
    }
} public class TestManaged implements Managed {
    @Override
    public void start() throws Exception {
        // do nothing
    }

    @Override
    public void stop() throws Exception {
        // do nothing
    }
} @Path("/api")
public class TestResource {
    @GET
    public String hello() {
        return "world";
    }
} public class TestTask extends Task {
    public TestTask() {
        super("test-task");
    }

    @Override
    public void execute(ImmutableMultimap<String, String> parameters, PrintWriter output) throws Exception {
        // do nothing
    }
}
import java.util.Set;
import javax.servlet.Filter;
import org.junit.Test;
import com.codahale.metrics.health.HealthCheck;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import io.dropwizard.Bundle;
import io.dropwizard.cli.Command;
import io.dropwizard.lifecycle.Managed;
import io.dropwizard.servlets.tasks.Task;
import io.graceland.filter.FilterSpec;
import io.graceland.inject.Keys;
import io.graceland.testing.TestBundle;
import io.graceland.testing.TestCommand;
import io.graceland.testing.TestConfiguration;
import io.graceland.testing.TestFilter;
import io.graceland.testing.TestHealthCheck;
import io.graceland.testing.TestManaged;
import io.graceland.testing.TestResource;
import io.graceland.testing.TestTask;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
                bindManaged(managedClass);
            }
        });

        Set<Managed> managedSet = injector.getInstance(Keys.ManagedObjects);
        Set<Class<? extends Managed>> managedClassSet = injector.getInstance(Keys.ManagedObjectClasses);

        assertThat(managedSet, hasSize(1));
        assertThat(managedSet, hasItem(managed));
        assertThat(managedClassSet, hasSize(1));
        assertThat(managedClassSet, hasItem(TestManaged.class));
    }

    @Test
    public void healthcheck_binds_work() {
        final HealthCheck healthCheck = mock(HealthCheck.class);
        final Class<TestHealthCheck> healthCheckClass = TestHealthCheck.class;

        Injector injector = Guice.createInjector(new AbstractPlugin() {
            @Override
            protected void configure() {
                bindHealthCheck(healthCheck);
                bindHealthCheck(healthCheckClass);
            }
        });

        Set<HealthCheck> healthCheckSet = injector.getInstance(Keys.HealthChecks);
        Set<Class<? extends HealthCheck>> healthCheckClassSet = injector.getInstance(Keys.HealthCheckClasses);

        assertThat(healthCheckSet, hasSize(1));
        assertThat(healthCheckSet, hasItem(healthCheck));
        assertThat(healthCheckClassSet, hasSize(1));
        assertThat(healthCheckClassSet, hasItem(TestHealthCheck.class));
    }

    @Test
    public void task_binds_work() {
        final Task task = mock(Task.class);
        final Class<TestTask> taskClass = TestTask.class;

        Injector injector = Guice.createInjector(new AbstractPlugin() {
            @Override
            protected void configure() {
                bindTask(task);
                bindTask(taskClass);
            }
        });

        Set<Task> taskSet = injector.getInstance(Keys.Tasks);
        Set<Class<? extends Task>> taskClassSet = injector.getInstance(Keys.TaskClasses);

        assertThat(taskSet, hasSize(1));
        assertThat(taskSet, hasItem(task));
        assertThat(taskClassSet, hasSize(1));
        assertThat(taskClassSet, hasItem(TestTask.class));
    }

    @Test
    public void bundle_binds_work() {
        final Bundle bundle = mock(Bundle.class);
        final Class<TestBundle> bundleClass = TestBundle.class;

        Injector injector = Guice.createInjector(new AbstractPlugin() {
            @Override
            protected void configure() {
                bindBundle(bundle);
                bindBundle(bundleClass);
            }
        });

        Set<Bundle> bundleSet = injector.getInstance(Keys.Bundles);
        Set<Class<? extends Bundle>> bundleClassSet = injector.getInstance(Keys.BundleClasses);

        assertThat(bundleSet, hasSize(1));
        assertThat(bundleSet, hasItem(bundle));
        assertThat(bundleClassSet, hasSize(1));
        assertThat(bundleClassSet, hasItem(TestBundle.class));
    }

    @Test
    public void command_binds_work() {
        final Command command = mock(Command.class);
        final Class<TestCommand> commandClass = TestCommand.class;

        Injector injector = Guice.createInjector(new AbstractPlugin() {
            @Override
            protected void configure() {
                bindCommand(command);
                bindCommand(commandClass);
            }
        });

        Set<Command> commandSet = injector.getInstance(Keys.Commands);
        Set<Class<? extends Command>> commandClassSet = injector.getInstance(Keys.CommandClasses);

        assertThat(commandSet, hasSize(1));
        assertThat(commandSet, hasItem(command));
        assertThat(commandClassSet, hasSize(1));
        assertThat(commandClassSet, hasItem(TestCommand.class));
    }

    @Test
    public void configuration_binds_work() {
        final TestConfiguration testConfiguration = new TestConfiguration();

        Injector injector = Guice.createInjector(new AbstractPlugin() {
            @Override
            protected void configure() {
                bindConfiguration(TestConfiguration.class).toInstance(testConfiguration);
            }
        });

        TestConfiguration actualConfiguration = injector.getInstance(Key.get(TestConfiguration.class));

        assertThat(actualConfiguration, is(testConfiguration));
    }

    @Test
    public void filter_binds_work() {
        final Filter filter = mock(Filter.class);
        final Class<TestFilter> filterClass = TestFilter.class;