Skip to content

Commit

Permalink
refactor(core): refactor extension config properties
Browse files Browse the repository at this point in the history
This commit contains a core refactoring of how
config properties are defined and exposed for extensions
  • Loading branch information
fhussonnois committed Jan 3, 2025
1 parent 708e357 commit bd455be
Show file tree
Hide file tree
Showing 74 changed files with 1,009 additions and 1,157 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.micronaut.context.ApplicationContext;
import io.streamthoughts.jikkou.core.JikkouApi;
import io.streamthoughts.jikkou.core.models.ApiOptionSpec;
import java.util.Optional;
import org.jetbrains.annotations.NotNull;
import picocli.CommandLine;

Expand All @@ -31,18 +32,18 @@ public AbstractCommandLineFactory(@NotNull ApplicationContext applicationContext
protected CommandLine.Model.OptionSpec createOptionSpec(ApiOptionSpec option,
AbstractApiCommand command) {
CommandLine.Model.OptionSpec.Builder builder = CommandLine.Model.OptionSpec
.builder(buildOptionName(option))
.type(option.typeClass())
.description(option.description())
.required(option.required())
.defaultValue(option.defaultValue())
.required(option.required())
.setter(new CommandLine.Model.ISetter() {
@Override
public <T> T set(T value) {
return command.option(option, value);
}
});
.builder(buildOptionName(option))
.type(option.typeClass())
.description(Optional.ofNullable(option.description()).orElse(""))
.required(option.required())
.initialValue(option.defaultValue())
.required(option.required())
.setter(new CommandLine.Model.ISetter() {
@Override
public <T> T set(T value) {
return command.option(option, value);
}
});
return builder.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,10 @@
import io.streamthoughts.jikkou.client.command.AbstractCommandLineFactory;
import io.streamthoughts.jikkou.client.renderer.CommandGroupRenderer;
import io.streamthoughts.jikkou.core.JikkouApi;
import io.streamthoughts.jikkou.core.models.ApiOptionSpec;
import io.streamthoughts.jikkou.core.models.ApiResource;
import io.streamthoughts.jikkou.core.models.ApiResourceList;
import io.streamthoughts.jikkou.core.models.ApiResourceVerbOptionList;
import io.streamthoughts.jikkou.core.models.ResourceType;
import io.streamthoughts.jikkou.core.models.Verb;
import io.streamthoughts.jikkou.core.models.*;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
import org.jetbrains.annotations.NotNull;
import picocli.CommandLine;
import picocli.CommandLine.Model.CommandSpec;
Expand Down Expand Up @@ -82,21 +72,22 @@ public CommandLine createCommandLine() {
}
if (resource.isVerbSupported(Verb.GET)) {
spec.addOption(CommandLine.Model.OptionSpec
.builder("--name")
.hasInitialValue(false)
.paramLabel("<name>")
.type(String.class)
.description("The name of the resource.")
.required(false)
.setter(new CommandLine.Model.ISetter() {
@Override
public <T> T set(T value) {
String str = Optional.ofNullable(value).map(Objects::toString).orElse(null);
command.setName(str);
return null;
}
})
.build());
.builder("--name")
.hasInitialValue(false)
.paramLabel("<name>")
.type(String.class)
.description("The name of the resource.")
.required(false)
.setter(new CommandLine.Model.ISetter() {
@Override
public <T> T set(T value) {
String str = Optional.ofNullable(value).map(Objects::toString).orElse(null);
command.setName(str);
return null;
}
})
.build()
);
}
cmd.addSubcommand(subcommand);
sections.computeIfAbsent("%nCOMMANDS FOR API GROUP '" + type.group() + "': %n%n", k -> new ArrayList<>())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ void shouldPrintUsageForGetCommand() {
int execute = Jikkou.execute(new String[]{"get"});
Assertions.assertEquals(CommandLine.ExitCode.USAGE, execute);
}

@Test
void testCommandHealthGetIndicators() {
int execute = Jikkou.execute(new String[]{"health", "get-indicators"});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@
import io.streamthoughts.jikkou.core.config.internals.Type;
import io.streamthoughts.jikkou.core.data.TypeConverter;
import io.streamthoughts.jikkou.core.models.NamedValue;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
Expand Down Expand Up @@ -61,7 +57,7 @@ public static ConfigProperty of(final @NotNull Type type,
*/
public static <T> ConfigProperty<T> of(final @NotNull String path,
final @NotNull TypeConverter<T> converter) {
return new ConfigProperty<>(path, (p, configuration) -> configuration.findAny(p).map(converter::convertValue));
return new ConfigProperty<>(path, null, (p, configuration) -> configuration.findAny(p).map(converter::convertValue));
}

/**
Expand All @@ -71,8 +67,9 @@ public static <T> ConfigProperty<T> of(final @NotNull String path,
* @param enumType the enum type.
* @return a new {@link ConfigProperty}.
*/
public static <T extends Enum<T>> ConfigProperty<T> ofEnum(final @NotNull String path, final @NotNull Class<T> enumType) {
return new ConfigProperty<>(path, (p, config) -> config.findString(p).map(val -> Enums.getForNameIgnoreCase(val, enumType)));
public static <T extends Enum<T>> ConfigProperty<T> ofEnum(final @NotNull String path,
final @NotNull Class<T> enumType) {
return new ConfigProperty<>(path, enumType, (p, config) -> config.findString(p).map(val -> Enums.getForNameIgnoreCase(val, enumType)));
}

/**
Expand All @@ -82,7 +79,7 @@ public static <T extends Enum<T>> ConfigProperty<T> ofEnum(final @NotNull String
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<Short> ofShort(final @NotNull String path) {
return new ConfigProperty<>(path, (p, config) -> config.findShort(p));
return new ConfigProperty<>(path, Short.class, (p, config) -> config.findShort(p));
}

/**
Expand All @@ -92,7 +89,7 @@ public static ConfigProperty<Short> ofShort(final @NotNull String path) {
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<Integer> ofInt(final @NotNull String path) {
return new ConfigProperty<>(path, (p, config) -> config.findInteger(p));
return new ConfigProperty<>(path, Integer.class, (p, config) -> config.findInteger(p));
}

/**
Expand All @@ -102,7 +99,7 @@ public static ConfigProperty<Integer> ofInt(final @NotNull String path) {
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<Float> ofFloat(final @NotNull String path) {
return new ConfigProperty<>(path, (p, config) -> config.findFloat(p));
return new ConfigProperty<>(path, Float.class, (p, config) -> config.findFloat(p));
}

/**
Expand All @@ -112,7 +109,7 @@ public static ConfigProperty<Float> ofFloat(final @NotNull String path) {
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<Long> ofLong(final @NotNull String key) {
return new ConfigProperty<>(key, (p, config) -> config.findLong(p));
return new ConfigProperty<>(key, Long.class, (p, config) -> config.findLong(p));
}

/**
Expand All @@ -122,7 +119,7 @@ public static ConfigProperty<Long> ofLong(final @NotNull String key) {
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<Double> ofDouble(final @NotNull String key) {
return new ConfigProperty<>(key, (p, config) -> config.findDouble(p));
return new ConfigProperty<>(key, Double.class, (p, config) -> config.findDouble(p));
}

/**
Expand All @@ -132,7 +129,7 @@ public static ConfigProperty<Double> ofDouble(final @NotNull String key) {
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<String> ofString(final @NotNull String key) {
return new ConfigProperty<>(key, (p, config) -> config.findString(p));
return new ConfigProperty<>(key, String.class, (p, config) -> config.findString(p));
}

/**
Expand All @@ -142,7 +139,7 @@ public static ConfigProperty<String> ofString(final @NotNull String key) {
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<Boolean> ofBoolean(final @NotNull String key) {
return new ConfigProperty<>(key, (p, config) -> config.findBoolean(p));
return new ConfigProperty<>(key, Boolean.class, (p, config) -> config.findBoolean(p));
}

/**
Expand All @@ -152,7 +149,7 @@ public static ConfigProperty<Boolean> ofBoolean(final @NotNull String key) {
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<Map<String, Object>> ofMap(final @NotNull String key) {
return new ConfigProperty<>(key, (p, config) -> config.findConfig(p).map(Configuration::asMap));
return new ConfigProperty<>(key, Map.class, (p, config) -> config.findConfig(p).map(Configuration::asMap));
}

/**
Expand All @@ -162,7 +159,17 @@ public static ConfigProperty<Map<String, Object>> ofMap(final @NotNull String ke
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<List<String>> ofList(final @NotNull String key) {
return new ConfigProperty<>(key, (p, config) -> config.findStringList(p));
return new ConfigProperty<>(key, List.class, (p, config) -> config.findStringList(p));
}

/**
* Static helper method to create a new {@link ConfigProperty} with an expected {@link Set} value.
*
* @param key the option string key.
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<Object> ofAny(final @NotNull String key) {
return new ConfigProperty<>(key, Object.class, (p, config) -> config.findAny(p));
}

/**
Expand All @@ -172,7 +179,7 @@ public static ConfigProperty<List<String>> ofList(final @NotNull String key) {
* @return a new {@link ConfigProperty}.
*/
public static <T> ConfigProperty<List<Class<T>>> ofClasses(final @NotNull String key) {
return new ConfigProperty<>(key, (p, config) -> config.findClassList(p));
return new ConfigProperty<>(key, List.class, (p, config) -> config.findClassList(p));
}

/**
Expand All @@ -182,7 +189,7 @@ public static <T> ConfigProperty<List<Class<T>>> ofClasses(final @NotNull String
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<Configuration> ofConfig(final @NotNull String path) {
return new ConfigProperty<>(path, (p, config) -> config.findConfig(p));
return new ConfigProperty<>(path, Configuration.class, (p, config) -> config.findConfig(p));
}

/**
Expand All @@ -192,8 +199,7 @@ public static ConfigProperty<Configuration> ofConfig(final @NotNull String path)
* @return a new {@link ConfigProperty}.
*/
public static ConfigProperty<List<Configuration>> ofConfigList(final @NotNull String path) {
BiFunction<String, Configuration, Optional<List<Configuration>>> supplier = (p, config) -> config.findConfigList(p);
return new ConfigProperty<>(path, supplier);
return new ConfigProperty<>(path, List.class, (p, config) -> config.findConfigList(p));
}

private final String key;
Expand All @@ -202,6 +208,10 @@ public static ConfigProperty<List<Configuration>> ofConfigList(final @NotNull St

private final Supplier<? extends T> defaultValueSupplier;

private final boolean isRequired;

private final Class<?> rawType;

public final BiFunction<String, Configuration, Optional<T>> accessor;

/**
Expand All @@ -210,8 +220,9 @@ public static ConfigProperty<List<Configuration>> ofConfigList(final @NotNull St
* @param key the key of the configuration property.
*/
public ConfigProperty(final @NotNull String key,
final Class<?> rawType,
final @NotNull BiFunction<String, Configuration, Optional<T>> valueSupplier) {
this(key, valueSupplier, null, null);
this(key, rawType, valueSupplier, null, null, false);
}

public Configuration asConfiguration(final Object value) {
Expand All @@ -231,25 +242,33 @@ public NamedValue asValue(final Object value) {
* @param description the option default value.
*/
public ConfigProperty(final @NotNull String key,
final Class<?> rawType,
final @NotNull BiFunction<String, Configuration, Optional<T>> accessor,
final @Nullable Supplier<? extends T> defaultValueSupplier,
final @Nullable String description) {
final @Nullable String description,
final boolean isRequired) {
this.key = Objects.requireNonNull(key, "key cannot be null");
this.rawType = Objects.requireNonNull(rawType, "rawType cannot be null");
this.accessor = accessor;
this.defaultValueSupplier = defaultValueSupplier;
this.description = description;
this.isRequired = isRequired;
}

public ConfigProperty<T> description(final String description) {
return new ConfigProperty<>(key, accessor, defaultValueSupplier, description);
return new ConfigProperty<>(key, rawType, accessor, defaultValueSupplier, description, isRequired);
}

public ConfigProperty<T> orElse(final T other) {
return orElse(() -> other);
public ConfigProperty<T> required(boolean isRequired) {
return new ConfigProperty<>(key, rawType, accessor, defaultValueSupplier, description, isRequired);
}

public ConfigProperty<T> orElse(final @NotNull Supplier<? extends T> other) {
return new ConfigProperty<>(key, accessor, other, description);
public ConfigProperty<T> defaultValue(final T other) {
return defaultValue(() -> other);
}

public ConfigProperty<T> defaultValue(final @NotNull Supplier<? extends T> other) {
return new ConfigProperty<>(key, rawType, accessor, other, description, isRequired);
}

/**
Expand All @@ -267,16 +286,22 @@ public <U> ConfigProperty<U> map(Function<? super T, ? extends U> mapper) {
.orElse(null);

return new ConfigProperty<>(
key,
(p, config) -> accessor.apply(p, config).map(mapper),
defaultValueSupplierWithMapper,
description
key,
rawType,
(p, config) -> accessor.apply(p, config).map(mapper),
defaultValueSupplierWithMapper,
description,
isRequired
);
}

public <U> ConfigProperty<U> convert(final TypeConverter<U> converter) {
return map(converter::convertValue);
}

public T orElseGet(final @NotNull Configuration config,
final @NotNull Supplier<? extends T> other) {
return orElse(other).get(config);
return defaultValue(other).get(config);
}

/**
Expand All @@ -295,8 +320,8 @@ public T get(final @NotNull Configuration config) {
*/
public Optional<T> getOptional(final @NotNull Configuration config) {
return accessor
.apply(key, config)
.or(() -> Optional.ofNullable(defaultValueSupplier).map(Supplier::get));
.apply(key, config)
.or(() -> Optional.ofNullable(defaultValueSupplier).map(Supplier::get));
}

/**
Expand All @@ -317,8 +342,22 @@ public String description() {
return description;
}

public Supplier<? extends T> defaultValueSupplier() {
return Optional.ofNullable(defaultValueSupplier).orElse(() -> null);
/**
* Gets the description of this property.
*
* @return the description string, or {@code null} if no description was set.
*/
public boolean required() {
return isRequired;
}

/**
* Gets the raw-type of this property.
*
* @return the raw-type class.
*/
public Class<?> rawType() {
return rawType;
}

/**
Expand Down Expand Up @@ -355,8 +394,8 @@ public int hashCode() {
@Override
public String toString() {
return "ConfigProperty[" +
"key=" + key +
", description=" + description +
']';
"key=" + key +
", description=" + description +
']';
}
}
Loading

0 comments on commit bd455be

Please sign in to comment.