package at.gv.egiz.moazs.preprocess; import at.gv.egiz.moazs.MoaZSException; import at.gv.zustellung.app2mzs.xsd.ConfigType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import static java.util.stream.Collectors.*; public class ConfigProfileGenerator { private static final Logger LOGGER = LoggerFactory.getLogger(ConfigProfileGenerator.class); private static final String PROFILE_NOT_COMPLETE_WARNING_MESSAGE = "The default values for a incoming " + "mzs:DeliveryRequest/Config element could not be extracted from configuration because some values were " + "missing."; private static final String PROFILE_NOT_COMPLETE_ERROR_MESSAGE = PROFILE_NOT_COMPLETE_WARNING_MESSAGE + " " + "Please verify that all default values are present (e.g. through application.{properties,yaml} " + "or System parameters). Otherwise, deactivate 'verify-completeness-of-default-delivery-request-configuration' " + "to continue operation without completing the default config profile. This means that " + "mzs:DeliveryRequest/Config needs to be configured completely *for each delivery request* in order to guarantee " + "availability."; private final SpringPropertiesFacade properties; private final ConfigUtil util; private final boolean verifyCompletenessOfDefaultConfiguration; private final String profilePrefix; private final String defaultConfigKey; public static ConfigProfileGeneratorBuilder configProfileGeneratorBuilder() { return new ConfigProfileGeneratorBuilder(); } private ConfigProfileGenerator( SpringPropertiesFacade properties, ConfigUtil util, boolean verifyCompletenessOfDefaultConfiguration, String profilePrefix, String defaultConfigKey) { this.util = util; this.properties = properties; this.verifyCompletenessOfDefaultConfiguration = verifyCompletenessOfDefaultConfiguration; this.profilePrefix = profilePrefix; this.defaultConfigKey = defaultConfigKey; } public Map generate() { var groupedKeys = properties.getPropertyNames() .filter(this::isConfigurationProfileProperty) .map(this::removePrefix) .filter(this::hasPrefix) .collect(groupingBy(this::keepPrefix, mapping(this::removePrefix, toSet()))); var profiles = groupedKeys.entrySet().stream() .collect(toMap(Entry::getKey, this::createConfigFromEnv)); var defaultProfile = profiles.get(defaultConfigKey); if (!util.isComplete(defaultProfile)) { if (verifyCompletenessOfDefaultConfiguration) throw MoaZSException.moaZSException(PROFILE_NOT_COMPLETE_ERROR_MESSAGE); else { LOGGER.warn(PROFILE_NOT_COMPLETE_WARNING_MESSAGE); } } return defaultProfile == null ? profiles : mergeProfiles(profiles, defaultProfile); } private boolean hasPrefix(String name) { return name.indexOf('.') != -1; } private boolean isConfigurationProfileProperty(String propName) { return propName.startsWith(profilePrefix + "."); } private String keepPrefix(String name) { return name.substring(0, name.indexOf('.')); } private String removePrefix(String name) { return name.substring(name.indexOf('.') + 1); } private ConfigType createConfigFromEnv(Entry> entry) { var profile = entry.getKey(); var values = new HashMap(); entry.getValue().stream() .forEach(key -> { var assembledKey = profilePrefix + '.' + profile + '.' + key; var value = properties.getProperty(assembledKey); values.put(key, value); }); return util.convert(values); } private Map mergeProfiles(Map profiles, ConfigType defaultProfile) { return profiles.entrySet().stream() .collect(toUnmodifiableMap( Entry::getKey, e -> util.merge(e.getValue(), defaultProfile))); } public static class ConfigProfileGeneratorBuilder { private SpringPropertiesFacade properties; private ConfigUtil util; private boolean verifyCompletenessOfDefaultConfiguration = true; private String profilePrefix = "delivery-request-configuration-profiles"; private String defaultConfigKey = "default"; public ConfigProfileGeneratorBuilder withProperties(SpringPropertiesFacade properties) { this.properties = properties; return this; } public ConfigProfileGeneratorBuilder withConfigUtil(ConfigUtil util) { this.util = util; return this; } public ConfigProfileGeneratorBuilder withVerifyCompletenessOfDefaultConfiguration(boolean verifyCompletenessOfDefaultConfiguration) { this.verifyCompletenessOfDefaultConfiguration = verifyCompletenessOfDefaultConfiguration; return this; } public ConfigProfileGeneratorBuilder withProfilePrefix(String profilePrefix) { this.profilePrefix = profilePrefix; return this; } public ConfigProfileGeneratorBuilder withDefaultConfigKey(String defaultConfigKey) { this.defaultConfigKey = defaultConfigKey; return this; } public ConfigProfileGenerator build() { if(properties == null || util == null || profilePrefix == null || defaultConfigKey == null) throw new IllegalArgumentException("Cannot build ConfigProfileGenerator: One or more arguments are null."); return new ConfigProfileGenerator(properties, util, verifyCompletenessOfDefaultConfiguration, profilePrefix, defaultConfigKey); } } }