io.opentelemetry.sdk.autoconfigure.internal.SpiHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of opentelemetry-sdk-extension-autoconfigure Show documentation
Show all versions of opentelemetry-sdk-extension-autoconfigure Show documentation
OpenTelemetry SDK Auto-configuration
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.autoconfigure.internal;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.Ordered;
import io.opentelemetry.sdk.autoconfigure.spi.internal.AutoConfigureListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*/
public final class SpiHelper {
private final ClassLoader classLoader;
private final SpiFinder spiFinder;
private final Set listeners =
Collections.newSetFromMap(new IdentityHashMap<>());
// Visible for testing
SpiHelper(ClassLoader classLoader, SpiFinder spiFinder) {
this.classLoader = classLoader;
this.spiFinder = spiFinder;
}
/** Create a {@link SpiHelper} which loads SPIs using the {@code classLoader}. */
public static SpiHelper create(ClassLoader classLoader) {
return new SpiHelper(classLoader, ServiceLoader::load);
}
/**
* Load implementations of an SPI which are configurable (i.e. they accept {@link
* ConfigProperties}.
*
* @param spiClass the SPI class
* @param getName function returning the name of an SPI implementation
* @param getConfigurable function returning a configured instance
* @param config the configuration to pass to invocations of {@code #getConfigurable}
* @param the configurable type
* @param the SPI type
* @return a {@link NamedSpiManager} used to access configured instances of the SPI by name
*/
public NamedSpiManager loadConfigurable(
Class spiClass,
Function getName,
BiFunction getConfigurable,
ConfigProperties config) {
Map> nameToProvider = new HashMap<>();
for (S provider : load(spiClass)) {
String name = getName.apply(provider);
nameToProvider.put(
name,
() -> {
T result = getConfigurable.apply(provider, config);
maybeAddListener(result);
return result;
});
}
return NamedSpiManager.create(nameToProvider);
}
/**
* Load implementations of an ordered SPI (i.e. implements {@link Ordered}).
*
* @param spiClass the SPI class
* @param the SPI type
* @return list of SPI implementations, in order
*/
public List loadOrdered(Class spiClass) {
List result = load(spiClass);
result.sort(Comparator.comparing(Ordered::order));
return result;
}
/**
* Load implementations of an SPI.
*
* @param spiClass the SPI class
* @param the SPI type
* @return list of SPI implementations
*/
public List load(Class spiClass) {
List result = new ArrayList<>();
for (T service : spiFinder.load(spiClass, classLoader)) {
maybeAddListener(service);
result.add(service);
}
return result;
}
private void maybeAddListener(Object object) {
if (object instanceof AutoConfigureListener) {
listeners.add((AutoConfigureListener) object);
}
}
/** Return the set of SPIs loaded which implement {@link AutoConfigureListener}. */
public Set getListeners() {
return Collections.unmodifiableSet(listeners);
}
// Visible for testing
interface SpiFinder {
Iterable load(Class spiClass, ClassLoader classLoader);
}
}