Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 244 additions & 0 deletions api/src/main/java/io/druid/guice/ConditionalMultibind.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
/*
* Licensed to Metamarkets Group Inc. (Metamarkets) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Metamarkets licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package io.druid.guice;

import com.google.common.base.Predicate;
import com.google.inject.Binder;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.Multibinder;

import java.lang.annotation.Annotation;
import java.util.Properties;

/**
* Provides the ability to conditionally bind an item to a set. The condition is based on the value set in the
* runtime.properties.
*
* Usage example:
*
* ConditionalMultibind.create(props, binder, Animal.class)
* .addConditionBinding("animal.type", Predicates.equalTo("cat"), Cat.class)
* .addConditionBinding("animal.type", Predicates.equalTo("dog"), Dog.class);
*
* At binding time, this will check the value set for property "animal.type" in props. If the value is "cat", it will
* add a binding to Cat.class. If the value is "dog", it will add a binding to Dog.class.
*
* At injection time, you will get the items that satisfy their corresponding predicates by calling
* injector.getInstance(Key.get(new TypeLiteral<Set<Animal>>(){}))
*/
public class ConditionalMultibind<T>
{

/**
* Create a ConditionalMultibind that resolves items to be added to the set at "binding" time.
*
* @param properties the runtime properties.
* @param binder the binder for the injector that is being configured.
* @param type the type that will be injected.
* @param <T> interface type.
*
* @return An instance of ConditionalMultibind that can be used to add conditional bindings.
*/
public static <T> ConditionalMultibind<T> create(Properties properties, Binder binder, Class<T> type)
{
return new ConditionalMultibind<T>(properties, Multibinder.<T>newSetBinder(binder, type));
}

/**
* Create a ConditionalMultibind that resolves items to be added to the set at "binding" time.
*
* @param properties the runtime properties.
* @param binder the binder for the injector that is being configured.
* @param type the type that will be injected.
* @param <T> interface type.
* @param annotationType the binding annotation.
*
* @return An instance of ConditionalMultibind that can be used to add conditional bindings.
*/
public static <T> ConditionalMultibind<T> create(
Properties properties,
Binder binder,
Class<T> type,
Class<? extends Annotation> annotationType
)
{
return new ConditionalMultibind<T>(properties, Multibinder.<T>newSetBinder(binder, type, annotationType));
}

/**
* Create a ConditionalMultibind that resolves items to be added to the set at "binding" time.
*
* @param properties the runtime properties.
* @param binder the binder for the injector that is being configured.
* @param type the type that will be injected.
* @param <T> interface type.
*
* @return An instance of ConditionalMultibind that can be used to add conditional bindings.
*/
public static <T> ConditionalMultibind<T> create(Properties properties, Binder binder, TypeLiteral<T> type)
{
return new ConditionalMultibind<T>(properties, Multibinder.<T>newSetBinder(binder, type));
}

/**
* Create a ConditionalMultibind that resolves items to be added to the set at "binding" time.
*
* @param properties the runtime properties.
* @param binder the binder for the injector that is being configured.
* @param type the type that will be injected.
* @param <T> interface type.
* @param annotationType the binding annotation.
*
* @return An instance of ConditionalMultibind that can be used to add conditional bindings.
*/
public static <T> ConditionalMultibind<T> create(
Properties properties,
Binder binder,
TypeLiteral<T> type,
Class<? extends Annotation> annotationType
)
{
return new ConditionalMultibind<T>(properties, Multibinder.<T>newSetBinder(binder, type, annotationType));
}


private final Properties properties;
private final Multibinder<T> multibinder;

public ConditionalMultibind(Properties properties, Multibinder<T> multibinder)
{
this.properties = properties;
this.multibinder = multibinder;
}

/**
* Unconditionally bind target to the set.
*
* @param target the target class to which it adds a binding.
*
* @return self to support a continuous syntax for adding more conditional bindings.
*/
public ConditionalMultibind<T> addBinding(Class<? extends T> target)
{
multibinder.addBinding().to(target);
return this;
}

/**
* Unconditionally bind target to the set.
*
* @param target the target instance to which it adds a binding.
*
* @return self to support a continuous syntax for adding more conditional bindings.
*/
public ConditionalMultibind<T> addBinding(T target)
{
multibinder.addBinding().toInstance(target);
return this;
}

/**
* Unconditionally bind target to the set.
*
* @param target the target type to which it adds a binding.
*
* @return self to support a continuous syntax for adding more conditional bindings.
*/
public ConditionalMultibind<T> addBinding(TypeLiteral<T> target)
{
multibinder.addBinding().to(target);
return this;
}

/**
* Conditionally bind target to the set. If "condition" returns true, add a binding to "target".
*
* @param property the property to inspect on
* @param condition the predicate used to verify whether to add a binding to "target"
* @param target the target class to which it adds a binding.
*
* @return self to support a continuous syntax for adding more conditional bindings.
*/
public ConditionalMultibind<T> addConditionBinding(
String property,
Predicate<String> condition,
Class<? extends T> target
)
{
final String value = properties.getProperty(property);
if (value == null) {
return this;
}
if (condition.apply(value)) {
multibinder.addBinding().to(target);
}
return this;
}

/**
* Conditionally bind target to the set. If "condition" returns true, add a binding to "target".
*
* @param property the property to inspect on
* @param condition the predicate used to verify whether to add a binding to "target"
* @param target the target instance to which it adds a binding.
*
* @return self to support a continuous syntax for adding more conditional bindings.
*/
public ConditionalMultibind<T> addConditionBinding(
String property,
Predicate<String> condition,
T target
)
{
final String value = properties.getProperty(property);
if (value == null) {
return this;
}
if (condition.apply(value)) {
multibinder.addBinding().toInstance(target);
}
return this;
}

/**
* Conditionally bind target to the set. If "condition" returns true, add a binding to "target".
*
* @param property the property to inspect on
* @param condition the predicate used to verify whether to add a binding to "target"
* @param target the target type to which it adds a binding.
*
* @return self to support a continuous syntax for adding more conditional bindings.
*/
public ConditionalMultibind<T> addConditionBinding(
String property,
Predicate<String> condition,
TypeLiteral<T> target
)
{
final String value = properties.getProperty(property);
if (value == null) {
return this;
}
if (condition.apply(value)) {
multibinder.addBinding().to(target);
}
return this;
}
}
Loading