From 0d3f6d8033efaab396bba31e0e93e2645dafd054 Mon Sep 17 00:00:00 2001 From: ialbert Date: Wed, 21 Sep 2022 19:15:37 +0300 Subject: [PATCH] added validator --- platform-parent/platform-utils/pom.xml | 10 ++ .../utils/validation/IValidationRule.java | 43 +++++++ .../platform/utils/validation/IValidator.java | 41 +++++++ .../utils/validation/IValidatorContext.java | 3 + .../utils/validation/ValidatorImpl.java | 106 ++++++++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidationRule.java create mode 100644 platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidator.java create mode 100644 platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidatorContext.java create mode 100644 platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/ValidatorImpl.java diff --git a/platform-parent/platform-utils/pom.xml b/platform-parent/platform-utils/pom.xml index 0578697fa..94591fe86 100644 --- a/platform-parent/platform-utils/pom.xml +++ b/platform-parent/platform-utils/pom.xml @@ -25,6 +25,16 @@ spring-context provided + + ch.qos.logback + logback-core + provided + + + org.slf4j + slf4j-api + provided + \ No newline at end of file diff --git a/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidationRule.java b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidationRule.java new file mode 100644 index 000000000..3ad88a3f1 --- /dev/null +++ b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidationRule.java @@ -0,0 +1,43 @@ +package ru.spcex.platform.utils.validation; + +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumId; + +import java.util.Optional; + +/** + * Правило валидации, описывающее какую ошибку возвращать и при каких условиях + * Все необходимые данные берет из контекста + * @param контекст + */ +public interface IValidationRule { + Optional validate(C context); + + /** + * для логов + */ + default String ruleName() { + return getClass().getSimpleName(); + } + + /** + * если у валидатора был вызван метод проверить все, этот метод может использоваться для более тонкой настройки + * по дефолту - выполнять проверку даже если предыдущие выполнены с ошибками + */ + default boolean runIfErrorsPresent() { + return true; + } + + //*************** методы для сокращения кода *************** + default Optional of(IEnumId error) { + return Optional.of(new EnumMessage(error)); + } + + default Optional of(IEnumId error, Object... args) { + return Optional.of(new EnumMessage(error, args)); + } + + default Optional empty() { + return Optional.empty(); + } +} diff --git a/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidator.java b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidator.java new file mode 100644 index 000000000..a9d688c70 --- /dev/null +++ b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidator.java @@ -0,0 +1,41 @@ +package ru.spcex.platform.utils.validation; + + +import ru.spcex.platform.utils.enumeration.EnumMessage; + +import java.util.Collection; +import java.util.Optional; + +/** + * Валидатор, в который можно добавлять правила проверок. + * Будет выполнять их в том порядке, в котором их добавляли + */ +public interface IValidator { + /** + * метод для добавления правил валидации + * если положить правило с некорректными типами, при вызове validate будет ClassCastException + */ + void addRule(IValidationRule rule); + + /** + * если хотим добавить проверки другого валидатора
+ * они будут выполняться только если проверки этого успешно пройдены + * возвращает себя + */ + IValidator chain(IValidator anotherValidator); + + /** + * валидирует все (подходит для случаев когда проверки не полагаются на то что предыдущие проверки прошли нормально) + */ + Collection validateAll(); + + /** + * валидирует до первой ошибки + */ + Optional tillFirstError(); + + /** + * валидирует все, возвращает первую ошибку - для совместимости + */ + Optional validateAllReturnFirst(); +} diff --git a/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidatorContext.java b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidatorContext.java new file mode 100644 index 000000000..0a4d8d365 --- /dev/null +++ b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidatorContext.java @@ -0,0 +1,3 @@ +package ru.spcex.platform.utils.validation; + +public interface IValidatorContext {} diff --git a/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/ValidatorImpl.java b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/ValidatorImpl.java new file mode 100644 index 000000000..7cc384b55 --- /dev/null +++ b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/ValidatorImpl.java @@ -0,0 +1,106 @@ +package ru.spcex.platform.utils.validation; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.spcex.platform.utils.enumeration.EnumMessage; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +/** + * Валидатор, предназначенный для правил у которых есть "контекст" валидации + */ +public class ValidatorImpl implements IValidator { + private final Logger log = LoggerFactory.getLogger(getClass()); + private List> rules = new ArrayList<>(); + private C context; + private IValidator chainedValidator; + + public ValidatorImpl(C context) {this.context = context;} + + public ValidatorImpl(C context, IValidationRule... rules) { // + this.context = context; + for (IValidationRule rule : rules) { + addRule(rule); + } + } + + public void setContext(C context) { + this.context = context; + } + + @Override + @SuppressWarnings("unchecked") + public void addRule(IValidationRule rule) { + rules.add((IValidationRule) rule); + } + + @Override + public IValidator chain(IValidator anotherValidator) { + if (chainedValidator == null) { + chainedValidator = anotherValidator; + } else { + chainedValidator.chain(anotherValidator); + } + return this; + } + + @Override + public Collection validateAll() { + List errors = new ArrayList<>(); + Instant begin = Instant.now(); + for (IValidationRule rule : rules) { + if (rule.runIfErrorsPresent() || errors.size() == 0) { + Optional validationError; + validationError = rule.validate(context); + validationError.ifPresent(errors::add); + if (validationError.isPresent()) { + log.debug("validating stage: {} error", rule.ruleName()); + } else { + log.debug("validating stage: {} complete", rule.ruleName()); + } + } + } + log.debug("validation {} in {} ms", + errors.size() == 0 ? "successfully completed" : "completed with errors", + Instant.now().toEpochMilli() - begin.toEpochMilli()); + if (chainedValidator != null && errors.size() == 0) errors.addAll(chainedValidator.validateAll()); + return errors; + } + + @Override + public Optional tillFirstError() { + Instant begin = Instant.now(); + for (IValidationRule rule : rules) { + log.debug("validating stage: {}", rule.ruleName()); + Optional validationError; + validationError = rule.validate(context); + if (validationError.isPresent()) { + log.debug("validation stage: {} completed with error {} in {} ms", + rule.ruleName(), validationError.get().getSubject().getId(), + Instant.now().toEpochMilli() - begin.toEpochMilli()); + return validationError; + } + } + log.debug("validation successfully completed in {} ms", Instant.now().toEpochMilli() - begin.toEpochMilli()); + if (chainedValidator != null) return chainedValidator.tillFirstError(); + return Optional.empty(); + } + + @Override + public Optional validateAllReturnFirst() { + Collection allErrors = validateAll(); + if (allErrors.size() > 0) { + EnumMessage error = allErrors.iterator().next(); + return Optional.of(error); + } else + return Optional.empty(); + } + + public C getContext() { + return context; + } +}