All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.druid.guice.ConditionalMultibind Maven / Gradle / Ivy

There is a newer version: 30.0.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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 org.apache.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 org.apache.druid.guice.annotations.PublicApi;

import javax.annotation.Nullable;
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>(){}))
 */
@PublicApi
public class ConditionalMultibind
{

  /**
   * 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         interface type.
   *
   * @return An instance of ConditionalMultibind that can be used to add conditional bindings.
   */
  public static  ConditionalMultibind create(Properties properties, Binder binder, Class type)
  {
    return new ConditionalMultibind(properties, Multibinder.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             interface type.
   * @param annotationType the binding annotation.
   *
   * @return An instance of ConditionalMultibind that can be used to add conditional bindings.
   */
  public static  ConditionalMultibind create(
      Properties properties,
      Binder binder,
      Class type,
      Class annotationType
  )
  {
    return new ConditionalMultibind(properties, Multibinder.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         interface type.
   *
   * @return An instance of ConditionalMultibind that can be used to add conditional bindings.
   */
  public static  ConditionalMultibind create(Properties properties, Binder binder, TypeLiteral type)
  {
    return new ConditionalMultibind(properties, Multibinder.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             interface type.
   * @param annotationType the binding annotation.
   *
   * @return An instance of ConditionalMultibind that can be used to add conditional bindings.
   */
  public static  ConditionalMultibind create(
      Properties properties,
      Binder binder,
      TypeLiteral type,
      Class annotationType
  )
  {
    return new ConditionalMultibind(properties, Multibinder.newSetBinder(binder, type, annotationType));
  }


  private final Properties properties;
  private final Multibinder multibinder;

  public ConditionalMultibind(Properties properties, Multibinder 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 addBinding(Class 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 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 addBinding(TypeLiteral 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 addConditionBinding(
      String property,
      Predicate condition,
      Class target
  )
  {
    return addConditionBinding(property, null, condition, target);
  }

  public ConditionalMultibind addConditionBinding(
      String property,
      String defaultValue,
      Predicate condition,
      Class target
  )
  {
    if (matchCondition(property, defaultValue, condition)) {
      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 addConditionBinding(
      String property,
      Predicate condition,
      T target
  )
  {
    if (matchCondition(property, condition)) {
      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.
   */
  @PublicApi
  public ConditionalMultibind addConditionBinding(
      String property,
      Predicate condition,
      TypeLiteral target
  )
  {
    if (matchCondition(property, condition)) {
      multibinder.addBinding().to(target);
    }
    return this;
  }

  public boolean matchCondition(String property, Predicate condition)
  {
    return matchCondition(property, null, condition);
  }

  public boolean matchCondition(String property, @Nullable String defaultValue, Predicate condition)
  {
    final String value = properties.getProperty(property, defaultValue);
    if (value == null) {
      return false;
    }
    return condition.apply(value);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy