ConfigHandler.java

package de.dlr.bt.stc.config;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.configuration2.CombinedConfiguration;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.HierarchicalConfiguration;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.tree.OverrideCombiner;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public final class ConfigHandler {
	private ConfigHandler() {
	}

	public static final String EXTENSION_KEY = "extends";
	public static final String ABSTRACT_KEY = "abstract";

	public static Map<String, HierarchicalConfiguration<?>> separateAndResolveConfigs(
			List<HierarchicalConfiguration<?>> mainConfigs) {
		return separateAndResolveConfigs(mainConfigs, EXTENSION_KEY, ABSTRACT_KEY);
	}

	public static Map<String, HierarchicalConfiguration<?>> separateAndResolveConfigs(
			List<HierarchicalConfiguration<?>> mainConfigs, String extensionKey, String abstractKey) {

		Map<String, Configuration> configurations = new HashMap<>();

		for (var mainConfig : mainConfigs) {
			var cfgs = mainConfig.childConfigurationsAt("");

			for (var cfg : cfgs) {
				final String rootElementName = cfg.getRootElementName();
				if (configurations.containsKey(rootElementName))
					log.warn("Duplicate configuration key {}", rootElementName);
				configurations.put(rootElementName, cfg);
			}
		}

		Map<String, HierarchicalConfiguration<?>> finalConfigs = new HashMap<>();

		OverrideCombiner override = new OverrideCombiner();

		for (var entry : configurations.entrySet()) {
			if (!entry.getValue().getBoolean(abstractKey, false)) {
				CombinedConfiguration cc = new CombinedConfiguration(override);
				try {
					addConfigurationRecursive(cc, entry.getKey(), entry.getValue(), configurations, extensionKey);

					finalConfigs.put(entry.getKey(), cc);
				} catch (ConfigurationException ce) {
					log.error("Failed to parse configuration file: {}", ce.toString());
				}
			}
		}

		return finalConfigs;
	}

	private static void addConfigurationRecursive(CombinedConfiguration cc, String key, Configuration cfg,
			Map<String, Configuration> other, String extensionKey) throws ConfigurationException {

		cc.addConfiguration(cfg);
		if (cfg.containsKey(extensionKey)) {
			var base = cfg.getString(extensionKey);
			var basecfg = other.get(base);
			if (basecfg != null)
				addConfigurationRecursive(cc, base, basecfg, other, extensionKey);
			else
				throw new ConfigurationException(
						"Invalid configuration %s, base element %s not found!".formatted(key, base));
		}
	}
}