валидация для ClearingMemberCategory. есть проблема с clearing-utils, при сборке maven его не видит, возможно была ошибка при добавлении модуля

This commit is contained in:
akulikov 2023-04-02 20:29:39 +03:00
parent ee86ba8340
commit a7875f2396
20 changed files with 839 additions and 13 deletions

View file

@ -86,6 +86,10 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-messaging</artifactId>
</dependency>
</dependencies>
<build>
<resources>

View file

@ -0,0 +1,7 @@
package ru.spcex.clearing.validation.common.context;
public interface IValidatorContext {
default <S> S getStoredObject(Enum<?> storedObject) {
throw new UnsupportedOperationException("not implemented");
}
}

View file

@ -0,0 +1,54 @@
package ru.spcex.clearing.validation.common.context;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.imdg.api.Imdg;
import java.util.HashMap;
import java.util.Map;
public class ImdgValidationContext<T> implements IValidatorContext {
private final Map<String, Imdg<?>> imdgs;
private final Map<Enum<?>, Object> storedObjects;
private T validatedObject;
public ImdgValidationContext() {
this.imdgs = new HashMap<>();
this.storedObjects = new HashMap<>();
}
public void addImdg(String key, Imdg<?> imdg) {
imdgs.put(key, imdg);
}
public void setValidatedObject(T validatedObject) {
this.validatedObject = validatedObject;
}
public T getValidatedObject() {
return validatedObject;
}
/**
* !!!не использовать один Enum в разных местах
*/
public void storeObject(Enum<?> storedObject, Object anyObject) {
storedObjects.put(storedObject, anyObject);
}
@Override
@SuppressWarnings("unchecked")
public <S> S getStoredObject(Enum<?> storedObject) {
Object o = storedObjects.get(storedObject);
return (S) o;
}
@SuppressWarnings("unchecked")
public <V extends SpcexObjectBase> Imdg<V> obtainMap(String mapName, Class<V> clazz) {
Imdg<?> imdg = imdgs.get(mapName);
if (imdg == null) {
throw new IllegalStateException(mapName + " imdg wasn't added to validation context");
}
return (Imdg<V>) imdg;
}
}

View file

@ -0,0 +1,61 @@
package ru.spcex.clearing.validation.common.rules;
import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
import java.time.LocalDate;
import java.util.Optional;
import java.util.function.Function;
/**
* Проверка поля с LocalDate. Условие проверки: поверяемая дата >= текущая дата
* @param <R> Класс проверяемого объекта
*/
public record DateNotBeforeRule<R>(
String fieldName,
Function<R, LocalDate> getter,
IEnumId errorEmptyRequiredValue,
IEnumId errorTaskForPastDate,
boolean required
) implements IValidationRule<ImdgValidationContext<R>> {
/**
* @param fieldName Название поля класса, используется для передачи ошибки
* @param getter Метод получения проверяемой даты
* @param required Флаг обязательности поля
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param errorTaskForPastDate Ошибка, которая будет возвращена, если проверяемая дата меньше текущей
* @param <R> Класс проверяемого объекта
*/
public static <R> DateNotBeforeRule<R> instance(String fieldName,
Function<R, LocalDate> getter,
IEnumId errorEmptyRequiredValue,
IEnumId errorTaskForPastDate,
boolean required) {
return new DateNotBeforeRule<>(fieldName, getter, errorEmptyRequiredValue, errorTaskForPastDate, required);
}
/**
* @param fieldName Название поля класса, используется для передачи ошибки
* @param getter Метод получения проверяемой даты
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param errorTaskForPastDate Ошибка, которая будет возвращена, если проверяемая дата меньше текущей
* @param <R> Класс проверяемого объекта
*/
public static <R> DateNotBeforeRule<R> instance(String fieldName,
Function<R, LocalDate> getter,
IEnumId errorEmptyRequiredValue,
IEnumId errorTaskForPastDate) {
return new DateNotBeforeRule<>(fieldName, getter, errorEmptyRequiredValue, errorTaskForPastDate, true);
}
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<R> context) {
R validatedObject = context.getValidatedObject();
LocalDate date = getter.apply(validatedObject);
if (date == null) return required ? of(errorEmptyRequiredValue, fieldName) : Optional.empty();
if (date.isBefore(LocalDate.now())) return of(errorTaskForPastDate, fieldName);
return Optional.empty();
}
}

