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

io.hyperfoil.core.steps.ServiceLoadedBuilderProvider Maven / Gradle / Ivy

There is a newer version: 0.27.1
Show newest version
package io.hyperfoil.core.steps;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.function.Consumer;

import io.hyperfoil.api.config.BenchmarkDefinitionException;
import io.hyperfoil.api.config.Locator;
import io.hyperfoil.api.config.ServiceLoadedContract;
import io.hyperfoil.api.config.ServiceLoadedFactory;

public class ServiceLoadedBuilderProvider> {
   private static final Map>, ServiceLoader>> SERVICE_LOADERS = new HashMap<>();
   private static final Map>, Collection>> FACTORIES = new HashMap<>();

   private final Class factoryClazz;
   private final Locator locator;
   private final Consumer consumer;

   public static synchronized Iterable> factories(Class> clazz) {
      Collection> factories = FACTORIES.get(clazz);
      if (factories != null) {
         return factories;
      }
      Set>> included = new HashSet<>();
      ArrayDeque>> deque = new ArrayDeque<>();
      deque.add(clazz);
      included.add(clazz);
      factories = new ArrayList<>();
      while (!deque.isEmpty()) {
         Class> factoryClass = deque.poll();
         ServiceLoader> loader = SERVICE_LOADERS.get(factoryClass);
         if (loader == null) {
            loader = ServiceLoader.load(factoryClass);
            SERVICE_LOADERS.put(factoryClass, loader);
         }
         for (ServiceLoadedFactory factory : loader) {
            factories.add(factory);
         }
         ServiceLoadedFactory.Include include = factoryClass.getAnnotation(ServiceLoadedFactory.Include.class);
         if (include != null) {
            for (Class> incl : include.value()) {
               if (!included.contains(incl)) {
                  deque.add(incl);
               }
            }
         }
      }
      FACTORIES.put(clazz, factories);
      return factories;
   }

   private static ServiceLoadedFactory factory(Class> clazz, String name) {
      Iterable> loader = factories(clazz);
      ServiceLoadedFactory factory = null;
      for (ServiceLoadedFactory f : loader) {
         if (f.name().equals(name)) {
            if (factory != null) {
               throw new BenchmarkDefinitionException("Two classes ('" + factory.getClass().getName() +
                     "' and '" + f.getClass().getName() + "') provide builders for name '" + name + "' and type '" +
                     clazz.getName() + "'");
            }
            factory = f;
         }
      }
      if (factory == null) {
         throw new BenchmarkDefinitionException("No class provides builders for name '" + name + "' and type '" + clazz.getName() + "'");
      }
      return factory;
   }

   public ServiceLoadedBuilderProvider(Class factoryClazz, Locator locator, Consumer consumer) {
      this.factoryClazz = factoryClazz;
      this.locator = locator;
      this.consumer = consumer;
   }

   public ServiceLoadedContract forName(String name, String param) {
      ServiceLoadedFactory factory = factory((Class) factoryClazz, name);
      if (param != null && !factory.acceptsParam()) {
         throw new BenchmarkDefinitionException(factory.name() + " does not accept inline parameter");
      }
      B builder = factory.newBuilder(locator, param);
      return new ServiceLoadedContract<>(builder, consumer);
   }
}