AergoClientBuilder.java

/*
 * @copyright defined in LICENSE.txt
 */

package hera.client;

import static org.slf4j.LoggerFactory.getLogger;

import hera.Context;
import hera.ContextProvider;
import hera.DefaultConstants;
import hera.Strategy;
import hera.annotation.ApiAudience;
import hera.annotation.ApiStability;
import hera.api.model.internal.Time;
import hera.exception.RpcException;
import hera.strategy.ConnectStrategy;
import hera.strategy.JustRetryStrategy;
import hera.strategy.NettyConnectStrategy;
import hera.strategy.OkHttpConnectStrategy;
import hera.strategy.PlainTextChannelStrategy;
import hera.strategy.SecurityConfigurationStrategy;
import hera.strategy.TimeoutStrategy;
import hera.strategy.TlsChannelStrategy;
import hera.util.Configuration;
import hera.util.conf.InMemoryConfiguration;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;

@ApiAudience.Public
@ApiStability.Unstable
public class AergoClientBuilder implements ClientConfiguer<AergoClientBuilder> {

  public static final String SCOPE = "global";

  protected static final Map<Class<?>, Strategy> necessaryStrategyMap;

  static {
    final Map<Class<?>, Strategy> map = new HashMap<Class<?>, Strategy>();
    map.put(ConnectStrategy.class, new NettyConnectStrategy());
    map.put(TimeoutStrategy.class, new TimeoutStrategy(DefaultConstants.DEFAULT_TIMEOUT));
    map.put(SecurityConfigurationStrategy.class, new PlainTextChannelStrategy());
    necessaryStrategyMap = Collections.unmodifiableMap(map);
  }

  protected final Logger logger = getLogger(getClass());

  protected final Map<Class<?>, Strategy> strategyMap = new LinkedHashMap<Class<?>, Strategy>();

  protected Configuration configuration = new InMemoryConfiguration();

  @Override
  public AergoClientBuilder addConfiguration(final String key, final String value) {
    configuration.define(key, value);
    return this;
  }

  @Override
  public AergoClientBuilder withEndpoint(final String endpoint) {
    configuration.define("endpoint", endpoint);
    return this;
  }

  @Override
  public AergoClientBuilder withNonBlockingConnect() {
    strategyMap.put(ConnectStrategy.class, new NettyConnectStrategy());
    return this;
  }

  @Override
  public AergoClientBuilder withBlockingConnect() {
    strategyMap.put(ConnectStrategy.class, new OkHttpConnectStrategy());
    return this;
  }

  @Override
  public AergoClientBuilder withTimeout(final long timeout, final TimeUnit unit) {
    strategyMap.put(TimeoutStrategy.class, new TimeoutStrategy(timeout, unit));
    return this;
  }

  @Override
  public AergoClientBuilder withRetry(final int count, final long interval, final TimeUnit unit) {
    strategyMap.put(JustRetryStrategy.class, new JustRetryStrategy(count, Time.of(interval, unit)));
    return this;
  }

  @Override
  public AergoClientBuilder withPlainText() {
    strategyMap.put(SecurityConfigurationStrategy.class, new PlainTextChannelStrategy());
    return this;
  }

  @Override
  public AergoClientBuilder withTransportSecurity(final String serverCommonName,
      final String serverCertPath, final String clientCertPath, final String clientKeyPath) {
    try {
      return withTransportSecurity(serverCommonName, new FileInputStream(serverCertPath),
          new FileInputStream(clientCertPath), new FileInputStream(clientKeyPath));
    } catch (Exception e) {
      throw new RpcException(e);
    }
  }

  @Override
  public AergoClientBuilder withTransportSecurity(final String serverCommonName,
      final InputStream serverCertInputStream,
      final InputStream clientCertInputStream, final InputStream clientKeyInputStream) {
    strategyMap.put(SecurityConfigurationStrategy.class, new TlsChannelStrategy(serverCommonName,
        serverCertInputStream, clientCertInputStream, clientKeyInputStream));
    return this;
  }

  /**
   * Build {@link AergoClient} with the current context. If necessary strategy is not provided,fill
   * necessary strategy.
   *
   * @return {@link AergoClient}
   */
  public AergoClient build() {
    final AergoClient client = new AergoClient(buildContext());
    return client;
  }

  protected Context buildContext() {
    for (final Class<?> necessaryClass : necessaryStrategyMap.keySet()) {
      if (!strategyMap.containsKey(necessaryClass)) {
        strategyMap.put(necessaryClass, necessaryStrategyMap.get(necessaryClass));
      }
    }
    final Context context = ContextProvider.defaultProvider.get()
        .withStrategies(new HashSet<Strategy>(this.strategyMap.values()))
        .withConfiguration(configuration)
        .withScope(AergoClientBuilder.SCOPE);
    logger.info("Global context: {}", context);
    return context;
  }

}