View file

@ -0,0 +1,102 @@
package ru.spcex.clearing.validation.common.rules;
import ru.clearing.platform.dictionary.AbstractDictionary;
import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Function;
/**
* Проверка поля с кодом из словаря (таблицы *_dictionary)
* @param <R> Класс проверяемого объекта
* @param <D> Класс словаря
*/
public record DictionaryPresentRule<R, D extends AbstractDictionary>(String fieldName,
Function<R, String> getter,
String dictionaryName,
Class<D> dictionaryClass,
IEnumId errorEmptyRequiredValue,
IEnumId errorWrongDictionaryValue,
boolean required) implements IValidationRule<ImdgValidationContext<R>> {
/**
* @param fieldName Название поля
* @param getter Метод получения проверяемого значения
* @param dictionaryName Название словаря (см. IMDGDistributedNames)
* @param dictionaryClass Класс словаря (классы *Dictionary.class)
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param errorWrongDictionaryValue Ошибка, которая будет возвращена, если поле не найдено в словаре
* @param required Флаг обязательности
* @param <R> Класс проверяемого объекта
* @param <D> Класс словаря
*/
public static <R, D extends AbstractDictionary> DictionaryPresentRule<R, D> instance(String fieldName,
Function<R, String> getter,
String dictionaryName,
Class<D> dictionaryClass,
IEnumId errorEmptyRequiredValue,
IEnumId errorWrongDictionaryValue,
boolean required) {
return new DictionaryPresentRule<>(fieldName,
getter,
dictionaryName,
dictionaryClass,
errorWrongDictionaryValue,
errorEmptyRequiredValue,
required);
}
/**
* @param fieldName Название поля
* @param getter Метод получения проверяемого значения
* @param dictionaryName Название словаря (см. IMDGDistributedNames)
* @param dictionaryClass Класс словаря (классы *Dictionary.class)
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param errorWrongDictionaryValue Ошибка, которая будет возвращена, если поле не найдено в словаре
* @param <R> Класс проверяемого объекта
* @param <D> Класс словаря
*/
public static <R, D extends AbstractDictionary> DictionaryPresentRule<R, D> instance(String fieldName,
Function<R, String> getter,
String dictionaryName,
Class<D> dictionaryClass,
IEnumId errorEmptyRequiredValue,
IEnumId errorWrongDictionaryValue) {
return new DictionaryPresentRule<>(fieldName,
getter,
dictionaryName,
dictionaryClass,
errorEmptyRequiredValue,
errorWrongDictionaryValue,
true);
}
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<R> context) {
R validatedObject = context.getValidatedObject();
String enumCode = getter.apply(validatedObject);
if (enumCode == null) return required ? of(errorEmptyRequiredValue, fieldName) : empty();
Imdg<D> dictImdg = context.obtainMap(
dictionaryName,
dictionaryClass
);
ImdgPredicateBuilder imdgPredicateBuilder = dictImdg.predicateBuilder();
ImdgPredicate imdgPredicate = imdgPredicateBuilder.equals("code", enumCode);
Collection<D> fromMap = dictImdg.getCollectionObjectsByPredicate(imdgPredicate);
if (fromMap.isEmpty()) {
return of(errorWrongDictionaryValue, fieldName);
}
assert fromMap.size() == 1;
D dictionaryFromMap = fromMap.iterator().next();
if (dictionaryFromMap == null) {
return of(errorWrongDictionaryValue, fieldName);
}
return empty();
}
}

View file

