io.hyperfoil.core.steps.ServiceLoadedBuilderProvider Maven / Gradle / Ivy
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 extends ServiceLoadedFactory>>> 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 extends ServiceLoadedFactory>> factoryClass = deque.poll();
ServiceLoader extends ServiceLoadedFactory>> 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 extends ServiceLoadedFactory>> 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);
}
}