[*] Remove config entry sealing

This commit is contained in:
2025-06-10 00:46:03 +02:00
parent a6900e673a
commit 2096ae540c
28 changed files with 201 additions and 163 deletions

View File

@@ -5,7 +5,6 @@ import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
import de.siphalor.tweed5.core.api.extension.TweedExtension;
import org.jspecify.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
@@ -33,7 +32,7 @@ public interface ConfigContainer<T> {
void finishExtensionSetup();
void attachAndSealTree(ConfigEntry<T> rootEntry);
void attachTree(ConfigEntry<T> rootEntry);
EntryExtensionsData createExtensionsData();

View File

@@ -3,6 +3,6 @@ package de.siphalor.tweed5.core.api.container;
public enum ConfigContainerSetupPhase {
EXTENSIONS_SETUP,
TREE_SETUP,
TREE_SEALED,
TREE_ATTACHED,
READY,
}

View File

@@ -3,29 +3,16 @@ package de.siphalor.tweed5.core.api.entry;
import de.siphalor.tweed5.core.api.container.ConfigContainer;
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public abstract class BaseConfigEntry<T> implements ConfigEntry<T> {
private final ConfigContainer<?> container;
private final Class<T> valueClass;
private ConfigContainer<?> container;
private EntryExtensionsData extensionsData;
private boolean sealed;
@Override
public void seal(ConfigContainer<?> container) {
requireUnsealed();
private final EntryExtensionsData extensionsData;
public BaseConfigEntry(ConfigContainer<?> container, Class<T> valueClass) {
this.container = container;
this.valueClass = valueClass;
this.extensionsData = container.createExtensionsData();
sealed = true;
}
protected void requireUnsealed() {
if (sealed) {
throw new IllegalStateException("Config entry is already sealed!");
}
}
}

View File

@@ -4,10 +4,10 @@ import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
import de.siphalor.tweed5.core.api.container.ConfigContainer;
public interface ConfigEntry<T> {
Class<T> valueClass();
void seal(ConfigContainer<?> container);
boolean sealed();
ConfigContainer<?> container();
Class<T> valueClass();
EntryExtensionsData extensionsData();

View File

@@ -200,7 +200,7 @@ public class DefaultConfigContainer<T> implements ConfigContainer<T> {
public <E extends TweedExtension> Optional<E> extension(Class<E> extensionClass) {
requireSetupPhase(
ConfigContainerSetupPhase.TREE_SETUP,
ConfigContainerSetupPhase.TREE_SEALED,
ConfigContainerSetupPhase.TREE_ATTACHED,
ConfigContainerSetupPhase.READY
);
try {
@@ -214,25 +214,19 @@ public class DefaultConfigContainer<T> implements ConfigContainer<T> {
public Collection<TweedExtension> extensions() {
requireSetupPhase(
ConfigContainerSetupPhase.TREE_SETUP,
ConfigContainerSetupPhase.TREE_SEALED,
ConfigContainerSetupPhase.TREE_ATTACHED,
ConfigContainerSetupPhase.READY
);
return Collections.unmodifiableCollection(extensions.values());
}
@Override
public void attachAndSealTree(ConfigEntry<T> rootEntry) {
public void attachTree(ConfigEntry<T> rootEntry) {
requireSetupPhase(ConfigContainerSetupPhase.TREE_SETUP);
this.rootEntry = rootEntry;
rootEntry.visitInOrder(entry -> {
if (!entry.sealed()) {
entry.seal(DefaultConfigContainer.this);
}
});
setupPhase = ConfigContainerSetupPhase.TREE_SEALED;
setupPhase = ConfigContainerSetupPhase.TREE_ATTACHED;
}
@Override
@@ -251,7 +245,7 @@ public class DefaultConfigContainer<T> implements ConfigContainer<T> {
public Map<Class<?>, ? extends RegisteredExtensionData<EntryExtensionsData, ?>> entryDataExtensions() {
requireSetupPhase(
ConfigContainerSetupPhase.TREE_SETUP,
ConfigContainerSetupPhase.TREE_SEALED,
ConfigContainerSetupPhase.TREE_ATTACHED,
ConfigContainerSetupPhase.READY
);
return registeredEntryDataExtensions;
@@ -259,7 +253,7 @@ public class DefaultConfigContainer<T> implements ConfigContainer<T> {
@Override
public void initialize() {
requireSetupPhase(ConfigContainerSetupPhase.TREE_SEALED);
requireSetupPhase(ConfigContainerSetupPhase.TREE_ATTACHED);
assert rootEntry != null;
rootEntry.visitInOrder(entry -> {
@@ -273,7 +267,7 @@ public class DefaultConfigContainer<T> implements ConfigContainer<T> {
@Override
public ConfigEntry<T> rootEntry() {
requireSetupPhase(ConfigContainerSetupPhase.TREE_SEALED, ConfigContainerSetupPhase.READY);
requireSetupPhase(ConfigContainerSetupPhase.TREE_ATTACHED, ConfigContainerSetupPhase.READY);
assert rootEntry != null;
return rootEntry;

View File

@@ -1,5 +1,6 @@
package de.siphalor.tweed5.core.impl.entry;
import de.siphalor.tweed5.core.api.container.ConfigContainer;
import de.siphalor.tweed5.core.api.entry.*;
import java.util.Collection;
@@ -7,16 +8,16 @@ import java.util.function.IntFunction;
public class CollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseConfigEntry<T> implements CollectionConfigEntry<E, T> {
private final IntFunction<T> collectionConstructor;
private ConfigEntry<E> elementEntry;
private final ConfigEntry<E> elementEntry;
public CollectionConfigEntryImpl(Class<T> valueClass, IntFunction<T> collectionConstructor) {
super(valueClass);
public CollectionConfigEntryImpl(
ConfigContainer<?> container,
Class<T> valueClass,
IntFunction<T> collectionConstructor,
ConfigEntry<E> elementEntry
) {
super(container, valueClass);
this.collectionConstructor = collectionConstructor;
}
public void elementEntry(ConfigEntry<E> elementEntry) {
requireUnsealed();
this.elementEntry = elementEntry;
}

View File

@@ -1,13 +1,14 @@
package de.siphalor.tweed5.core.impl.entry;
import de.siphalor.tweed5.core.api.container.ConfigContainer;
import de.siphalor.tweed5.core.api.entry.BaseConfigEntry;
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor;
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
public class SimpleConfigEntryImpl<T> extends BaseConfigEntry<T> implements SimpleConfigEntry<T> {
public SimpleConfigEntryImpl(Class<T> valueClass) {
super(valueClass);
public SimpleConfigEntryImpl(ConfigContainer<?> container, Class<T> valueClass) {
super(container, valueClass);
}
@Override

View File

@@ -1,5 +1,6 @@
package de.siphalor.tweed5.core.impl.entry;
import de.siphalor.tweed5.core.api.container.ConfigContainer;
import de.siphalor.tweed5.core.api.entry.*;
import java.util.LinkedHashMap;
@@ -8,16 +9,17 @@ import java.util.function.IntFunction;
public class StaticMapCompoundConfigEntryImpl<T extends Map<String, Object>> extends BaseConfigEntry<T> implements CompoundConfigEntry<T> {
private final IntFunction<T> mapConstructor;
private final Map<String, ConfigEntry<?>> compoundEntries = new LinkedHashMap<>();
private final Map<String, ConfigEntry<?>> compoundEntries;
public StaticMapCompoundConfigEntryImpl(Class<T> valueClass, IntFunction<T> mapConstructor) {
super(valueClass);
public StaticMapCompoundConfigEntryImpl(
ConfigContainer<?> container,
Class<T> valueClass,
IntFunction<T> mapConstructor,
Map<String, ConfigEntry<?>> compoundEntries
) {
super(container, valueClass);
this.mapConstructor = mapConstructor;
}
public void addSubEntry(String key, ConfigEntry<?> entry) {
requireUnsealed();
compoundEntries.put(key, entry);
this.compoundEntries = new LinkedHashMap<>(compoundEntries);
}
@Override

View File

@@ -105,23 +105,23 @@ class DefaultConfigContainerTest {
@SuppressWarnings("unchecked")
@Test
void attachAndSealTree() {
void attachTree() {
var configContainer = new DefaultConfigContainer<Map<String, Object>>();
var compoundEntry = new StaticMapCompoundConfigEntryImpl<>(
(Class<Map<String, Object>>)(Class<?>) Map.class,
(capacity) -> new HashMap<>(capacity * 2, 0.5F)
);
var subEntry = new SimpleConfigEntryImpl<>(String.class);
compoundEntry.addSubEntry("test", subEntry);
configContainer.registerExtension(ExtensionInitTracker.class);
configContainer.finishExtensionSetup();
assertThat(configContainer.setupPhase()).isEqualTo(ConfigContainerSetupPhase.TREE_SETUP);
configContainer.attachAndSealTree(compoundEntry);
var subEntry = new SimpleConfigEntryImpl<>(configContainer, String.class);
var compoundEntry = new StaticMapCompoundConfigEntryImpl<>(
configContainer,
(Class<Map<String, Object>>)(Class<?>) Map.class,
(capacity) -> new HashMap<>(capacity * 2, 0.5F),
Map.of("test", subEntry)
);
assertThat(configContainer.setupPhase()).isEqualTo(ConfigContainerSetupPhase.TREE_SEALED);
assertThat(compoundEntry.sealed()).isTrue();
assertThat(subEntry.sealed()).isTrue();
assertThat(configContainer.setupPhase()).isEqualTo(ConfigContainerSetupPhase.TREE_SETUP);
configContainer.attachTree(compoundEntry);
assertThat(configContainer.setupPhase()).isEqualTo(ConfigContainerSetupPhase.TREE_ATTACHED);
assertThat(configContainer.rootEntry()).isSameAs(compoundEntry);
}
@@ -155,21 +155,23 @@ class DefaultConfigContainerTest {
assertThat(((ExtensionBData) extensionsData).test()).isEqualTo("blub");
}
@SuppressWarnings("unchecked")
@Test
void initialize() {
var configContainer = new DefaultConfigContainer<Map<String, Object>>();
var compoundEntry = new StaticMapCompoundConfigEntryImpl<>(
(Class<Map<String, Object>>)(Class<?>) Map.class,
(capacity) -> new HashMap<>(capacity * 2, 0.5F)
);
var subEntry = new SimpleConfigEntryImpl<>(String.class);
compoundEntry.addSubEntry("test", subEntry);
configContainer.registerExtension(ExtensionInitTracker.class);
configContainer.finishExtensionSetup();
configContainer.attachAndSealTree(compoundEntry);
assertThat(configContainer.setupPhase()).isEqualTo(ConfigContainerSetupPhase.TREE_SEALED);
var subEntry = new SimpleConfigEntryImpl<>(configContainer, String.class);
var compoundEntry = new StaticMapCompoundConfigEntryImpl<>(
configContainer,
(Class<Map<String, Object>>)(Class<?>) Map.class,
(capacity) -> new HashMap<>(capacity * 2, 0.5F),
Map.of("test", subEntry)
);
configContainer.attachTree(compoundEntry);
assertThat(configContainer.setupPhase()).isEqualTo(ConfigContainerSetupPhase.TREE_ATTACHED);
configContainer.initialize();
assertThat(configContainer.setupPhase()).isEqualTo(ConfigContainerSetupPhase.READY);