@ -1,10 +1,9 @@
package ru.spcex.clearing.validation.common;
package ru.spcex.clearing.validation.common.rules;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
import ru.spcex.platform.utils.enumeration.IEnumKey;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.util.Optional;
import java.util.function.Function;
@ -25,6 +24,8 @@ public record EnumPresentRule<R, E extends IEnumKey>(String fieldName,
* @param fieldName Название поля
* @param getter Метод получения проверяемого значения
* @param enumValues Значения из проверяемого множества (Enum.values())
* @param errorWrongEnumValue Ошибка, которая будет возвращена, если поле не найдено в Enum
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param required Флаг обязательности
* @param <R> Класс проверяемого объекта
* @param <E> Enum
@ -44,6 +45,8 @@ public record EnumPresentRule<R, E extends IEnumKey>(String fieldName,
* @param fieldName Название поля
* @param getter Метод получения проверяемого значения
* @param enumValues Значения из проверяемого множества (Enum.values())
* @param errorWrongEnumValue Ошибка, которая будет возвращена, если поле не найдено в Enum
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param <R> Класс проверяемого объекта
* @param <E> Enum
*/

View file

@ -1,24 +1,29 @@
package ru.spcex.clearing.validation.common;
package ru.spcex.clearing.validation.common.rules;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.util.Optional;
import java.util.function.Function;
/**
* Проверка обязательности поля (not null)
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param <R> Класс проверяемого объекта
* @param <V> Класс проверяемого значения
*/
public record FieldRequiredRule<R, V>(String fieldName, Function<R, V> getter, IEnumId errorEmptyRequiredValue) implements IValidationRule<ImdgValidationContext<R>> {
public record FieldRequiredRule<R, V>(
String fieldName,
Function<R, V> getter,
IEnumId errorEmptyRequiredValue
) implements IValidationRule<ImdgValidationContext<R>> {
/**
* @param fieldName Название поля
* @param getter Метод получения значения
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param <R> Класс проверяемого объекта
* @param <V> Класс проверяемого значения
*/

View file

@ -0,0 +1,44 @@
package ru.spcex.clearing.validation.common.rules;
import ru.spcex.clearing.validation.common.context.IValidatorContext;
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();
}
}

View file

@ -0,0 +1,105 @@
package ru.spcex.clearing.validation.common.rules;
import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
import java.util.Optional;
import java.util.function.Function;
/**
* Проверка наличия связанного по Id объекта в базе
* @param <R> Класс проверяемого объекта
* @param <V> Класс связанного объекта
*/
public record IdPresentRule<R, V extends SpcexObjectBase>(
String fieldName,
Function<R, Long> idGetter,
String mapName,
Class<V> mapClass,
IEnumId errorEmptyRequiredValue,
IEnumId errorIdNotPresent,
boolean required,
Function<V, IEnumId>[] additionalChecks
) implements IValidationRule<ImdgValidationContext<R>> {
/**
* @param fieldName Название поля, содержащего Id
* @param idGetter Метод получения Id
* @param mapName Название мапы связанного объекта (см. IMDGDistributedNames)
* @param mapClass Класс связанного объекта
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param errorIdNotPresent Ошибка, которая будет возвращена, если Id не найден
* @param required Флаг обязательности
* @param additionalChecks Дополнительные проверки, которые можно провести со связанным объектом
* @param <R> Класс проверяемого объекта
* @param <V> Класс связанного объекта
*/
@SafeVarargs
public static <R, V extends SpcexObjectBase> IdPresentRule<R, V> instance(String fieldName,
Function<R, Long> idGetter,
String mapName,
Class<V> mapClass,
IEnumId errorEmptyRequiredValue,
IEnumId errorIdNotPresent,
boolean required,
Function<V, IEnumId> ... additionalChecks) {
return new IdPresentRule<>(fieldName,
idGetter,
mapName,
mapClass,
errorEmptyRequiredValue,
errorIdNotPresent,
required,
additionalChecks);
}
/**
* @param fieldName Название поля, содержащего Id
* @param idGetter Метод получения Id
* @param mapName Название мапы связанного объекта (см. IMDGDistributedNames)
* @param mapClass Класс связанного объекта
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param errorIdNotPresent Ошибка, которая будет возвращена, если Id не найден
* @param additionalChecks Дополнительные проверки, которые можно провести со связанным объектом
* @param <R> Класс проверяемого объекта
* @param <V> Класс связанного объекта
*/
@SafeVarargs
public static <R, V extends SpcexObjectBase> IdPresentRule<R, V> instance(String fieldName,
Function<R, Long> idGetter,
String mapName,
Class<V> mapClass,
IEnumId errorEmptyRequiredValue,
IEnumId errorIdNotPresent,
Function<V, IEnumId> ... additionalChecks) {
return new IdPresentRule<>(fieldName,
idGetter,
mapName,
mapClass,
errorEmptyRequiredValue,
errorIdNotPresent,
true,
additionalChecks);
}
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<R> context) {
R validatedObject = context.getValidatedObject();
Long id = idGetter.apply(validatedObject);
if (id == null) return required ? of(errorEmptyRequiredValue, fieldName) : empty();
Imdg<V> imdg = context.obtainMap(mapName, mapClass);
V fromMap = imdg.getSingleObjectByID(id);
if (fromMap == null) {
return of(errorIdNotPresent, fieldName);
}
for (Function<V, IEnumId> additionalCheck : additionalChecks) {
IEnumId validationError = additionalCheck.apply(fromMap);
if (validationError != null)
return of(validationError, fieldName);
}
return empty();
}
}

View file

@ -0,0 +1,61 @@
package ru.spcex.clearing.validation.common.rules;
import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
import java.time.LocalTime;
import java.util.Optional;
import java.util.function.Function;
/**
* Проверка поля с LocalTime. Условие проверки: проверяемое время >= текущее время
* @param <R> Класс проверяемого объекта
*/
public record TimeNotBeforeRule<R>(
String fieldName,
Function<R, LocalTime> getter,
IEnumId errorEmptyRequiredValue,
IEnumId errorTaskForPastTime,
boolean required
) implements IValidationRule<ImdgValidationContext<R>> {
/**
* @param fieldName Название поля класса, используется для передачи ошибки
* @param getter Метод получения проверяемого времени
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param errorTaskForPastTime Ошибка, которая будет возвращена, если проверяемое время меньше текущего
* @param required Флаг обязательности поля
* @param <R> Класс проверяемого объекта
*/
public static <R> TimeNotBeforeRule<R> instance(String fieldName,
Function<R, LocalTime> getter,
IEnumId errorEmptyRequiredValue,
IEnumId errorTaskForPastTime,
boolean required) {
return new TimeNotBeforeRule<>(fieldName, getter, errorEmptyRequiredValue, errorTaskForPastTime, required);
}
/**
* @param fieldName Название поля класса, используется для передачи ошибки
* @param getter Метод получения проверяемого времени
* @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param errorTaskForPastTime Ошибка, которая будет возвращена, если проверяемое время меньше текущего
* @param <R> Класс проверяемого объекта
*/
public static <R> TimeNotBeforeRule<R> instance(String fieldName,
Function<R, LocalTime> getter,
IEnumId errorEmptyRequiredValue,
IEnumId errorTaskForPastTime) {
return new TimeNotBeforeRule<>(fieldName, getter, errorEmptyRequiredValue, errorTaskForPastTime, true);
}
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<R> context) {
R validatedObject = context.getValidatedObject();
LocalTime date = getter.apply(validatedObject);
if (date == null) return required ? of(errorEmptyRequiredValue, fieldName) : Optional.empty();
if (date.isBefore(LocalTime.now())) return of(errorTaskForPastTime, fieldName);
return Optional.empty();
}
}

