Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor SPI interfaces - use single common ConfigExtension to ServiceLoad all avaje-config extensions #149

Merged
merged 8 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion avaje-aws-appconfig/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,16 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>3.15-RC1</version>
<version>4.0-RC1</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-spi-service</artifactId>
<version>1.4</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
package io.avaje.config.appconfig;

import io.avaje.applog.AppLog;
import io.avaje.config.ConfigParser;
import io.avaje.config.Configuration;
import io.avaje.config.ConfigurationSource;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.ERROR;
import static java.lang.System.Logger.Level.INFO;
import static java.lang.System.Logger.Level.TRACE;
import static java.lang.System.Logger.Level.WARNING;

import java.io.StringReader;
import java.time.Instant;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;

import static java.lang.System.Logger.Level.*;
import io.avaje.applog.AppLog;
import io.avaje.config.ConfigParser;
import io.avaje.config.Configuration;
import io.avaje.config.ConfigurationSource;
import io.avaje.spi.ServiceProvider;

/**
* Plugin that loads AWS AppConfig as Yaml or Properties.
* <p>
* By default, will periodically reload the configuration if it has changed.
*/
@ServiceProvider
public final class AppConfigPlugin implements ConfigurationSource {

private static final System.Logger log = AppLog.getLogger("io.avaje.config.AwsAppConfig");
Expand Down
3 changes: 2 additions & 1 deletion avaje-aws-appconfig/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import io.avaje.config.ConfigSPI;
import io.avaje.config.appconfig.AppConfigPlugin;

module io.avaje.config.appconfig {
Expand All @@ -7,5 +8,5 @@
requires io.avaje.config;
requires java.net.http;
requires transitive io.avaje.applog;
provides io.avaje.config.ConfigurationSource with AppConfigPlugin;
provides ConfigSPI with AppConfigPlugin;
}

This file was deleted.

9 changes: 8 additions & 1 deletion avaje-config/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>3.15-RC1</version>
<version>4.0-RC1</version>

<scm>
<developerConnection>scm:git:git@github.com:avaje/avaje-config.git</developerConnection>
Expand All @@ -31,6 +31,13 @@
<version>1.1</version>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-spi-service</artifactId>
<version>1.4</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-applog</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* Load a config file into a flattened map.
*/
@NonNullApi
public interface ConfigParser {
public interface ConfigParser extends ConfigSPI {

/**
* File extensions Supported by this parser
Expand Down
8 changes: 8 additions & 0 deletions avaje-config/src/main/java/io/avaje/config/ConfigSPI.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.avaje.config;

import io.avaje.spi.Service;

// TODO Make a sealed interface when we upgrade to 17
/** Super interface for all SPI classes */
@Service
public interface ConfigSPI {}
16 changes: 1 addition & 15 deletions avaje-config/src/main/java/io/avaje/config/ConfigurationLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,7 @@
* control how the events are logged. For example, it might delay logging messages
* until logging implementation has finished configuration.
*/
public interface ConfigurationLog {

/**
* Invoked when the configuration is being initialised.
*/
default void preInitialisation() {
rob-bygrave marked this conversation as resolved.
Show resolved Hide resolved
// do nothing by default
}

/**
* Invoked when the initialisation of configuration has been completed.
*/
default void postInitialisation() {
// do nothing by default
}
public interface ConfigurationLog extends ConfigSPI {

/**
* Log an event with the given level, message, and thrown exception.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@

import java.util.function.Consumer;

/**
* Plugin that is initiated after the configuration has been loaded.
*/
public interface ConfigurationPlugin {
/** Plugin that is initiated before/after the configuration has been loaded. */
public interface ConfigurationPlugin extends ConfigSPI {

/** Invoked when the configuration is being initialised. */
default void preInitialisation() {
// do nothing by default
}

/**
* Apply the plugin. Typically, a plugin might read configuration and do something
* and listen for configuration changes via {@link Configuration#onChange(Consumer, String...)}.
* Apply the plugin. Typically, a plugin might read configuration and do something and listen for
* configuration changes via {@link Configuration#onChange(Consumer, String...)}.
*
* @param configuration The configuration that has been loaded including all {@link ConfigurationSource}.
* @param configuration The configuration that has been loaded including all {@link
* ConfigurationSource}.
*/
void apply(Configuration configuration);
void postInitialization(Configuration configuration);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Additional source to load and update configuration.
*/
public interface ConfigurationSource {
public interface ConfigurationSource extends ConfigSPI {

/**
* Load additional configuration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,14 @@ CoreConfiguration postLoad(@Nullable InitialLoader loader) {
initSystemProperties();
if (loader != null) {
logMessage(loader);
applyPlugins();
}
log.postInitialisation();
applyPlugins();
return this;
}

private void applyPlugins() {
for (ConfigurationPlugin plugin : plugins) {
plugin.apply(this);
plugin.postInitialization(this);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,56 @@
package io.avaje.config;

import io.avaje.lang.NonNullApi;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.INFO;
import static java.util.Objects.requireNonNull;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.stream.Collectors;

import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.INFO;
import static java.util.Objects.requireNonNull;
import io.avaje.config.CoreConfiguration.ForegroundEventRunner;
import io.avaje.lang.NonNullApi;

@NonNullApi
final class CoreConfigurationBuilder implements Configuration.Builder {

private ConfigurationLog log = initialiseLog();
private static ConfigurationLog spiLog;
private static ResourceLoader spiResourceLoader;
private static ModificationEventRunner spiEventRunner;
private static final List<ConfigurationSource> SOURCES= new ArrayList<>();
private static final List<ConfigurationPlugin> PLUGINS= new ArrayList<>();

private ConfigurationLog log = spiLog;
private final Parsers parsers = new Parsers();
private final CoreEntry.CoreMap sourceMap = CoreEntry.newMap();
private ResourceLoader resourceLoader = initialiseResourceLoader();
private ModificationEventRunner eventRunner;
private ResourceLoader resourceLoader = spiResourceLoader;
private ModificationEventRunner eventRunner = spiEventRunner;
private boolean includeResourceLoading;
private InitialLoader initialLoader;

private static ConfigurationLog initialiseLog() {
return ServiceLoader.load(ConfigurationLog.class)
.findFirst()
.orElseGet(DefaultConfigurationLog::new);
static {
rbygrave marked this conversation as resolved.
Show resolved Hide resolved
for (var spi : ServiceLoader.load(ConfigSPI.class)) {
if (spi instanceof ConfigurationSource) {
SOURCES.add((ConfigurationSource) spi);
} else if (spi instanceof ConfigurationPlugin) {
PLUGINS.add((ConfigurationPlugin) spi);
} else if (spi instanceof ConfigurationLog) {
spiLog = (ConfigurationLog) spi;
} else if (spi instanceof ResourceLoader) {
spiResourceLoader = (ResourceLoader) spi;
} else if (spi instanceof ModificationEventRunner) {
spiEventRunner = (ModificationEventRunner) spi;
}
}
spiLog = spiLog == null ? new DefaultConfigurationLog() : spiLog;
spiResourceLoader = spiResourceLoader == null ? new DefaultResourceLoader() : spiResourceLoader;
spiEventRunner = spiEventRunner == null ? new ForegroundEventRunner() : spiEventRunner;
}

@Override
Expand Down Expand Up @@ -59,22 +80,24 @@ public Configuration.Builder put(String key, String value) {
@Override
public Configuration.Builder putAll(Map<String, ?> source) {
requireNonNull(source);
source.forEach((key, value) -> {
if (key != null && value != null) {
sourceMap.put(key, value.toString(), "initial");
}
});
source.forEach(
(key, value) -> {
if (key != null && value != null) {
sourceMap.put(key, value.toString(), "initial");
}
});
return this;
}

@Override
public Configuration.Builder putAll(Properties source) {
requireNonNull(source);
source.forEach((key, value) -> {
if (key != null && value != null) {
sourceMap.put(key.toString(), value.toString(), "initial");
}
});
source.forEach(
(key, value) -> {
if (key != null && value != null) {
sourceMap.put(key.toString(), value.toString(), "initial");
}
});
return this;
}

Expand Down Expand Up @@ -137,17 +160,12 @@ public Configuration.Builder includeResourceLoading() {

@Override
public Configuration build() {
final var runner = initRunner();
final var sources = ServiceLoader.load(ConfigurationSource.class).stream()
.map(ServiceLoader.Provider::get)
.collect(Collectors.toList());
final var plugins = ServiceLoader.load(ConfigurationPlugin.class).stream()
.map(ServiceLoader.Provider::get)
.collect(Collectors.toList());

var components = new CoreComponents(runner, log, parsers, sources, plugins);

var components = new CoreComponents(eventRunner, log, parsers, SOURCES, PLUGINS);
if (includeResourceLoading) {
log.preInitialisation();
for (var plugin : PLUGINS) {
plugin.preInitialisation();
}
initialLoader = new InitialLoader(components, resourceLoader);
}
return new CoreConfiguration(components, initEntries()).postLoad(initialLoader);
Expand All @@ -162,19 +180,4 @@ private CoreEntry.CoreMap initEntries() {
private CoreEntry.CoreMap initEntryMap() {
return initialLoader == null ? CoreEntry.newMap() : initialLoader.load();
}

private static ResourceLoader initialiseResourceLoader() {
return ServiceLoader.load(ResourceLoader.class)
.findFirst()
.orElseGet(DefaultResourceLoader::new);
}

private ModificationEventRunner initRunner() {
if (eventRunner == null) {
eventRunner = ServiceLoader.load(ModificationEventRunner.class)
.findFirst()
.orElseGet(CoreConfiguration.ForegroundEventRunner::new);
}
return eventRunner;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* The default is for event listener notification to be executed using the same thread
* that is making the modifications to the configuration.
*/
public interface ModificationEventRunner {
public interface ModificationEventRunner extends ConfigSPI {

/**
* Run the task of notifying all the event listeners of a modification event
Expand Down
15 changes: 10 additions & 5 deletions avaje-config/src/main/java/io/avaje/config/Parsers.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,16 @@ private void initYamlParser() {
}

private void initParsers() {
ServiceLoader.load(ConfigParser.class).forEach(p -> {
for (var ext : p.supportedExtensions()) {
parserMap.put(ext, p);
}
});
ServiceLoader.load(ConfigSPI.class)
rbygrave marked this conversation as resolved.
Show resolved Hide resolved
.forEach(
spi -> {
if (spi instanceof ConfigParser) {
ConfigParser p = (ConfigParser) spi;
for (var ext : p.supportedExtensions()) {
parserMap.put(ext, p);
}
}
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.avaje.config;

import io.avaje.lang.Nullable;
import io.avaje.spi.Service;

import java.io.InputStream;

Expand All @@ -13,7 +14,7 @@
* Note there is a fallback to use {@link ClassLoader#getSystemResourceAsStream(String)}
* if the ResourceLoader returns null.
*/
public interface ResourceLoader {
public interface ResourceLoader extends ConfigSPI {

/**
* Return the InputStream for the given resource or null if it can not be found.
Expand Down
9 changes: 3 additions & 6 deletions avaje-config/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@
requires transitive io.avaje.applog;
requires static org.yaml.snakeyaml;

uses io.avaje.config.ConfigParser;
uses io.avaje.config.ConfigurationLog;
uses io.avaje.config.ConfigurationPlugin;
uses io.avaje.config.ModificationEventRunner;
uses io.avaje.config.ConfigurationSource;
uses io.avaje.config.ResourceLoader;
requires static io.avaje.spi;

uses io.avaje.config.ConfigSPI;

}
Loading
Loading