From 6959228c5c557df0204a2902807b35d90063b600 Mon Sep 17 00:00:00 2001 From: Christof Rabensteiner Date: Wed, 15 May 2019 14:55:09 +0200 Subject: Handle Config Related Edge Cases in Augmenter & ProfileGenerator ConfigProfileGenerator: - Cancel startup if default Config profile is incomplete. - Add property flag 'verify-completeness-of-default-delivery-request-configuration', which allows admin to disable completeness check. In that case, just log a warning if the default profile is incomplete. Augmenter: - Ensure that after merging the config is complete (or throw an exception otherwise). - Refactor: Move ConfigProfileValidator from ConfigProfileGenerator to dedicated "ConfigProfileValidator" class; Reason: Augmenter needs to check completness of at-runtime-compiled configuration. - Refactor: Rewrote code for better readability. Others - NPE Fix in ConfigProfileMerger: If FallbackConfigProfile/Server is empty, use PrimaryProfile/Server. --- .../config/DeliveryRequestAugmenterConfig.java | 15 ++++++- .../moazs/preprocess/ConfigProfileGenerator.java | 48 ++++++++++++++++---- .../egiz/moazs/preprocess/ConfigProfileMerger.java | 4 ++ .../moazs/preprocess/ConfigProfileValidator.java | 17 +++++++ .../moazs/preprocess/DeliveryRequestAugmenter.java | 52 ++++++++++++++++------ src/main/resources/application.yaml | 7 ++- 6 files changed, 119 insertions(+), 24 deletions(-) create mode 100644 src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileValidator.java (limited to 'src/main') diff --git a/src/main/java/at/gv/egiz/moazs/config/DeliveryRequestAugmenterConfig.java b/src/main/java/at/gv/egiz/moazs/config/DeliveryRequestAugmenterConfig.java index d5b52c5..01d13f5 100644 --- a/src/main/java/at/gv/egiz/moazs/config/DeliveryRequestAugmenterConfig.java +++ b/src/main/java/at/gv/egiz/moazs/config/DeliveryRequestAugmenterConfig.java @@ -1,10 +1,14 @@ package at.gv.egiz.moazs.config; import at.gv.egiz.moazs.preprocess.ConfigProfileGenerator; +import at.gv.egiz.moazs.preprocess.ConfigProfileMerger; +import at.gv.egiz.moazs.preprocess.ConfigProfileValidator; import at.gv.zustellung.app2mzs.xsd.ConfigType; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.ConfigurableEnvironment; import java.util.Map; @@ -13,8 +17,17 @@ public class DeliveryRequestAugmenterConfig { @Bean @Autowired - Map deliveryRequestConfigs(ConfigProfileGenerator generator) { + public Map deliveryRequestConfigs(ConfigProfileGenerator generator) { return generator.generate(); } + @Value("${verify-completeness-of-default-delivery-request-configuration:true}") + private boolean verifyCompletenessOfDefaultConfiguration; + + @Bean + @Autowired + public ConfigProfileGenerator configProfileGenerator(ConfigurableEnvironment env, ConfigProfileMerger merger, ConfigProfileValidator validator) { + return new ConfigProfileGenerator(env, merger, verifyCompletenessOfDefaultConfiguration, validator); + } + } diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java index 21d97fc..1d79eb8 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java @@ -1,9 +1,10 @@ package at.gv.egiz.moazs.preprocess; +import at.gv.egiz.moazs.MoaZSException; import at.gv.zustellung.app2mzs.xsd.ConfigType; -import org.springframework.beans.factory.annotation.Autowired; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.env.*; -import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.HashMap; @@ -18,20 +19,37 @@ import static at.gv.zustellung.app2mzs.xsd.ServerType.serverTypeBuilder; import static java.util.stream.Collectors.*; import static java.util.stream.Collectors.toMap; -@Component public class ConfigProfileGenerator { + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigProfileGenerator.class); private static final String PROFILE_PREFIX = "delivery-request-configuration-profiles."; private static final String TNVZ_REQUEST_KEY = "perform-query-person-request"; private static final String MSG_URL_KEY = "msg.url"; + private static final String DEFAULT_CONFIG_KEY = "default"; + + private final boolean verifyCompletenessOfDefaultConfiguration; + + 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 ConfigurableEnvironment env; private final ConfigProfileMerger merger; + private final ConfigProfileValidator validator; - @Autowired - public ConfigProfileGenerator(ConfigurableEnvironment env, ConfigProfileMerger merger) { + public ConfigProfileGenerator(ConfigurableEnvironment env, ConfigProfileMerger merger, + boolean verifyCompletenessOfDefaultConfiguration, ConfigProfileValidator validator) { this.env = env; this.merger = merger; + this.verifyCompletenessOfDefaultConfiguration = verifyCompletenessOfDefaultConfiguration; + this.validator = validator; } public Map generate() { @@ -39,14 +57,27 @@ public class ConfigProfileGenerator { var groupedKeys = getStreamOfPropertyKeysFromEnv() .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("default"); + var defaultProfile = profiles.get(DEFAULT_CONFIG_KEY); - return mergeProfiles(profiles, defaultProfile); + if (!validator.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; } // @author pedorro @@ -99,6 +130,8 @@ public class ConfigProfileGenerator { .build(); } + + private Map mergeProfiles(Map profiles, ConfigType defaultProfile) { return profiles.entrySet().stream() .collect(toUnmodifiableMap( @@ -106,5 +139,4 @@ public class ConfigProfileGenerator { e -> merger.merge(e.getValue(), defaultProfile))); } - } diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileMerger.java b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileMerger.java index f25ec12..c94723e 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileMerger.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileMerger.java @@ -32,6 +32,10 @@ public class ConfigProfileMerger { private ServerType merge(ServerType primary, ServerType fallback) { + if (fallback == null) { + return primary; + } + var builder = serverTypeBuilder(fallback); if (primary.getX509() != null) builder.withX509 (primary.getX509() ); diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileValidator.java b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileValidator.java new file mode 100644 index 0000000..08d8aea --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileValidator.java @@ -0,0 +1,17 @@ +package at.gv.egiz.moazs.preprocess; + +import at.gv.zustellung.app2mzs.xsd.ConfigType; +import org.springframework.stereotype.Component; + +@Component +public class ConfigProfileValidator { + + public boolean isComplete(ConfigType profile) { + //TODO: add check fo x509 certificate + return profile != null + && profile.isPerformQueryPersonRequest() != null + && profile.getServer() != null + && profile.getServer().getZUSEUrlID() != null; + } + +} diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java b/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java index 7211f6d..0b49347 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java @@ -2,24 +2,33 @@ package at.gv.egiz.moazs.preprocess; import at.gv.zustellung.app2mzs.xsd.ConfigType; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; -import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.DeliveryRequestTypeBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Map; -import static at.gv.egiz.moazs.util.NullCoalesce.coalesce; +import static at.gv.egiz.moazs.MoaZSException.moaZSException; +import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.deliveryRequestTypeBuilder; @Component public class DeliveryRequestAugmenter { private final ConfigProfileMerger merger; private final Map configs; + private final ConfigProfileValidator validator; + + private static final String INCOMPLETE_CONFIG_ERROR_MESSAGE = "Could not find a profile for " + + "the delivery request configuration, and the configuration attached to mzs:DeliveryRequest is incomplete."; + private static final String INCOMPLETE_MERGED_CONFIG_ERROR_MESSAGE = "I merged parameters from " + + "mzs:DeliveryRequest/Config with parameters from config profile with ProfileId='%s', but the " + + "configuration is incomplete."; @Autowired - public DeliveryRequestAugmenter(Map deliveryRequestConfigs, ConfigProfileMerger merger) { + public DeliveryRequestAugmenter(Map deliveryRequestConfigs, ConfigProfileMerger merger, + ConfigProfileValidator validator) { this.configs = deliveryRequestConfigs; this.merger = merger; + this.validator = validator; } /** @@ -31,25 +40,40 @@ public class DeliveryRequestAugmenter { public DeliveryRequestType augment(DeliveryRequestType request) { var requestConfig = request.getConfig(); + var profileId = determineProfileIdFrom(requestConfig); + var fallbackConfig = configs.get(profileId); - var fallbackConfig = determineProfileFromProfileId(requestConfig); + if (fallbackConfig == null) { - var config = merger.merge(requestConfig, fallbackConfig); + if (validator.isComplete(requestConfig)) + return request; + else + throw moaZSException(INCOMPLETE_CONFIG_ERROR_MESSAGE); - return new DeliveryRequestTypeBuilder(request) - .withConfig(config) - .build(); - } + } else { - private ConfigType determineProfileFromProfileId(ConfigType requestConfig) { + var mergedConfig = merger.merge(requestConfig, fallbackConfig); - if (requestConfig == null || requestConfig.getProfileID() == null) { - return configs.get("default"); + if (validator.isComplete(mergedConfig)) { + return deliveryRequestTypeBuilder(request) + .withConfig(mergedConfig) + .build(); + } else { + throw moaZSException(INCOMPLETE_MERGED_CONFIG_ERROR_MESSAGE, profileId); + } } + } - var id = requestConfig.getProfileID(); + private String determineProfileIdFrom(ConfigType requestConfig) { + return (requestConfig == null + || requestConfig.getProfileID() == null + || isProfileMissing(requestConfig.getProfileID())) + ? "default" + : requestConfig.getProfileID(); + } - return coalesce(configs.get(id), configs.get("default")).get(); + private boolean isProfileMissing(String id) { + return !configs.containsKey(id); } } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 98987b8..9e987bf 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -25,4 +25,9 @@ delivery-request-configuration-profiles: app-profile-2: msg: - url: https://msg-url2.com \ No newline at end of file + url: https://msg-url2.com + +## If set to false, moa zs ignores an incomplete default DeliveryRequest-configuration +## profile and continues startup. See 'delivery-request-configuration-profiles'. +## Default value: true +# verify-completeness-of-default-delivery-request-configuration: false \ No newline at end of file -- cgit v1.2.3