/******************************************************************************* * Copyright 2019 Graz University of Technology * MOA ZS has been developed in a cooperation between EGIZ * and Graz University of Technology. * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. *******************************************************************************/ package at.gv.egiz.moazs.preprocess; import at.gv.egiz.moazs.MoaZSException; import at.gv.egiz.moazs.util.StringUtils; 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 at.gv.egiz.moazs.MoaZSException.moaZSException; import static java.lang.String.format; import static java.util.stream.Collectors.*; /** * @author Christof Rabensteiner * */ 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 MzsDeliveryRequestValidator validator; 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, MzsDeliveryRequestValidator validator, boolean verifyCompletenessOfDefaultConfiguration, String profilePrefix, String defaultConfigKey) { this.util = util; this.properties = properties; this.validator = validator; this.verifyCompletenessOfDefaultConfiguration = verifyCompletenessOfDefaultConfiguration; this.profilePrefix = profilePrefix; this.defaultConfigKey = defaultConfigKey; } /** * Generate a map of Config profiles on the basis of supplied properties. * * @return map with profiles, indexed by ProfileId */ public Map generate() { var groupedKeys = properties.getPropertyNames() .filter(this::isConfigurationProfileProperty) .map(StringUtils::removePrefix) .filter(StringUtils::hasPrefix) .collect(groupingBy(StringUtils::keepPrefix, mapping(StringUtils::removePrefix, toSet()))); var profiles = groupedKeys.entrySet().stream() .collect(toUnmodifiableMap(Entry::getKey, this::createConfigFromEnv)); var defaultProfile = profiles.get(defaultConfigKey); try { validator.isConfigProfileComplete(defaultProfile); } catch (MoaZSException ex) { if (verifyCompletenessOfDefaultConfiguration) throw moaZSException(format("%s Reason: %s", PROFILE_NOT_COMPLETE_ERROR_MESSAGE, ex.getMessage())); else { LOGGER.warn(PROFILE_NOT_COMPLETE_WARNING_MESSAGE); } } return defaultProfile == null ? profiles : mergeProfiles(profiles, defaultProfile); } private boolean isConfigurationProfileProperty(String propName) { return propName.startsWith(profilePrefix + "."); } 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 MzsDeliveryRequestValidator validator; private boolean verify = 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 withValidator(MzsDeliveryRequestValidator validator) { this.validator = validator; return this; } public ConfigProfileGeneratorBuilder withVerifyCompletenessOfDefaultConfiguration( boolean verify) { this.verify = verify; 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 || validator == null) throw new IllegalArgumentException("Cannot build ConfigProfileGenerator: " + "One or more arguments are null."); return new ConfigProfileGenerator(properties, util, validator, verify, profilePrefix, defaultConfigKey); } } }