View file

@ -0,0 +1,46 @@
package ru.spcex.clearing.validation.common.validator;
import ru.spcex.clearing.validation.common.rules.IValidationRule;
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();
default <S> S getStored(Enum<?> storedObject) {
throw new UnsupportedOperationException("not implemented");
}
}

View file

@ -0,0 +1,36 @@
package ru.spcex.clearing.validation.common.validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.platform.messaging.service.Status;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import java.util.Optional;
import java.util.function.Function;
public class ValidationHelper {
private final static Logger log = LoggerFactory.getLogger(ValidationHelper.class);
public static <R> RequestInfoUpdate validate(BaseRequest<R> userRequest,
Function<R, IValidator> validatorBuilder,
IMessageResolver messageResolver) {
if (validatorBuilder != null) {
R req = userRequest.getRequestPayload();
IValidator validator = validatorBuilder.apply(req);
Optional<EnumMessage> validationError = validator.tillFirstError();
if (validationError.isPresent()) {
String errorMsg = messageResolver.resolve(validationError.get());
log.error("validation error for {} error={}, id={}: {}", req.getClass().getSimpleName(), validationError.get().getSubject(), userRequest.getId(), errorMsg);
return new RequestInfoUpdate()
.setId(userRequest.getId())
.setStatus(Status.Error)
.setMessage(errorMsg);
}
}
return null;
}
}

View file

@ -0,0 +1,113 @@
package ru.spcex.clearing.validation.common.validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.spcex.clearing.validation.common.context.IValidatorContext;
import ru.spcex.clearing.validation.common.rules.IValidationRule;
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();
}
@Override
public <S> S getStored(Enum<?> storedObject) {
return context.getStoredObject(storedObject);
}
public C getContext() {
return context;
}
}

View file

@ -0,0 +1,114 @@
//package ru.spcex.clearing.company.config.validation;
//
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import ru.clearing.classes.statics.data.company.Company;
//import ru.clearing.classes.statics.data.generated.ClearingMemberCategory;
//import ru.clearing.platform.dictionary.ClearingCategoryDictionary;
//import ru.spcex.clearing.company.error.CompanyErrors;
//import ru.spcex.clearing.imdg.IMDGDistributedNames;
//import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
//import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryNewRequest;
//import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryUpdateRequest;
//import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
//import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
//import ru.spcex.clearing.validation.common.rules.EnumPresentRule;
//import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
//import ru.spcex.clearing.validation.common.rules.IdPresentRule;
//import ru.spcex.clearing.validation.common.validator.IValidator;
//import ru.spcex.clearing.validation.common.validator.ValidatorImpl;
//import ru.spcex.platform.classes.base.SpcexObjectBase;
//import ru.spcex.platform.enumeration.ClearingCategory;
//import ru.spcex.platform.enumeration.WorkflowStatus;
//import ru.spcex.platform.imdg.api.Imdg;
//
//import java.util.Map;
//import java.util.function.Consumer;
//import java.util.function.Function;
//
//@Configuration
//public class ClearingMemberCategoryValidationConfig {
//
// @Bean("clearingMemberCategoryNewRequestValidator")
// public Function<ClearingMemberCategoryNewRequest, IValidator> clearingMemberCategoryNewRequestValidator(
// Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
// ) {
// return clearingMemberCategoryNewRequest -> {
// ImdgValidationContext<ClearingMemberCategoryNewRequest> context = new ImdgValidationContext<>();
// context.setValidatedObject(clearingMemberCategoryNewRequest);
// Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
// addImdg.accept(IMDGDistributedNames.Map_Company);
// return new ValidatorImpl<>(context,
// IdPresentRule.instance("companyId",
// ClearingMemberCategoryNewRequest::getCompanyId,
// IMDGDistributedNames.Map_Company,
// Company.class,
// CompanyErrors.RequiredFieldEmpty,
// CompanyErrors.CompanyNotFound,
// company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : CompanyErrors.CompanyDisabled),
// FieldRequiredRule.instance("clearingMemberCategory",
// ClearingMemberCategoryNewRequest::getClearingMemberCategory,
// CompanyErrors.RequiredFieldEmpty));
// };
// }
//
// @Bean("clearingMemberCategoryUpdateRequestValidator")
// public Function<ClearingMemberCategoryUpdateRequest, IValidator> clearingMemberCategoryUpdateRequestValidator(
// Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
// ) {
// return clearingMemberCategoryUpdateRequest -> {
// ImdgValidationContext<ClearingMemberCategoryUpdateRequest> context = new ImdgValidationContext<>();
// context.setValidatedObject(clearingMemberCategoryUpdateRequest);
// Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
// addImdg.accept(IMDGDistributedNames.Map_Company);
// addImdg.accept(IMDGDistributedNames.Map_ClearingMemberCategory);
// return new ValidatorImpl<>(context,
// IdPresentRule.instance("id",
// ClearingMemberCategoryUpdateRequest::getId,
// IMDGDistributedNames.Map_ClearingMemberCategory,
// ClearingMemberCategory.class,
// CompanyErrors.RequiredFieldEmpty,
// CompanyErrors.CategoryNotFound,
// clearingMemberCategory -> {
// Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
// Company company = companyImdg.getSingleObjectByID(clearingMemberCategory.getCompanyId());
// if (company == null) return CompanyErrors.CompanyNotFound;
// if (!WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()))
// return CompanyErrors.CompanyDisabled;
// return null;
// }),
// EnumPresentRule.instance("clearingMemberCategory",
// ClearingMemberCategoryUpdateRequest::getClearingMemberCategory,
// ClearingCategory.values(),
// CompanyErrors.WrongFieldValue,
// CompanyErrors.RequiredFieldEmpty),
// DictionaryPresentRule.instance("clearingMemberCategory",
// ClearingMemberCategoryUpdateRequest::getClearingMemberCategory,
// IMDGDistributedNames.Map_ClearingCategoryDictionary,
// ClearingCategoryDictionary.class,
// CompanyErrors.RequiredFieldEmpty,
// CompanyErrors.WrongFieldValue));
// };
// }
//
// @Bean("clearingMemberCategoryDeleteRequestValidator")
// public Function<CommonDeleteRequest, IValidator> clearingMemberCategoryDeleteRequestValidator(
// Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
// ) {
// return clearingMemberCategoryDeleteRequest -> {
// ImdgValidationContext<CommonDeleteRequest> context = new ImdgValidationContext<>();
// context.setValidatedObject(clearingMemberCategoryDeleteRequest);
// Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
// addImdg.accept(IMDGDistributedNames.Map_ClearingMemberCategory);
// return new ValidatorImpl<>(context,
// IdPresentRule.instance("id",
// CommonDeleteRequest::getId,
// IMDGDistributedNames.Map_ClearingMemberCategory,
// ClearingMemberCategory.class,
// CompanyErrors.RequiredFieldEmpty,
// CompanyErrors.CategoryNotFound)
// );
// };
// }
//
//}

View file

@ -0,0 +1,30 @@
//package ru.spcex.clearing.company.config.validation;
//
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import ru.clearing.classes.statics.data.company.Company;
//import ru.clearing.classes.statics.data.generated.ClearingMemberCategory;
//import ru.spcex.clearing.imdg.IMDGDistributedNames;
//import ru.spcex.platform.classes.base.SpcexObjectBase;
//import ru.spcex.platform.imdg.api.Imdg;
//import ru.spcex.platform.imdg.api.ImdgProvider;
//
//import java.util.HashMap;
//import java.util.Map;
//import java.util.function.BiConsumer;
//
//@Configuration
//public class ValidationConfig {
//
// @Bean("imdgForValidation")
// public Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation(ImdgProvider imdgProvider) {
// final Map<String, Imdg<? extends SpcexObjectBase>> imdg = new HashMap<>();
// BiConsumer<String, Class<? extends SpcexObjectBase>> addImdg = (s, aClass) -> imdg.put(s, imdgProvider.getImdg(s, aClass));
//
// addImdg.accept(IMDGDistributedNames.Map_Company, Company.class);
// addImdg.accept(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
//
// return imdg;
// }
//
//}

View file

@ -8,7 +8,7 @@ public enum CompanyErrors implements IEnumId {
RequiredFieldEmpty(3002L), // Не заданы обязательные поля %s.
DictionaryNotFound(3003L), // Запись с идентификатором %s в справочнике %s не найдена.
VrongFieldValue(3004L), // Неверное значение поля %s.
WrongFieldValue(3004L), // Неверное значение поля %s.
RecordAlreadyExist(3005L), // Запись с идентификатором %s уже существует.
RecordNotFound(3006L), // Запись с идентификатором %s не найдена.
CompanyALreadyExist(3010L), // Компания %s уже существует

View file

@ -15,19 +15,40 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques
import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryUpdateRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
@Service
public class ClearingMemberCategoryService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<ClearingMemberCategory> clearingMemberCategoryMap;
private final IMessageResolver messageResolver;
/*
private final Function<ClearingMemberCategoryNewRequest, IValidator> clearingMemberCategoryNewRequestValidator;
private final Function<ClearingMemberCategoryUpdateRequest, IValidator> clearingMemberCategoryUpdateRequestValidator;
private final Function<CommonDeleteRequest, IValidator> clearingMemberCategoryDeleteRequestValidator;
*/
@Autowired
public ClearingMemberCategoryService(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaProducer,
ImdgProvider imdgProvider) {
public ClearingMemberCategoryService(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaProducer,
ImdgProvider imdgProvider,
IMessageResolver messageResolver /*,
@Qualifier("clearingMemberCategoryNewRequestValidator") Function<ClearingMemberCategoryNewRequest, IValidator> clearingMemberCategoryNewRequestValidator,
@Qualifier("clearingMemberCategoryUpdateRequestValidator") Function<ClearingMemberCategoryUpdateRequest, IValidator> clearingMemberCategoryUpdateRequestValidator,
@Qualifier("clearingMemberCategoryDeleteRequestValidator") Function<CommonDeleteRequest, IValidator> clearingMemberCategoryDeleteRequestValidator */) {
super(kafkaQueue, kafkaProducer);
this.clearingMemberCategoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
this.messageResolver = messageResolver;
/*
this.clearingMemberCategoryNewRequestValidator = clearingMemberCategoryNewRequestValidator;
this.clearingMemberCategoryUpdateRequestValidator = clearingMemberCategoryUpdateRequestValidator;
this.clearingMemberCategoryDeleteRequestValidator = clearingMemberCategoryDeleteRequestValidator;
*/
}
@Override
@ -44,19 +65,29 @@ public class ClearingMemberCategoryService extends QueueConsumer implements Init
init();
}
private void clearingMemberCategoryNew(BaseRequest<ClearingMemberCategoryNewRequest> userRequest) {
private RequestInfoUpdate clearingMemberCategoryNew(BaseRequest<ClearingMemberCategoryNewRequest> userRequest) {
ClearingMemberCategoryNewRequest req = userRequest.getRequestPayload();
// RequestInfoUpdate requestInfoUpdate = ValidationHelper.validate(userRequest, clearingMemberCategoryNewRequestValidator, messageResolver);
// if (requestInfoUpdate != null) return requestInfoUpdate;
log.debug("ClearingMemberCategoryUpdateRequest received {}", userRequest.getId());
ClearingMemberCategory newCategory = new ClearingMemberCategory();
newCategory.setCompanyId(req.getCompanyId());
newCategory.setClearingMemberCategory(req.getClearingMemberCategory());
clearingMemberCategoryMap.insert(newCategory);
log.debug("successfully processed, new category id {}", newCategory.getId());
return null;
}
public void clearingMemberCategoryUpdate(BaseRequest<ClearingMemberCategoryUpdateRequest> userRequest) {
public RequestInfoUpdate clearingMemberCategoryUpdate(BaseRequest<ClearingMemberCategoryUpdateRequest> userRequest) {
ClearingMemberCategoryUpdateRequest req = userRequest.getRequestPayload();
// RequestInfoUpdate requestInfoUpdate = ValidationHelper.validate(userRequest, clearingMemberCategoryUpdateRequestValidator, messageResolver);
// if (requestInfoUpdate != null) return requestInfoUpdate;
log.debug("ClearingMemberCategoryUpdateRequest received");
ClearingMemberCategory clearingMemberCategory = clearingMemberCategoryMap.getSingleObjectByID(req.getId());
@ -64,12 +95,19 @@ public class ClearingMemberCategoryService extends QueueConsumer implements Init
clearingMemberCategoryMap.update(clearingMemberCategory);
log.debug("successfully processed, id {}", clearingMemberCategory.getId());
return null;
}
private void clearingMemberCategoryDelete(BaseRequest<CommonDeleteRequest> userRequest) {
private RequestInfoUpdate clearingMemberCategoryDelete(BaseRequest<CommonDeleteRequest> userRequest) {
CommonDeleteRequest req = userRequest.getRequestPayload();
// RequestInfoUpdate requestInfoUpdate = ValidationHelper.validate(userRequest, clearingMemberCategoryDeleteRequestValidator, messageResolver);
// if (requestInfoUpdate != null) return requestInfoUpdate;
log.debug("CommonDeleteRequest received id = {}", req.getId());
ClearingMemberCategory clearingMemberCategory = clearingMemberCategoryMap.getSingleObjectByID(req.getId());
clearingMemberCategoryMap.delete(clearingMemberCategory);
return null;
}
}

View file

@ -7,6 +7,7 @@ public class CommonDeleteRequest implements WithId {
@JsonProperty
public Long id;
@Override
public Long getId() {
return id;
}

View file

@ -171,6 +171,7 @@ public class QueueConsumer implements AutoCloseable {
* @param <R> Класс проверяемого запроса
* @return null если ошибок нет
*/
@Deprecated
public <R> RequestInfoUpdate validate(BaseRequest<R> userRequest,
Function<R, IValidator> validatorBuilder,
IMessageResolver messageResolver) {

View file

@ -10,6 +10,7 @@ import java.util.Optional;
* Все необходимые данные берет из контекста
* @param <C> контекст
*/
// todo move this to clearing-utils (or move clearing-utils
public interface IValidationRule<C extends IValidatorContext> {
Optional<EnumMessage> validate(C context);