added validator
This commit is contained in:
parent
5419765866
commit
0d3f6d8033
5 changed files with 203 additions and 0 deletions
|
|
@ -25,6 +25,16 @@
|
|||
<artifactId>spring-context</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -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 <C> контекст
|
||||
*/
|
||||
public interface IValidationRule<C extends IValidatorContext> {
|
||||
Optional<EnumMessage> validate(C context);
|
||||
|
||||
/**
|
||||
* для логов
|
||||
*/
|
||||
default String ruleName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* если у валидатора был вызван метод проверить все, этот метод может использоваться для более тонкой настройки
|
||||
* по дефолту - выполнять проверку даже если предыдущие выполнены с ошибками
|
||||
*/
|
||||
default boolean runIfErrorsPresent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
//*************** методы для сокращения кода ***************
|
||||
default Optional<EnumMessage> of(IEnumId error) {
|
||||
return Optional.of(new EnumMessage(error));
|
||||
}
|
||||
|
||||
default Optional<EnumMessage> of(IEnumId error, Object... args) {
|
||||
return Optional.of(new EnumMessage(error, args));
|
||||
}
|
||||
|
||||
default Optional<EnumMessage> empty() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* если хотим добавить проверки другого валидатора<br>
|
||||
* они будут выполняться только если проверки этого успешно пройдены
|
||||
* возвращает себя
|
||||
*/
|
||||
IValidator chain(IValidator anotherValidator);
|
||||
|
||||
/**
|
||||
* валидирует все (подходит для случаев когда проверки не полагаются на то что предыдущие проверки прошли нормально)
|
||||
*/
|
||||
Collection<EnumMessage> validateAll();
|
||||
|
||||
/**
|
||||
* валидирует до первой ошибки
|
||||
*/
|
||||
Optional<EnumMessage> tillFirstError();
|
||||
|
||||
/**
|
||||
* валидирует все, возвращает первую ошибку - для совместимости
|
||||
*/
|
||||
Optional<EnumMessage> validateAllReturnFirst();
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package ru.spcex.platform.utils.validation;
|
||||
|
||||
public interface IValidatorContext {}
|
||||
|
|
@ -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<C extends IValidatorContext> implements IValidator {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private List<IValidationRule<C>> rules = new ArrayList<>();
|
||||
private C context;
|
||||
private IValidator chainedValidator;
|
||||
|
||||
public ValidatorImpl(C context) {this.context = context;}
|
||||
|
||||
public ValidatorImpl(C context, IValidationRule<?>... rules) { //<C>
|
||||
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<C>) rule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValidator chain(IValidator anotherValidator) {
|
||||
if (chainedValidator == null) {
|
||||
chainedValidator = anotherValidator;
|
||||
} else {
|
||||
chainedValidator.chain(anotherValidator);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<EnumMessage> validateAll() {
|
||||
List<EnumMessage> errors = new ArrayList<>();
|
||||
Instant begin = Instant.now();
|
||||
for (IValidationRule<C> rule : rules) {
|
||||
if (rule.runIfErrorsPresent() || errors.size() == 0) {
|
||||
Optional<EnumMessage> 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<EnumMessage> tillFirstError() {
|
||||
Instant begin = Instant.now();
|
||||
for (IValidationRule<C> rule : rules) {
|
||||
log.debug("validating stage: {}", rule.ruleName());
|
||||
Optional<EnumMessage> 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<EnumMessage> validateAllReturnFirst() {
|
||||
Collection<EnumMessage> allErrors = validateAll();
|
||||
if (allErrors.size() > 0) {
|
||||
EnumMessage error = allErrors.iterator().next();
|
||||
return Optional.of(error);
|
||||
} else
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public C getContext() {
|
||||
return context;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue