From 05dfccf5e2a101fba8b369756d3f38c2b50d2b61 Mon Sep 17 00:00:00 2001 From: akulikov Date: Thu, 12 Jan 2023 14:48:35 +0300 Subject: [PATCH 01/14] http://jira.mfd.msk:8088/browse/CLS-51 add entry listener to map static Util -> bean PlannerAllTodayMaker fix condition removeIf add enum Parent(tmpl, plnr, clnd) add enum DayStatus(bday, doff) --- clearing-parent/imdg/pom.xml | 4 + .../AbstractHazelcastLifecycleSupport.java | 8 +- .../services/HazelcastLifecycleSupport.java | 4 +- .../imdg/services/PlannerAllTodayMaker.java | 115 ++++++++++++++++++ .../ru/spcex/clearing/imdg/util/Util.java | 113 ----------------- .../scheduler/service/TaskManager.java | 4 + .../spcex/platform/enumeration/DayStatus.java | 18 +++ .../ru/spcex/platform/enumeration/Parent.java | 18 +++ 8 files changed, 165 insertions(+), 119 deletions(-) create mode 100644 clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/PlannerAllTodayMaker.java delete mode 100644 clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/util/Util.java create mode 100644 platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/DayStatus.java create mode 100644 platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/Parent.java diff --git a/clearing-parent/imdg/pom.xml b/clearing-parent/imdg/pom.xml index 5a35a391a..cb06f2437 100644 --- a/clearing-parent/imdg/pom.xml +++ b/clearing-parent/imdg/pom.xml @@ -71,6 +71,10 @@ ru.spcex.platform platform-imdg-api-hazelcast-impl + + ru.spcex.platform + platform-enum + diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractHazelcastLifecycleSupport.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractHazelcastLifecycleSupport.java index 53a6dd15a..8b9ea7df8 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractHazelcastLifecycleSupport.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractHazelcastLifecycleSupport.java @@ -19,17 +19,17 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; -import static ru.spcex.clearing.imdg.util.Util.makeSchedulerAllTodayMap; - //todo почистить класс public abstract class AbstractHazelcastLifecycleSupport implements InitializingBean, DisposableBean { private final Logger log = LoggerFactory.getLogger(this.getClass()); private final HazelcastInstance hazelcastServerInstance; private final JdbcTemplate jdbcTemplate; + private final PlannerAllTodayMaker plannerAllTodayMaker; - public AbstractHazelcastLifecycleSupport(HazelcastInstance hazelcastServerInstance, JdbcTemplate jdbcTemplate) { + public AbstractHazelcastLifecycleSupport(HazelcastInstance hazelcastServerInstance, JdbcTemplate jdbcTemplate, PlannerAllTodayMaker plannerAllTodayMaker) { this.hazelcastServerInstance = hazelcastServerInstance; this.jdbcTemplate = jdbcTemplate; + this.plannerAllTodayMaker = plannerAllTodayMaker; } /** @@ -103,7 +103,7 @@ public abstract class AbstractHazelcastLifecycleSupport implements InitializingB boolean generatorResult = generator.init(maxKey); if (generatorResult) { log.info("IDGenerator {} success init by {}", IMDGDistributedNames.MAP_SEQUENCE_NAME, maxKey); - makeSchedulerAllTodayMap(hazelcastServerInstance); + plannerAllTodayMaker.makeSchedulerAllTodayMap(); } else { log.info("IDGenerator {} already initialized in other node", IMDGDistributedNames.MAP_SEQUENCE_NAME); } diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/HazelcastLifecycleSupport.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/HazelcastLifecycleSupport.java index e248a2054..bf249777b 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/HazelcastLifecycleSupport.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/HazelcastLifecycleSupport.java @@ -19,8 +19,8 @@ public class HazelcastLifecycleSupport extends AbstractHazelcastLifecycleSupport private final Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired - public HazelcastLifecycleSupport(HazelcastInstance hazelcastServerInstance, JdbcTemplate jdbcTemplate) { - super(hazelcastServerInstance, jdbcTemplate); + public HazelcastLifecycleSupport(HazelcastInstance hazelcastServerInstance, JdbcTemplate jdbcTemplate, PlannerAllTodayMaker plannerAllTodayMaker) { + super(hazelcastServerInstance, jdbcTemplate, plannerAllTodayMaker); } @Override diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/PlannerAllTodayMaker.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/PlannerAllTodayMaker.java new file mode 100644 index 000000000..31d807ac9 --- /dev/null +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/PlannerAllTodayMaker.java @@ -0,0 +1,115 @@ +package ru.spcex.clearing.imdg.services; + +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.core.IMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ru.clearing.classes.statics.data.scheduler.ClearingCalendar; +import ru.clearing.classes.statics.data.scheduler.Planner; +import ru.clearing.classes.statics.data.scheduler.PlannerAllToday; +import ru.clearing.classes.statics.data.scheduler.PlannerTemplate; +import ru.spcex.platform.enumeration.DayStatus; +import ru.spcex.platform.enumeration.Parent; +import ru.spcex.platform.enumeration.Status; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static ru.spcex.clearing.imdg.IMDGDistributedNames.*; + +@Service +public class PlannerAllTodayMaker { + private final HazelcastInstance hazelcastInstance; + private final IMap plannerMap; + private final IMap clearingCalendarMap; + private final IMap plannerTemplateMap; + private final IMap plannerAllTodayMap; + + @Autowired + public PlannerAllTodayMaker(HazelcastInstance hazelcastInstance) { + this.hazelcastInstance = hazelcastInstance; + plannerMap = hazelcastInstance.getMap(Map_Planner); + clearingCalendarMap = hazelcastInstance.getMap(Map_ClearingCalendar); + plannerTemplateMap = hazelcastInstance.getMap(Map_PlannerTemplate); + plannerAllTodayMap = hazelcastInstance.getMap(Map_PlannerAllToday); + } + + public void makeSchedulerAllTodayMap() { + LocalDate currentDate = LocalDate.now(); + List listOfPlannerAllToday = new ArrayList<>(); + + if (!plannerMap.isEmpty()) listOfPlannerAllToday.addAll(getPlannersAllTodayToDate(currentDate)); + + plannerMap.values().stream().filter((x) -> x.getClearingDate().isEqual(currentDate)).forEach((x) -> { + if (x.getTaskStatus().equalsIgnoreCase(Status.Active.getKey())) { + listOfPlannerAllToday.add(createPlannerAllTodayFromPlanner(x)); + } + + if (x.getTaskStatus().equalsIgnoreCase(Status.Cancel.getKey()) || x.getTaskStatus().equalsIgnoreCase(Status.Blocked.getKey())) { + listOfPlannerAllToday.removeIf((allToday) -> x.getTaskTime().equals(allToday.getTaskTime()) && + x.getTask().equalsIgnoreCase(allToday.getTask())); + } + }); + for (PlannerAllToday plannerAllToday : listOfPlannerAllToday) { + plannerAllToday.setId(hazelcastInstance.getIdGenerator(MAP_SEQUENCE_NAME).newId()); + plannerAllTodayMap.put(plannerAllToday.getId(), plannerAllToday); + } + } + + private List getPlannersAllTodayToDate(LocalDate currentDate) { + boolean weekend = Arrays.asList(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY).contains(currentDate.getDayOfWeek()); + List res = new ArrayList<>(); + if (clearingCalendarMap == null || clearingCalendarMap.isEmpty()) { + if (!weekend) { + for (PlannerTemplate plannerTemplate : plannerTemplateMap.values()) { + res.add(createPlannerAllTodayFromPlannerTemplate(plannerTemplate)); + } + } + } else { + Optional clearingCalendarOptional = clearingCalendarMap.values().stream() + .filter((calendar) -> calendar.getClearingDate().isEqual(currentDate)) + .findFirst(); + if (clearingCalendarOptional.isPresent()) { + ClearingCalendar calendar = clearingCalendarOptional.get(); + if (calendar.getDayStatus().equalsIgnoreCase(DayStatus.Workday.getKey())) { + if (calendar.getCompanyId() != null && calendar.getCompanyId() != 0) { + for (PlannerTemplate plannerTemplate : plannerTemplateMap.values()) { + res.add(createPlannerAllTodayFromPlannerTemplate(plannerTemplate)); + } + } + } + } + } + + return res; + } + + private PlannerAllToday createPlannerAllTodayFromPlanner(Planner planner) { + PlannerAllToday res = new PlannerAllToday(); + res.setTask(planner.getTask()); + res.setTaskTime(planner.getTaskTime()); + res.setClearingDate(planner.getClearingDate()); + res.setMarket(planner.getMarket()); + res.setTaskStatus(planner.getTaskStatus()); + res.setCompanyId(planner.getCompanyId()); + res.setSecurityId(planner.getSecurityId()); + res.setParent(Parent.Planner.getKey()); + res.setParentId(planner.getId()); + return res; + } + + private PlannerAllToday createPlannerAllTodayFromPlannerTemplate(PlannerTemplate plannerTemplate) { + PlannerAllToday res = new PlannerAllToday(); + res.setTask(plannerTemplate.getTask()); + res.setTaskTime(plannerTemplate.getTaskTime()); + res.setTaskStatus(plannerTemplate.getTaskStatus()); + res.setParent(Parent.Template.getKey()); + res.setParentId(plannerTemplate.getId()); + return res; + } + +} diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/util/Util.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/util/Util.java deleted file mode 100644 index 9ad1d2551..000000000 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/util/Util.java +++ /dev/null @@ -1,113 +0,0 @@ -package ru.spcex.clearing.imdg.util; - -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; -import ru.clearing.classes.statics.data.scheduler.ClearingCalendar; -import ru.clearing.classes.statics.data.scheduler.Planner; -import ru.clearing.classes.statics.data.scheduler.PlannerAllToday; -import ru.clearing.classes.statics.data.scheduler.PlannerTemplate; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static ru.spcex.clearing.imdg.IMDGDistributedNames.*; - -public class Util { - - public static void makeSchedulerAllTodayMap(HazelcastInstance hazelcastInstance) { - IMap plannerMap = hazelcastInstance.getMap(Map_Planner); - IMap clearingCalendarMap = hazelcastInstance.getMap(Map_ClearingCalendar); - IMap plannerTemplateMap = hazelcastInstance.getMap(Map_PlannerTemplate); - IMap plannerAllTodayMap = hazelcastInstance.getMap(Map_PlannerAllToday); - LocalDate currentDate = LocalDate.now(); - List listOfPlannerAllToday = new ArrayList<>(); - - - if (!plannerMap.isEmpty()) { - switch (currentDate.getDayOfWeek()) { - case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> listOfPlannerAllToday.addAll(getPlannersOnMonday2Friday(currentDate, clearingCalendarMap, plannerTemplateMap)); - case SUNDAY, SATURDAY -> listOfPlannerAllToday.addAll(getPlannersOnSunday2Saturday(currentDate, clearingCalendarMap, plannerTemplateMap)); - } - } - - plannerMap.values().stream().filter((x) -> x.getClearingDate().isEqual(currentDate)).forEach((x) -> { - if (x.getTaskStatus().equalsIgnoreCase("ACTV")) { - listOfPlannerAllToday.add(createPlannerAllTodayFromPlanner(x)); - } - - if (x.getTaskStatus().equalsIgnoreCase("CNCL") || x.getTaskStatus().equalsIgnoreCase("BLKD")) { - listOfPlannerAllToday.removeIf((allToday) -> !x.getTaskTime().equals(allToday.getTaskTime()) || - !x.getTask().equalsIgnoreCase(allToday.getTask())); - } - }); - for (PlannerAllToday plannerAllToday : listOfPlannerAllToday) { - plannerAllToday.setId(hazelcastInstance.getIdGenerator(MAP_SEQUENCE_NAME).newId()); - plannerAllTodayMap.put(plannerAllToday.getId(), plannerAllToday); - } - } - - private static List getPlannersOnMonday2Friday(LocalDate currentDate, IMap clearingCalendarMap, IMap plannerTemplateMap) { - List res = new ArrayList<>(); - if (clearingCalendarMap == null || clearingCalendarMap.isEmpty()) { - for (PlannerTemplate plannerTemplate : plannerTemplateMap.values()) { - res.add(createPlannerAllTodayFromPlannerTemplate(plannerTemplate)); - } - } else { - Optional clearingCalendarOptional = clearingCalendarMap.values().stream().filter((calendar) -> calendar.getClearingDate().isEqual(currentDate)).findFirst(); - if (clearingCalendarOptional.isPresent()) { - ClearingCalendar calendar = clearingCalendarOptional.get(); - if (calendar.getDayStatus().equalsIgnoreCase("BDAY")) { - if (calendar.getCompanyId() != null && calendar.getCompanyId() != 0) { - for (PlannerTemplate plannerTemplate : - plannerTemplateMap.values()) { - res.add(createPlannerAllTodayFromPlannerTemplate(plannerTemplate)); - } - } - } - } - } - - return res; - } - - private static List getPlannersOnSunday2Saturday(LocalDate currentDate, IMap clearingCalendarMap, IMap plannerTemplateMap) { - List res = new ArrayList<>(); - Optional clearingCalendarOptional = clearingCalendarMap.values().stream().filter((calendar) -> calendar.getClearingDate().isEqual(currentDate)).findFirst(); - if (clearingCalendarOptional.isPresent()) { - ClearingCalendar clearingCalendar = clearingCalendarOptional.get(); - if (clearingCalendar.getDayStatus().equalsIgnoreCase("BDAY")) { - for (PlannerTemplate plannerTemplate : plannerTemplateMap.values()) { - res.add(createPlannerAllTodayFromPlannerTemplate(plannerTemplate)); - } - } - } - return res; - } - - private static PlannerAllToday createPlannerAllTodayFromPlanner(Planner planner) { - PlannerAllToday res = new PlannerAllToday(); - res.setTask(planner.getTask()); - res.setTaskTime(planner.getTaskTime()); - res.setClearingDate(planner.getClearingDate()); - res.setMarket(planner.getMarket()); - res.setTaskStatus(planner.getTaskStatus()); - res.setCompanyId(planner.getCompanyId()); - res.setSecurityId(planner.getSecurityId()); - res.setParent("PLNR"); - res.setParentId(planner.getId()); - return res; - } - - private static PlannerAllToday createPlannerAllTodayFromPlannerTemplate(PlannerTemplate plannerTemplate) { - PlannerAllToday res = new PlannerAllToday(); - res.setTask(plannerTemplate.getTask()); - res.setTaskTime(plannerTemplate.getTaskTime()); - res.setTaskStatus(plannerTemplate.getTaskStatus()); - res.setParent("TMPL"); - res.setParentId(plannerTemplate.getId()); - return res; - } - -} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java index ee5b53975..89fd9c81c 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java @@ -18,6 +18,7 @@ import ru.spcex.platform.enumeration.Status; import ru.spcex.platform.enumeration.Task; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgHazelcast; import java.time.*; import java.util.ArrayList; @@ -72,6 +73,9 @@ public class TaskManager implements EntryAddedListener, public void afterPropertiesSet() { this.launcherMap = imdgProvider.getImdg(Map_Launcher, Launcher.class); this.plannerAllTodayMap = imdgProvider.getImdg(Map_PlannerAllToday, PlannerAllToday.class); + if (plannerAllTodayMap instanceof ImdgHazelcast plannerAllTodayImdgHazelcast) { + plannerAllTodayImdgHazelcast.getMap().addEntryListener(this, true); + } scheduledJobs = new ConcurrentHashMap<>(); updateScheduler(); } diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/DayStatus.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/DayStatus.java new file mode 100644 index 000000000..2028f093c --- /dev/null +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/DayStatus.java @@ -0,0 +1,18 @@ +package ru.spcex.platform.enumeration; + +import ru.spcex.platform.utils.enumeration.IEnumKey; + +public enum DayStatus implements IEnumKey { + Workday("BDAY"), DayOff("DOFF"); + + private final String key; + + DayStatus(String key) { + this.key = key; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/Parent.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/Parent.java new file mode 100644 index 000000000..523bba0bf --- /dev/null +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/Parent.java @@ -0,0 +1,18 @@ +package ru.spcex.platform.enumeration; + +import ru.spcex.platform.utils.enumeration.IEnumKey; + +public enum Parent implements IEnumKey { + Template("TMPL"), Planner("PLNR"), Calendar("CLND"); + + private final String key; + + Parent(String key) { + this.key = key; + } + + @Override + public String getKey() { + return key; + } +} From 5b82cf4d22ec95acb672671d378b443ebbeda37b Mon Sep 17 00:00:00 2001 From: akulikov Date: Fri, 13 Jan 2023 14:08:21 +0300 Subject: [PATCH 02/14] validators --- .../clearing/scheduler/IRequestValidator.java | 179 ++++++++++++++++++ .../service/ClearingCalendarService.java | 22 +++ .../scheduler/service/PlannerService.java | 11 ++ .../service/PlannerTemplateService.java | 11 ++ 4 files changed, 223 insertions(+) create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java new file mode 100644 index 000000000..47e0e83db --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java @@ -0,0 +1,179 @@ +package ru.spcex.clearing.scheduler; + +import org.slf4j.Logger; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.*; +import ru.spcex.platform.enumeration.DayStatus; +import ru.spcex.platform.enumeration.Market; +import ru.spcex.platform.enumeration.Status; +import ru.spcex.platform.enumeration.Task; +import ru.spcex.platform.utils.enumeration.IEnumKey; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +public interface IRequestValidator { + List validate(T req); + + /** + * Общий запрос на удаление + */ + IRequestValidator COMMON_DELETE_REQUEST = req -> { + var errors = new LinkedList(); + validateLong(req.id, "id", true, errors); + return errors; + }; + + /** + * Запрос на добавление ClearingCalendar + */ + IRequestValidator CLEARING_CALENDAR_NEW_REQUEST = req -> { + var errors = new LinkedList(); + validateDate(req.clearingDate, "clearingDate", true, true, errors); + validateLong(req.companyId, "companyId", false, errors); + validateEnum(req.dayStatus, "dayStatus", true, errors, DayStatus.values()); + return errors; + }; + + /** + * Запрос на обновление ClearingCalendar + */ + IRequestValidator CLEARING_CALENDAR_UPDATE_REQUEST = req -> { + var errors = new LinkedList(); + validateLong(req.id, "id", true, errors); + validateLong(req.companyId, "companyId", false, errors); + validateDate(req.clearingDate, "clearingDate", false, true, errors); + validateEnum(req.dayStatus, "dayStatus", false, errors, DayStatus.values()); + return errors; + }; + + /** + * Запрос на добавление Planner + */ + IRequestValidator PLANNER_NEW_REQUEST = req -> { + var errors = new LinkedList(); + validateEnum(req.task, "task", true, errors, Task.values()); + validateDate(req.clearingDate, "clearingDate", true, true, errors); + validateTime(req.taskTime, "taskTime", true, true, errors); + validateEnum(req.market, "market", false, errors, Market.values()); + validateEnum(req.taskStatus, "taskStatus", true, errors, Status.values()); + validateLong(req.companyId, "companyId", false, errors); + validateLong(req.securityId, "securityId", false, errors); + return errors; + }; + + /** + * Запрос на обновление Planner + */ + IRequestValidator PLANNER_UPDATE_REQUEST = req -> { + var errors = new LinkedList(); + validateLong(req.id, "id", true, errors); + validateEnum(req.task, "task", false, errors, Task.values()); + validateDate(req.clearingDate, "clearingDate", false, true, errors); + validateTime(req.taskTime, "taskTime", false, true, errors); + validateEnum(req.market, "market", false, errors, Market.values()); + validateEnum(req.taskStatus, "taskStatus", false, errors, Status.values()); + validateLong(req.companyId, "companyId", false, errors); + validateLong(req.securityId, "securityId", false, errors); + return errors; + }; + + /** + * Запрос на добавление PlannerTemplate + */ + IRequestValidator PLANNER_TEMPLATE_NEW_REQUEST = req -> { + var errors = new LinkedList(); + validateEnum(req.task, "task", true, errors, Task.values()); + validateTime(req.taskTime, "taskTime", true, true, errors); + validateEnum(req.taskStatus, "taskStatus", true, errors, Status.values()); + validateLong(req.companyId, "companyId", false, errors); + validateLong(req.securityId, "securityId", false, errors); + return errors; + }; + + /** + * Запрос на обновление PlannerTemplate + */ + IRequestValidator PLANNER_TEMPLATE_UPDATE_REQUEST = req -> { + var errors = new LinkedList(); + validateLong(req.id, "id", true, errors); + validateEnum(req.task, "task", false, errors, Task.values()); + validateTime(req.taskTime, "taskTime", false, true, errors); + validateEnum(req.taskStatus, "taskStatus", false, errors, Status.values()); + validateLong(req.companyId, "companyId", false, errors); + validateLong(req.securityId, "securityId", false, errors); + return errors; + }; + + + + + static & IEnumKey> void validateEnum(String enumStr, + String fieldName, + boolean required, + List errors, + T... enumSet) { + if (enumStr != null) { + boolean correctTask = IEnumKey.contains(enumStr, enumSet); + if (!correctTask) + errors.add(new ValidationError(fieldName, ErrorType.UNKNOWN_VALUE)); + } else if (required) errors.add(new ValidationError(fieldName, ErrorType.MISSING_REQUIRED)); + } + + static void validateLong(Long value, String fieldName, boolean required, List errors) { + if (value != null) { + if (value < 0 || value == Long.MAX_VALUE) + errors.add(new ValidationError(fieldName, ErrorType.INVALID_VALUE)); + } else if (required) errors.add(new ValidationError(fieldName, ErrorType.MISSING_REQUIRED)); + } + + static void validateDate(LocalDate value, + String fieldName, + boolean required, + boolean checkDate, + List errors) { + if (value != null) { + if (checkDate && (value.isBefore(LocalDate.now()))) + errors.add(new ValidationError(fieldName, ErrorType.INVALID_VALUE)); + } else if (required) errors.add(new ValidationError(fieldName, ErrorType.MISSING_REQUIRED)); + } + + static void validateTime(LocalTime value, + String fieldName, + boolean required, + boolean checkDate, + List errors) { + if (value != null) { + if (checkDate && (value.isBefore(LocalTime.now()))) + errors.add(new ValidationError(fieldName, ErrorType.INVALID_VALUE)); + } else if (required) errors.add(new ValidationError(fieldName, ErrorType.MISSING_REQUIRED)); + } + + /** + * Временный метод + */ + static boolean checkErrorList(List errors, Logger log) { + if (!errors.isEmpty()) { + log.error("Validation error: [{}]", + errors.stream().map(IRequestValidator.ValidationError::toString).collect(Collectors.joining(", ")) + ); + return true; + } + return false; + } + + enum ErrorType { + MISSING_REQUIRED, UNKNOWN_VALUE, INVALID_VALUE + } + + record ValidationError(String fieldName, ErrorType errorType) { + @Override + public String toString() { + return "%s: %s".formatted(fieldName, errorType); + } + } + +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java index 3a86684b7..0c347b70c 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java @@ -15,15 +15,21 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; +import ru.spcex.clearing.scheduler.IRequestValidator; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; import java.time.Instant; +import java.util.List; +import java.util.stream.Collectors; @Service public class ClearingCalendarService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); private final Imdg clearingCalendarMap; + private final IRequestValidator newRequestValidator = IRequestValidator.CLEARING_CALENDAR_NEW_REQUEST; + private final IRequestValidator updateRequestValidator = IRequestValidator.CLEARING_CALENDAR_UPDATE_REQUEST; + private final IRequestValidator deleteRequestValidator = IRequestValidator.COMMON_DELETE_REQUEST; @Autowired public ClearingCalendarService(Consumer kafkaQueue, Producer kafkaProducer, @@ -49,6 +55,8 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi private void newClearingCalendar(BaseRequest userRequest) { ClearingCalendarNewRequest req = userRequest.getRequestPayload(); log.debug("ClearingCalendarNewRequest received"); + List errors = newRequestValidator.validate(req); + if (IRequestValidator.checkErrorList(errors, log)) return; ClearingCalendar clearingCalendar = new ClearingCalendar(); Instant created = Instant.now(); clearingCalendar.setCreated(created); @@ -62,6 +70,8 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi private void updateClearingCalendar(BaseRequest userRequest) { ClearingCalendarUpdateRequest req = userRequest.getRequestPayload(); log.debug("ClearingCalendarUpdateRequest received"); + List errors = updateRequestValidator.validate(req); + if (IRequestValidator.checkErrorList(errors, log)) return; Instant updated = Instant.now(); ClearingCalendar clearingCalendar = clearingCalendarMap.getSingleObjectByID(req.getId()); clearingCalendar.setClearingDate(req.getClearingDate()); @@ -74,8 +84,20 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi private void deleteClearingCalendar(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); + List errors = deleteRequestValidator.validate(req); + if (IRequestValidator.checkErrorList(errors, log)) return; log.debug("CommonDeleteRequest received id = {}", req.getId()); ClearingCalendar clearingCalendar = clearingCalendarMap.getSingleObjectByID(req.getId()); clearingCalendarMap.delete(clearingCalendar); } + + static boolean checkErrors(List errors, Logger log) { + if (!errors.isEmpty()) { + log.error("Validation error: [{}]", + errors.stream().map(IRequestValidator.ValidationError::toString).collect(Collectors.joining(", ")) + ); + return true; + } + return false; + } } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java index 199c12ab4..53dc8a791 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java @@ -15,15 +15,20 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; +import ru.spcex.clearing.scheduler.IRequestValidator; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; import java.time.Instant; +import java.util.List; @Service public class PlannerService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); private final Imdg plannerMap; + private final IRequestValidator plannerNewRequest = IRequestValidator.PLANNER_NEW_REQUEST; + private final IRequestValidator plannerUpdateRequest = IRequestValidator.PLANNER_UPDATE_REQUEST; + private final IRequestValidator deleteRequestValidator = IRequestValidator.COMMON_DELETE_REQUEST; @Autowired public PlannerService(Consumer kafkaQueue, Producer kafkaProducer, @@ -49,6 +54,8 @@ public class PlannerService extends QueueConsumer implements InitializingBean { private void newScheduler(BaseRequest userRequest) { PlannerNewRequest req = userRequest.getRequestPayload(); log.debug("PlannerNewRequest received"); + List errors = plannerNewRequest.validate(req); + if (IRequestValidator.checkErrorList(errors, log)) return; Planner planner = new Planner(); planner.setCreated(Instant.now()); planner.setTask(req.getTask()); @@ -65,6 +72,8 @@ public class PlannerService extends QueueConsumer implements InitializingBean { private void updateScheduler(BaseRequest userRequest) { PlannerUpdateRequest req = userRequest.getRequestPayload(); log.debug("PlannerUpdateRequest received id = {}", req.getId()); + List errors = plannerUpdateRequest.validate(req); + if (IRequestValidator.checkErrorList(errors, log)) return; Planner planner = plannerMap.getSingleObjectByID(req.getId()); planner.setUpdated(Instant.now()); planner.setTask(req.getTask()); @@ -80,6 +89,8 @@ public class PlannerService extends QueueConsumer implements InitializingBean { private void deleteScheduler(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); log.debug("CommonDeleteRequest received id = {}", req.getId()); + List errors = deleteRequestValidator.validate(req); + if (IRequestValidator.checkErrorList(errors, log)) return; Planner planner = plannerMap.getSingleObjectByID(req.getId()); plannerMap.delete(planner); } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java index 77a1466a0..0d9d12b33 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java @@ -15,15 +15,20 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; +import ru.spcex.clearing.scheduler.IRequestValidator; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; import java.time.Instant; +import java.util.List; @Service public class PlannerTemplateService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); private final Imdg plannerTemplateMap; + private final IRequestValidator plannerTemplateNewRequest = IRequestValidator.PLANNER_TEMPLATE_NEW_REQUEST; + private final IRequestValidator plannerTemplateUpdateRequest = IRequestValidator.PLANNER_TEMPLATE_UPDATE_REQUEST; + private final IRequestValidator deleteRequestValidator = IRequestValidator.COMMON_DELETE_REQUEST; @Autowired public PlannerTemplateService(Consumer kafkaQueue, Producer kafkaProducer, @@ -49,6 +54,8 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin private void newTimetable(BaseRequest userRequest) { PlannerTemplateNewRequest req = userRequest.getRequestPayload(); log.debug("PlannerTemplateNewRequest received"); + List errors = plannerTemplateNewRequest.validate(req); + if (IRequestValidator.checkErrorList(errors, log)) return; PlannerTemplate plannerTemplate = new PlannerTemplate(); Instant created = Instant.now(); plannerTemplate.setCreated(created); @@ -65,6 +72,8 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin PlannerTemplateUpdateRequest req = userRequest.getRequestPayload(); log.debug("PlannerTemplateUpdateRequest received"); PlannerTemplate plannerTemplate = plannerTemplateMap.getSingleObjectByID(req.getId()); + List errors = plannerTemplateUpdateRequest.validate(req); + if (IRequestValidator.checkErrorList(errors, log)) return; Instant updated = Instant.now(); plannerTemplate.setUpdated(updated); plannerTemplate.setTask(req.getTask()); @@ -79,6 +88,8 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin private void deleteTimetable(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); log.debug("CommonDeleteRequest received id = {}", req.getId()); + List errors = deleteRequestValidator.validate(req); + if (IRequestValidator.checkErrorList(errors, log)) return; PlannerTemplate plannerTemplate = plannerTemplateMap.getSingleObjectByID(req.getId()); plannerTemplateMap.delete(plannerTemplate); } From f91e15f2a447f56cb15a0eaabc9f5e5c6c56d307 Mon Sep 17 00:00:00 2001 From: akulikov Date: Fri, 13 Jan 2023 15:13:23 +0300 Subject: [PATCH 03/14] validate from dictionaries --- clearing-parent/scheduler-service/pom.xml | 4 + .../clearing/scheduler/IRequestValidator.java | 110 ++++++++++++++---- 2 files changed, 93 insertions(+), 21 deletions(-) diff --git a/clearing-parent/scheduler-service/pom.xml b/clearing-parent/scheduler-service/pom.xml index 04774fd14..cb13c4eef 100644 --- a/clearing-parent/scheduler-service/pom.xml +++ b/clearing-parent/scheduler-service/pom.xml @@ -28,6 +28,10 @@ ru.spcex.platform platform-imdg-api-hazelcast-impl + + ru.spcex.clearing + dictionary + ru.spcex.clearing classes diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java index 47e0e83db..78285922a 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java @@ -1,27 +1,32 @@ package ru.spcex.clearing.scheduler; import org.slf4j.Logger; +import ru.clearing.platform.dictionary.AbstractDictionary; +import ru.clearing.platform.dictionary.DayStatusDictionary; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.*; -import ru.spcex.platform.enumeration.DayStatus; import ru.spcex.platform.enumeration.Market; -import ru.spcex.platform.enumeration.Status; -import ru.spcex.platform.enumeration.Task; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.utils.enumeration.IEnumKey; import java.time.LocalDate; import java.time.LocalTime; +import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; public interface IRequestValidator { - List validate(T req); + List validate(T req, ImdgProvider imdgProvider); /** * Общий запрос на удаление */ - IRequestValidator COMMON_DELETE_REQUEST = req -> { + IRequestValidator COMMON_DELETE_REQUEST = (req, imdgProvider) -> { var errors = new LinkedList(); validateLong(req.id, "id", true, errors); return errors; @@ -30,36 +35,56 @@ public interface IRequestValidator { /** * Запрос на добавление ClearingCalendar */ - IRequestValidator CLEARING_CALENDAR_NEW_REQUEST = req -> { + IRequestValidator CLEARING_CALENDAR_NEW_REQUEST = (req, imdgProvider) -> { var errors = new LinkedList(); validateDate(req.clearingDate, "clearingDate", true, true, errors); validateLong(req.companyId, "companyId", false, errors); - validateEnum(req.dayStatus, "dayStatus", true, errors, DayStatus.values()); +// validateEnum(req.dayStatus, "dayStatus", true, errors, DayStatus.values()); + validateDictionary(req.dayStatus, + "dayStatus", + true, + imdgProvider.getImdg(IMDGDistributedNames.Map_DayStatusDictionary, DayStatusDictionary.class), + errors); return errors; }; /** * Запрос на обновление ClearingCalendar */ - IRequestValidator CLEARING_CALENDAR_UPDATE_REQUEST = req -> { + IRequestValidator CLEARING_CALENDAR_UPDATE_REQUEST = (req, imdgProvider) -> { var errors = new LinkedList(); validateLong(req.id, "id", true, errors); validateLong(req.companyId, "companyId", false, errors); validateDate(req.clearingDate, "clearingDate", false, true, errors); - validateEnum(req.dayStatus, "dayStatus", false, errors, DayStatus.values()); +// validateEnum(req.dayStatus, "dayStatus", false, errors, DayStatus.values()); + validateDictionary(req.dayStatus, + "dayStatus", + false, + imdgProvider.getImdg(IMDGDistributedNames.Map_DayStatusDictionary, DayStatusDictionary.class), + errors); return errors; }; /** * Запрос на добавление Planner */ - IRequestValidator PLANNER_NEW_REQUEST = req -> { + IRequestValidator PLANNER_NEW_REQUEST = (req, imdgProvider) -> { var errors = new LinkedList(); - validateEnum(req.task, "task", true, errors, Task.values()); +// validateEnum(req.task, "task", true, errors, Task.values()); + validateDictionary(req.task, + "task", + true, + imdgProvider.getImdg(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class), + errors); validateDate(req.clearingDate, "clearingDate", true, true, errors); validateTime(req.taskTime, "taskTime", true, true, errors); validateEnum(req.market, "market", false, errors, Market.values()); - validateEnum(req.taskStatus, "taskStatus", true, errors, Status.values()); +// validateEnum(req.taskStatus, "taskStatus", true, errors, Status.values()); + validateDictionary(req.taskStatus, + "taskStatus", + true, + imdgProvider.getImdg(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class), + errors); validateLong(req.companyId, "companyId", false, errors); validateLong(req.securityId, "securityId", false, errors); return errors; @@ -68,14 +93,24 @@ public interface IRequestValidator { /** * Запрос на обновление Planner */ - IRequestValidator PLANNER_UPDATE_REQUEST = req -> { + IRequestValidator PLANNER_UPDATE_REQUEST = (req, imdgProvider) -> { var errors = new LinkedList(); validateLong(req.id, "id", true, errors); - validateEnum(req.task, "task", false, errors, Task.values()); +// validateEnum(req.task, "task", false, errors, Task.values()); + validateDictionary(req.task, + "task", + false, + imdgProvider.getImdg(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class), + errors); validateDate(req.clearingDate, "clearingDate", false, true, errors); validateTime(req.taskTime, "taskTime", false, true, errors); validateEnum(req.market, "market", false, errors, Market.values()); - validateEnum(req.taskStatus, "taskStatus", false, errors, Status.values()); +// validateEnum(req.taskStatus, "taskStatus", false, errors, Status.values()); + validateDictionary(req.taskStatus, + "taskStatus", + false, + imdgProvider.getImdg(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class), + errors); validateLong(req.companyId, "companyId", false, errors); validateLong(req.securityId, "securityId", false, errors); return errors; @@ -84,11 +119,21 @@ public interface IRequestValidator { /** * Запрос на добавление PlannerTemplate */ - IRequestValidator PLANNER_TEMPLATE_NEW_REQUEST = req -> { + IRequestValidator PLANNER_TEMPLATE_NEW_REQUEST = (req, imdgProvider) -> { var errors = new LinkedList(); - validateEnum(req.task, "task", true, errors, Task.values()); +// validateEnum(req.task, "task", true, errors, Task.values()); + validateDictionary(req.task, + "task", + true, + imdgProvider.getImdg(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class), + errors); validateTime(req.taskTime, "taskTime", true, true, errors); - validateEnum(req.taskStatus, "taskStatus", true, errors, Status.values()); +// validateEnum(req.taskStatus, "taskStatus", true, errors, Status.values()); + validateDictionary(req.taskStatus, + "taskStatus", + true, + imdgProvider.getImdg(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class), + errors); validateLong(req.companyId, "companyId", false, errors); validateLong(req.securityId, "securityId", false, errors); return errors; @@ -97,12 +142,22 @@ public interface IRequestValidator { /** * Запрос на обновление PlannerTemplate */ - IRequestValidator PLANNER_TEMPLATE_UPDATE_REQUEST = req -> { + IRequestValidator PLANNER_TEMPLATE_UPDATE_REQUEST = (req, imdgProvider) -> { var errors = new LinkedList(); validateLong(req.id, "id", true, errors); - validateEnum(req.task, "task", false, errors, Task.values()); +// validateEnum(req.task, "task", false, errors, Task.values()); + validateDictionary(req.task, + "task", + false, + imdgProvider.getImdg(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class), + errors); validateTime(req.taskTime, "taskTime", false, true, errors); - validateEnum(req.taskStatus, "taskStatus", false, errors, Status.values()); +// validateEnum(req.taskStatus, "taskStatus", false, errors, Status.values()); + validateDictionary(req.taskStatus, + "taskStatus", + false, + imdgProvider.getImdg(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class), + errors); validateLong(req.companyId, "companyId", false, errors); validateLong(req.securityId, "securityId", false, errors); return errors; @@ -110,6 +165,19 @@ public interface IRequestValidator { + static void validateDictionary(String src, + String fieldName, + boolean required, + Imdg dictionary, + List errors) { + if (src != null) { + boolean correctTask = false; + Collection values = dictionary.getAllValues(); + for (T value : values) correctTask |= src.equalsIgnoreCase(value.getCode()); + if (!correctTask) + errors.add(new ValidationError(fieldName, ErrorType.UNKNOWN_VALUE)); + } else if (required) errors.add(new ValidationError(fieldName, ErrorType.MISSING_REQUIRED)); + } static & IEnumKey> void validateEnum(String enumStr, String fieldName, From 0b1cc5639e84423785d7c6c07e7d762461daf8e1 Mon Sep 17 00:00:00 2001 From: akulikov Date: Fri, 13 Jan 2023 15:25:07 +0300 Subject: [PATCH 04/14] validate from dictionaries (fix) --- .../scheduler/service/ClearingCalendarService.java | 8 +++++--- .../spcex/clearing/scheduler/service/PlannerService.java | 8 +++++--- .../scheduler/service/PlannerTemplateService.java | 8 +++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java index 0c347b70c..efe225cd3 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java @@ -26,6 +26,7 @@ import java.util.stream.Collectors; @Service public class ClearingCalendarService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); + private final ImdgProvider imdgProvider; private final Imdg clearingCalendarMap; private final IRequestValidator newRequestValidator = IRequestValidator.CLEARING_CALENDAR_NEW_REQUEST; private final IRequestValidator updateRequestValidator = IRequestValidator.CLEARING_CALENDAR_UPDATE_REQUEST; @@ -36,6 +37,7 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi ImdgProvider imdgProvider) { super(kafkaQueue, kafkaProducer); this.clearingCalendarMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingCalendar, ClearingCalendar.class); + this.imdgProvider = imdgProvider; } @Override @@ -55,7 +57,7 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi private void newClearingCalendar(BaseRequest userRequest) { ClearingCalendarNewRequest req = userRequest.getRequestPayload(); log.debug("ClearingCalendarNewRequest received"); - List errors = newRequestValidator.validate(req); + List errors = newRequestValidator.validate(req, imdgProvider); if (IRequestValidator.checkErrorList(errors, log)) return; ClearingCalendar clearingCalendar = new ClearingCalendar(); Instant created = Instant.now(); @@ -70,7 +72,7 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi private void updateClearingCalendar(BaseRequest userRequest) { ClearingCalendarUpdateRequest req = userRequest.getRequestPayload(); log.debug("ClearingCalendarUpdateRequest received"); - List errors = updateRequestValidator.validate(req); + List errors = updateRequestValidator.validate(req, imdgProvider); if (IRequestValidator.checkErrorList(errors, log)) return; Instant updated = Instant.now(); ClearingCalendar clearingCalendar = clearingCalendarMap.getSingleObjectByID(req.getId()); @@ -84,7 +86,7 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi private void deleteClearingCalendar(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); - List errors = deleteRequestValidator.validate(req); + List errors = deleteRequestValidator.validate(req, imdgProvider); if (IRequestValidator.checkErrorList(errors, log)) return; log.debug("CommonDeleteRequest received id = {}", req.getId()); ClearingCalendar clearingCalendar = clearingCalendarMap.getSingleObjectByID(req.getId()); diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java index 53dc8a791..343e57b85 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java @@ -25,6 +25,7 @@ import java.util.List; @Service public class PlannerService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); + private final ImdgProvider imdgProvider; private final Imdg plannerMap; private final IRequestValidator plannerNewRequest = IRequestValidator.PLANNER_NEW_REQUEST; private final IRequestValidator plannerUpdateRequest = IRequestValidator.PLANNER_UPDATE_REQUEST; @@ -35,6 +36,7 @@ public class PlannerService extends QueueConsumer implements InitializingBean { ImdgProvider imdgProvider) { super(kafkaQueue, kafkaProducer); this.plannerMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Planner, Planner.class); + this.imdgProvider = imdgProvider; } @Override @@ -54,7 +56,7 @@ public class PlannerService extends QueueConsumer implements InitializingBean { private void newScheduler(BaseRequest userRequest) { PlannerNewRequest req = userRequest.getRequestPayload(); log.debug("PlannerNewRequest received"); - List errors = plannerNewRequest.validate(req); + List errors = plannerNewRequest.validate(req, imdgProvider); if (IRequestValidator.checkErrorList(errors, log)) return; Planner planner = new Planner(); planner.setCreated(Instant.now()); @@ -72,7 +74,7 @@ public class PlannerService extends QueueConsumer implements InitializingBean { private void updateScheduler(BaseRequest userRequest) { PlannerUpdateRequest req = userRequest.getRequestPayload(); log.debug("PlannerUpdateRequest received id = {}", req.getId()); - List errors = plannerUpdateRequest.validate(req); + List errors = plannerUpdateRequest.validate(req, imdgProvider); if (IRequestValidator.checkErrorList(errors, log)) return; Planner planner = plannerMap.getSingleObjectByID(req.getId()); planner.setUpdated(Instant.now()); @@ -89,7 +91,7 @@ public class PlannerService extends QueueConsumer implements InitializingBean { private void deleteScheduler(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); log.debug("CommonDeleteRequest received id = {}", req.getId()); - List errors = deleteRequestValidator.validate(req); + List errors = deleteRequestValidator.validate(req, imdgProvider); if (IRequestValidator.checkErrorList(errors, log)) return; Planner planner = plannerMap.getSingleObjectByID(req.getId()); plannerMap.delete(planner); diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java index 0d9d12b33..d1eec0d90 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java @@ -26,6 +26,7 @@ import java.util.List; public class PlannerTemplateService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); private final Imdg plannerTemplateMap; + private final ImdgProvider imdgProvider; private final IRequestValidator plannerTemplateNewRequest = IRequestValidator.PLANNER_TEMPLATE_NEW_REQUEST; private final IRequestValidator plannerTemplateUpdateRequest = IRequestValidator.PLANNER_TEMPLATE_UPDATE_REQUEST; private final IRequestValidator deleteRequestValidator = IRequestValidator.COMMON_DELETE_REQUEST; @@ -35,6 +36,7 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin ImdgProvider imdgProvider) { super(kafkaQueue, kafkaProducer); this.plannerTemplateMap = imdgProvider.getImdg(IMDGDistributedNames.Map_PlannerTemplate, PlannerTemplate.class); + this.imdgProvider = imdgProvider; } @Override @@ -54,7 +56,7 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin private void newTimetable(BaseRequest userRequest) { PlannerTemplateNewRequest req = userRequest.getRequestPayload(); log.debug("PlannerTemplateNewRequest received"); - List errors = plannerTemplateNewRequest.validate(req); + List errors = plannerTemplateNewRequest.validate(req, imdgProvider); if (IRequestValidator.checkErrorList(errors, log)) return; PlannerTemplate plannerTemplate = new PlannerTemplate(); Instant created = Instant.now(); @@ -72,7 +74,7 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin PlannerTemplateUpdateRequest req = userRequest.getRequestPayload(); log.debug("PlannerTemplateUpdateRequest received"); PlannerTemplate plannerTemplate = plannerTemplateMap.getSingleObjectByID(req.getId()); - List errors = plannerTemplateUpdateRequest.validate(req); + List errors = plannerTemplateUpdateRequest.validate(req, imdgProvider); if (IRequestValidator.checkErrorList(errors, log)) return; Instant updated = Instant.now(); plannerTemplate.setUpdated(updated); @@ -88,7 +90,7 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin private void deleteTimetable(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); log.debug("CommonDeleteRequest received id = {}", req.getId()); - List errors = deleteRequestValidator.validate(req); + List errors = deleteRequestValidator.validate(req, imdgProvider); if (IRequestValidator.checkErrorList(errors, log)) return; PlannerTemplate plannerTemplate = plannerTemplateMap.getSingleObjectByID(req.getId()); plannerTemplateMap.delete(plannerTemplate); From 58d0e9655daa912b867d07ddec0454c950d4f9c8 Mon Sep 17 00:00:00 2001 From: akulikov Date: Mon, 16 Jan 2023 16:38:49 +0300 Subject: [PATCH 05/14] EnumPresentRule validator (commit for test) --- .../scheduler/config/ValidationConfig.java | 63 +++++++++++++++++++ .../clearing/scheduler/error/Errors.java | 21 +++++++ .../validation/rules/EnumPresentRule.java | 48 ++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/Errors.java create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/EnumPresentRule.java diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java new file mode 100644 index 000000000..3948ed69a --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java @@ -0,0 +1,63 @@ +package ru.spcex.clearing.scheduler.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.account.AccountBalance; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.company.CompanySymbols; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.validation.rules.EnumPresentRule; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; + +@Configuration +public class ValidationConfig { + private final Map> imdgs; + + public ValidationConfig(ImdgProvider imdgProvider) { + this.imdgs = new HashMap<>(); + BiConsumer> addImdg = (s, aClass) -> imdgs.put(s, imdgProvider.getImdg(s, aClass)); + addImdg.accept(IMDGDistributedNames.Map_Account, Account.class); + addImdg.accept(IMDGDistributedNames.Map_Company, Company.class); + addImdg.accept(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class); + addImdg.accept(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class); + } + + /** + * чтобы во всех валидаторах был один экземпляр Imdg + */ + private Imdg getImdg(String key) { + return imdgs.get(key); + } + + @Bean("plannerNewRequestValidator") + public Function plannerNewRequestValidator() { + return plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + Consumer addImdg = (s) -> context.addImdg(s, getImdg(s)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary); + return new ValidatorImpl<>(context, + EnumPresentRule.instance("task", + PlannerNewRequest::getTask, + IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class) + ); + }; + } + +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/Errors.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/Errors.java new file mode 100644 index 000000000..7fdec8a3e --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/Errors.java @@ -0,0 +1,21 @@ +package ru.spcex.clearing.scheduler.error; + +import ru.spcex.platform.utils.enumeration.IEnumId; + +public enum Errors implements IEnumId { + WrongFieldValue(10003L) + + ; + + private final Long id; + + Errors(Long id) { + this.id = id; + } + + + @Override + public Long getId() { + return null; + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/EnumPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/EnumPresentRule.java new file mode 100644 index 000000000..0acec99af --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/EnumPresentRule.java @@ -0,0 +1,48 @@ +package ru.spcex.clearing.scheduler.validation.rules; + +import ru.spcex.clearing.scheduler.error.Errors; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class EnumPresentRule implements IValidationRule> { + protected final Function getEnumCode; + protected final String dictionaryName; + protected final String fieldName; + protected final Class enumClass; + + public EnumPresentRule(String fieldName, Function getEnumCode, String dictionaryName, Class enumClass) { + this.fieldName = fieldName; + this.getEnumCode = getEnumCode; + this.dictionaryName = dictionaryName; + this.enumClass = enumClass; + } + + public static EnumPresentRule instance(String fieldName, + Function getEnumCode, + String dictionaryName, + Class enumClass) { + return new EnumPresentRule<>(fieldName, getEnumCode, dictionaryName, enumClass); + } + + @Override + public Optional validate(ImdgValidationContext context) { + T validatedObject = context.getValidatedObject(); + String enumCode = getEnumCode.apply(validatedObject); + Imdg dictImdg = context.obtainMap( + dictionaryName, + enumClass + ); + D taskFromMap = dictImdg.getSingleObjectByFieldValues(Map.of("code", enumCode)); + if (taskFromMap == null) { + return of(Errors.WrongFieldValue, fieldName); + } + return empty(); + } +} From a6100aca8fc913eb61dab2638583c3a3414bd838 Mon Sep 17 00:00:00 2001 From: akulikov Date: Tue, 17 Jan 2023 12:45:31 +0300 Subject: [PATCH 06/14] FieldRequiredRule, tests for DictionaryPresentRule --- .../scheduler/config/ValidationConfig.java | 7 +- .../scheduler/error/PlannerErrors.java | 1 + .../service/ClearingCalendarService.java | 2 +- .../scheduler/service/PlannerService.java | 2 +- .../service/PlannerTemplateService.java | 2 +- .../{ => validation}/IRequestValidator.java | 2 +- .../rules/DictionaryPresentRule.java | 45 ++++++ .../validation/rules/EnumPresentRule.java | 48 ------- .../validation/rules/FieldRequiredRule.java | 24 ++++ .../validation/DictionaryPresentRuleTest.java | 130 ++++++++++++++++++ .../validation/FieldRequiredRuleTest.java | 44 ++++++ 11 files changed, 252 insertions(+), 55 deletions(-) rename clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/{ => validation}/IRequestValidator.java (99%) create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/DictionaryPresentRule.java delete mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/EnumPresentRule.java create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/FieldRequiredRule.java create mode 100644 clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java create mode 100644 clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java index f11175789..fde7183b9 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java @@ -5,7 +5,7 @@ import org.springframework.context.annotation.Configuration; import ru.clearing.platform.dictionary.TaskDictionary; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; -import ru.spcex.clearing.scheduler.validation.rules.EnumPresentRule; +import ru.spcex.clearing.scheduler.validation.rules.DictionaryPresentRule; import ru.spcex.platform.classes.base.SpcexObjectBase; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; @@ -44,10 +44,11 @@ public class ValidationConfig { Consumer addImdg = (s) -> context.addImdg(s, getImdg(s)); addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); return new ValidatorImpl<>(context, - EnumPresentRule.instance("task", + DictionaryPresentRule.instance("task", PlannerNewRequest::getTask, IMDGDistributedNames.Map_TaskDictionary, - TaskDictionary.class) + TaskDictionary.class, + true) ); }; } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/PlannerErrors.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/PlannerErrors.java index fc15d5a5b..8a52bc8f1 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/PlannerErrors.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/PlannerErrors.java @@ -4,6 +4,7 @@ import ru.spcex.platform.utils.enumeration.IEnumId; public enum PlannerErrors implements IEnumId { WrongEnumValue(10003L), + EmptyRequiredValue(10002L) ; private final Long id; diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java index efe225cd3..8131a9626 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java @@ -15,7 +15,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; -import ru.spcex.clearing.scheduler.IRequestValidator; +import ru.spcex.clearing.scheduler.validation.IRequestValidator; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java index 869168f21..bab9b5174 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java @@ -18,8 +18,8 @@ import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerUpdateReq import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.clearing.platform.messaging.service.Status; -import ru.spcex.clearing.scheduler.IRequestValidator; import ru.spcex.clearing.scheduler.error.PlannerErrors; +import ru.spcex.clearing.scheduler.validation.IRequestValidator; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.utils.enumeration.EnumMessage; diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java index d1eec0d90..6cf914e9b 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java @@ -15,7 +15,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; -import ru.spcex.clearing.scheduler.IRequestValidator; +import ru.spcex.clearing.scheduler.validation.IRequestValidator; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java similarity index 99% rename from clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java rename to clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java index 78285922a..2651aeb30 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/IRequestValidator.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java @@ -1,4 +1,4 @@ -package ru.spcex.clearing.scheduler; +package ru.spcex.clearing.scheduler.validation; import org.slf4j.Logger; import ru.clearing.platform.dictionary.AbstractDictionary; diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/DictionaryPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/DictionaryPresentRule.java new file mode 100644 index 000000000..b8c66a8cb --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/DictionaryPresentRule.java @@ -0,0 +1,45 @@ +package ru.spcex.clearing.scheduler.validation.rules; + +import ru.clearing.platform.dictionary.AbstractDictionary; +import ru.spcex.clearing.scheduler.error.PlannerErrors; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public record DictionaryPresentRule(String fieldName, + Function getEnumCode, + String dictionaryName, + Class enumClass, + boolean required) implements IValidationRule> { + + public static DictionaryPresentRule instance(String fieldName, + Function getEnumCode, + String dictionaryName, + Class enumClass, + boolean required) { + return new DictionaryPresentRule<>(fieldName, getEnumCode, dictionaryName, enumClass, required); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + String enumCode = getEnumCode.apply(validatedObject); + if (enumCode == null) { + return required ? of(PlannerErrors.EmptyRequiredValue, fieldName) : empty(); + } + Imdg dictImdg = context.obtainMap( + dictionaryName, + enumClass + ); + D dictionaryFromMap = dictImdg.getSingleObjectByFieldValues(Map.of("code", enumCode)); + if (dictionaryFromMap == null) { + return of(PlannerErrors.WrongEnumValue, fieldName); + } + return empty(); + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/EnumPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/EnumPresentRule.java deleted file mode 100644 index 36eda3401..000000000 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/EnumPresentRule.java +++ /dev/null @@ -1,48 +0,0 @@ -package ru.spcex.clearing.scheduler.validation.rules; - -import ru.spcex.clearing.scheduler.error.PlannerErrors; -import ru.spcex.platform.classes.base.SpcexObjectBase; -import ru.spcex.platform.imdg.api.Imdg; -import ru.spcex.platform.imdg.validation.ImdgValidationContext; -import ru.spcex.platform.utils.enumeration.EnumMessage; -import ru.spcex.platform.utils.validation.IValidationRule; - -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - -public class EnumPresentRule implements IValidationRule> { - protected final Function getEnumCode; - protected final String dictionaryName; - protected final String fieldName; - protected final Class enumClass; - - public EnumPresentRule(String fieldName, Function getEnumCode, String dictionaryName, Class enumClass) { - this.fieldName = fieldName; - this.getEnumCode = getEnumCode; - this.dictionaryName = dictionaryName; - this.enumClass = enumClass; - } - - public static EnumPresentRule instance(String fieldName, - Function getEnumCode, - String dictionaryName, - Class enumClass) { - return new EnumPresentRule<>(fieldName, getEnumCode, dictionaryName, enumClass); - } - - @Override - public Optional validate(ImdgValidationContext context) { - T validatedObject = context.getValidatedObject(); - String enumCode = getEnumCode.apply(validatedObject); - Imdg dictImdg = context.obtainMap( - dictionaryName, - enumClass - ); - D taskFromMap = dictImdg.getSingleObjectByFieldValues(Map.of("code", enumCode)); - if (taskFromMap == null) { - return of(PlannerErrors.WrongEnumValue, fieldName); - } - return empty(); - } -} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/FieldRequiredRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/FieldRequiredRule.java new file mode 100644 index 000000000..4c4701c5a --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/FieldRequiredRule.java @@ -0,0 +1,24 @@ +package ru.spcex.clearing.scheduler.validation.rules; + +import ru.spcex.clearing.scheduler.error.PlannerErrors; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.util.Optional; +import java.util.function.Function; + +public record FieldRequiredRule(String fieldName, Function getter) implements IValidationRule> { + + public static FieldRequiredRule instance(String fieldName, Function getter) { + return new FieldRequiredRule<>(fieldName, getter); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + V value = getter.apply(validatedObject); + if (value == null) return of(PlannerErrors.EmptyRequiredValue, fieldName); + return empty(); + } +} diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java new file mode 100644 index 000000000..897cb4a70 --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java @@ -0,0 +1,130 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.platform.dictionary.AbstractDictionary; +import ru.clearing.platform.dictionary.DayStatusDictionary; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.error.PlannerErrors; +import ru.spcex.clearing.scheduler.validation.rules.DictionaryPresentRule; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; +import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { + HazelcastServiceTestConfiguration.class}) +class DictionaryPresentRuleTest { + @Autowired + @Qualifier("hazelcastServiceTest") + private HazelcastService hazelcastServiceTest; + + @Test + public void dictionaryPresentRuleTest() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + testDictionary(IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class, + PlannerNewRequest.class, + "task", + PlannerNewRequest::getTask, + PlannerNewRequest::setTask); + testDictionary(IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class, + PlannerNewRequest.class, + "taskStatus", + PlannerNewRequest::getTaskStatus, + PlannerNewRequest::setTaskStatus); + testDictionary(IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class, + PlannerNewRequest.class, + "task", + PlannerNewRequest::getTask, + PlannerNewRequest::setTask); + testDictionary(IMDGDistributedNames.Map_DayStatusDictionary, + DayStatusDictionary.class, + ClearingCalendarNewRequest.class, + "dayStatus", + ClearingCalendarNewRequest::getDayStatus, + ClearingCalendarNewRequest::setDayStatus); + + } + + private void testDictionary(String dictionaryKey, + Class dictionaryClass, + Class recordClass, + String fieldName, + Function getter, + BiConsumer setter) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Imdg dictionaryImdg = hazelcastServiceTest.getImdg(dictionaryKey, dictionaryClass); + D td1 = dictionaryClass.getConstructor().newInstance(); + td1.setId(1L); + td1.setCode("CSD1"); + td1.setName("TEST NAME 1"); + dictionaryImdg.insert(td1); + D td2 = dictionaryClass.getConstructor().newInstance(); + td2.setId(2L); + td2.setCode("CSD2"); + td2.setName("TEST NAME 2"); + dictionaryImdg.insert(td2); + + BiFunction validatorBuilder = (plannerNewRequest, required) -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + context.addImdg(dictionaryKey, dictionaryImdg); + return new ValidatorImpl<>(context, + DictionaryPresentRule.instance(fieldName, + getter, + dictionaryKey, + dictionaryClass, + required) + ); + }; + R record = recordClass.getConstructor().newInstance(); + IValidator strictValidator = validatorBuilder.apply(record, true); + IValidator lazyValidator = validatorBuilder.apply(record, false); + + setter.accept(record, "CSD1"); + Collection enumMessages = strictValidator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + setter.accept(record, "CSD2"); + enumMessages = strictValidator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + setter.accept(record, null); + enumMessages = strictValidator.validateAll(); + assertEquals(1, enumMessages.size()); + assertEquals(PlannerErrors.EmptyRequiredValue, enumMessages.iterator().next().getSubject()); + enumMessages = lazyValidator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + setter.accept(record, "NOT_CSD"); + enumMessages = strictValidator.validateAll(); + assertEquals(1, enumMessages.size()); + assertEquals(PlannerErrors.WrongEnumValue, enumMessages.iterator().next().getSubject()); + enumMessages = lazyValidator.validateAll(); + assertEquals(1, enumMessages.size()); + assertEquals(PlannerErrors.WrongEnumValue, enumMessages.iterator().next().getSubject()); + } + +} \ No newline at end of file diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java new file mode 100644 index 000000000..3cfb9991d --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java @@ -0,0 +1,44 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.validation.rules.FieldRequiredRule; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.util.Collection; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +class FieldRequiredRuleTest { + + @Test + public void fieldRequiredRuleTest() { + Function validatorBuilder = plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + return new ValidatorImpl<>(context, + new FieldRequiredRule<>("task", PlannerNewRequest::getTask) + ); + }; + PlannerNewRequest plannerNewRequest = new PlannerNewRequest(); + + plannerNewRequest.setTask("test"); + IValidator validator = validatorBuilder.apply(plannerNewRequest); + Collection enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + plannerNewRequest.setTask(null); + validator = validatorBuilder.apply(plannerNewRequest); + enumMessages = validator.validateAll(); + assertEquals(1, enumMessages.size()); + } + +} \ No newline at end of file From 299cbb1abe11f14d605707c7cf0360019edf207b Mon Sep 17 00:00:00 2001 From: akulikov Date: Tue, 17 Jan 2023 13:35:13 +0300 Subject: [PATCH 07/14] Some ValidatorRule and PlannerNewRequest validator --- .../scheduler/config/ValidationConfig.java | 41 ++++++- .../scheduler/error/PlannerErrors.java | 21 ---- .../scheduler/error/ValidationError.java | 28 +++++ .../scheduler/service/PlannerService.java | 3 +- .../validation/IRequestValidator.java | 2 +- .../rules/common/DateNotBeforeRule.java | 30 +++++ .../{ => common}/DictionaryPresentRule.java | 31 +++--- .../rules/common/EnumPresentRule.java | 40 +++++++ .../rules/{ => common}/FieldRequiredRule.java | 6 +- .../rules/common/IdPresentRule.java | 62 +++++++++++ .../rules/common/TimeNotBeforeRule.java | 30 +++++ .../validation/DateNotBeforeRuleTest.java | 49 ++++++++ .../validation/DictionaryPresentRuleTest.java | 77 ++++++------- .../validation/EnumPresentRuleTest.java | 97 ++++++++++++++++ .../validation/FieldRequiredRuleTest.java | 2 +- .../validation/IdPresentRuleTest.java | 105 ++++++++++++++++++ .../validation/TimeNotBeforeRuleTest.java | 49 ++++++++ .../platform/enumeration/WorkflowStatus.java | 19 ++++ 18 files changed, 599 insertions(+), 93 deletions(-) delete mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/PlannerErrors.java create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java rename clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/{ => common}/DictionaryPresentRule.java (58%) create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java rename clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/{ => common}/FieldRequiredRule.java (79%) create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java create mode 100644 clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DateNotBeforeRuleTest.java create mode 100644 clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/EnumPresentRuleTest.java create mode 100644 clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/IdPresentRuleTest.java create mode 100644 clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/TimeNotBeforeRuleTest.java create mode 100644 platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/WorkflowStatus.java diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java index fde7183b9..28bf7a2c4 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java @@ -2,11 +2,17 @@ package ru.spcex.clearing.scheduler.config; 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.security.Security; import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; -import ru.spcex.clearing.scheduler.validation.rules.DictionaryPresentRule; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.*; import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.enumeration.Market; +import ru.spcex.platform.enumeration.WorkflowStatus; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.validation.ImdgValidationContext; @@ -27,11 +33,11 @@ public class ValidationConfig { this.imdgs = new HashMap<>(); BiConsumer> addImdg = (s, aClass) -> imdgs.put(s, imdgProvider.getImdg(s, aClass)); addImdg.accept(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class); + addImdg.accept(IMDGDistributedNames.Map_Company, Company.class); + addImdg.accept(IMDGDistributedNames.Map_Security, Security.class); } - /** - * чтобы во всех валидаторах был один экземпляр Imdg - */ private Imdg getImdg(String key) { return imdgs.get(key); } @@ -47,8 +53,31 @@ public class ValidationConfig { DictionaryPresentRule.instance("task", PlannerNewRequest::getTask, IMDGDistributedNames.Map_TaskDictionary, - TaskDictionary.class, - true) + TaskDictionary.class), + TimeNotBeforeRule.instance("taskTime", + PlannerNewRequest::getTaskTime), + DateNotBeforeRule.instance("clearingDate", + PlannerNewRequest::getClearingDate), + EnumPresentRule.instance("market", + PlannerNewRequest::getMarket, + Market.values(), + false), + DictionaryPresentRule.instance("taskStatus", + PlannerNewRequest::getTaskStatus, + IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class), + IdPresentRule.instance("companyId", + PlannerNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + IdPresentRule.instance("securityId", + PlannerNewRequest::getSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + ValidationError.SecurityNotFound, + security -> WorkflowStatus.Active.getKey().equals(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive) ); }; } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/PlannerErrors.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/PlannerErrors.java deleted file mode 100644 index 8a52bc8f1..000000000 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/PlannerErrors.java +++ /dev/null @@ -1,21 +0,0 @@ -package ru.spcex.clearing.scheduler.error; - -import ru.spcex.platform.utils.enumeration.IEnumId; - -public enum PlannerErrors implements IEnumId { - WrongEnumValue(10003L), - EmptyRequiredValue(10002L) - ; - - private final Long id; - - PlannerErrors(Long id) { - this.id = id; - } - - - @Override - public Long getId() { - return null; - } -} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java new file mode 100644 index 000000000..bdc24ed06 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java @@ -0,0 +1,28 @@ +package ru.spcex.clearing.scheduler.error; + +import ru.spcex.platform.utils.enumeration.IEnumId; + +public enum ValidationError implements IEnumId { + WrongDictionaryValue(10003L), + EmptyRequiredValue(10002L), + WrongEnumValue(777L), //todo set code + TaskForPastDate(7010L), + TaskForPastTime(7011L), + CompanyNotFound(7014L), + SecurityNotFound(7012L), + CompanyNotActive(7015L), + SecurityNotActive(7013L) + ; + + private final Long id; + + ValidationError(Long id) { + this.id = id; + } + + + @Override + public Long getId() { + return null; + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java index bab9b5174..4a069ec79 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java @@ -18,7 +18,6 @@ import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerUpdateReq import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.clearing.platform.messaging.service.Status; -import ru.spcex.clearing.scheduler.error.PlannerErrors; import ru.spcex.clearing.scheduler.validation.IRequestValidator; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; @@ -74,7 +73,7 @@ public class PlannerService extends QueueConsumer implements InitializingBean { IValidator validator = validationFactory.apply(req); Optional validationError = validator.tillFirstError(); if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(new EnumMessage(PlannerErrors.WrongEnumValue)); + String errorMsg = messageResolver.resolve(validationError.get()); log.error("cannot process PlannerNewRequest id={}: {}", userRequest.getId(), errorMsg); return new RequestInfoUpdate() .setId(userRequest.getId()) diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java index 2651aeb30..baaee072d 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java @@ -225,7 +225,7 @@ public interface IRequestValidator { */ static boolean checkErrorList(List errors, Logger log) { if (!errors.isEmpty()) { - log.error("Validation error: [{}]", + log.error("Validation idNotPresentError: [{}]", errors.stream().map(IRequestValidator.ValidationError::toString).collect(Collectors.joining(", ")) ); return true; diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java new file mode 100644 index 000000000..aaa94d43e --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java @@ -0,0 +1,30 @@ +package ru.spcex.clearing.scheduler.validation.rules.common; + +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.time.LocalDate; +import java.util.Optional; +import java.util.function.Function; + +public record DateNotBeforeRule(String fieldName, Function getter, boolean required) implements IValidationRule> { + + public static DateNotBeforeRule instance(String fieldName, Function getter, boolean required) { + return new DateNotBeforeRule<>(fieldName, getter, required); + } + + public static DateNotBeforeRule instance(String fieldName, Function getter) { + return new DateNotBeforeRule<>(fieldName, getter, true); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + LocalDate date = getter.apply(validatedObject); + if (date == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : Optional.empty(); + if (date.isBefore(LocalDate.now())) return of(ValidationError.TaskForPastDate, fieldName); + return Optional.empty(); + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/DictionaryPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java similarity index 58% rename from clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/DictionaryPresentRule.java rename to clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java index b8c66a8cb..68301c308 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/DictionaryPresentRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java @@ -1,7 +1,7 @@ -package ru.spcex.clearing.scheduler.validation.rules; +package ru.spcex.clearing.scheduler.validation.rules.common; import ru.clearing.platform.dictionary.AbstractDictionary; -import ru.spcex.clearing.scheduler.error.PlannerErrors; +import ru.spcex.clearing.scheduler.error.ValidationError; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.utils.enumeration.EnumMessage; @@ -12,33 +12,38 @@ import java.util.Optional; import java.util.function.Function; public record DictionaryPresentRule(String fieldName, - Function getEnumCode, + Function getter, String dictionaryName, - Class enumClass, + Class dictionaryClass, boolean required) implements IValidationRule> { public static DictionaryPresentRule instance(String fieldName, - Function getEnumCode, + Function getter, String dictionaryName, - Class enumClass, + Class dictionaryClass, boolean required) { - return new DictionaryPresentRule<>(fieldName, getEnumCode, dictionaryName, enumClass, required); + return new DictionaryPresentRule<>(fieldName, getter, dictionaryName, dictionaryClass, required); + } + + public static DictionaryPresentRule instance(String fieldName, + Function getter, + String dictionaryName, + Class dictionaryClass) { + return new DictionaryPresentRule<>(fieldName, getter, dictionaryName, dictionaryClass, true); } @Override public Optional validate(ImdgValidationContext context) { R validatedObject = context.getValidatedObject(); - String enumCode = getEnumCode.apply(validatedObject); - if (enumCode == null) { - return required ? of(PlannerErrors.EmptyRequiredValue, fieldName) : empty(); - } + String enumCode = getter.apply(validatedObject); + if (enumCode == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : empty(); Imdg dictImdg = context.obtainMap( dictionaryName, - enumClass + dictionaryClass ); D dictionaryFromMap = dictImdg.getSingleObjectByFieldValues(Map.of("code", enumCode)); if (dictionaryFromMap == null) { - return of(PlannerErrors.WrongEnumValue, fieldName); + return of(ValidationError.WrongDictionaryValue, fieldName); } return empty(); } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java new file mode 100644 index 000000000..6a1cf9e58 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java @@ -0,0 +1,40 @@ +package ru.spcex.clearing.scheduler.validation.rules.common; + +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumKey; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.util.Optional; +import java.util.function.Function; + +public record EnumPresentRule(String fieldName, + Function getter, + E[] enumValues, + boolean required) implements IValidationRule> { + + public static EnumPresentRule instance(String fieldName, + Function getter, + E[] enumValues, + boolean required) { + return new EnumPresentRule<>(fieldName, getter, enumValues, required); + } + + public static EnumPresentRule instance(String fieldName, + Function getter, + E[] enumValues) { + return new EnumPresentRule<>(fieldName, getter, enumValues, true); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + String enumCode = getter.apply(validatedObject); + if (enumCode == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : empty(); + for (E enumValue : enumValues) { + if (enumValue.getKey().equals(enumCode)) return empty(); + } + return of(ValidationError.WrongEnumValue, fieldName); + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/FieldRequiredRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/FieldRequiredRule.java similarity index 79% rename from clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/FieldRequiredRule.java rename to clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/FieldRequiredRule.java index 4c4701c5a..80c3e5600 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/FieldRequiredRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/FieldRequiredRule.java @@ -1,6 +1,6 @@ -package ru.spcex.clearing.scheduler.validation.rules; +package ru.spcex.clearing.scheduler.validation.rules.common; -import ru.spcex.clearing.scheduler.error.PlannerErrors; +import ru.spcex.clearing.scheduler.error.ValidationError; import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.validation.IValidationRule; @@ -18,7 +18,7 @@ public record FieldRequiredRule(String fieldName, Function getter) i public Optional validate(ImdgValidationContext context) { R validatedObject = context.getValidatedObject(); V value = getter.apply(validatedObject); - if (value == null) return of(PlannerErrors.EmptyRequiredValue, fieldName); + if (value == null) return of(ValidationError.EmptyRequiredValue, fieldName); return empty(); } } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java new file mode 100644 index 000000000..dd71412e0 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java @@ -0,0 +1,62 @@ +package ru.spcex.clearing.scheduler.validation.rules.common; + +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public record IdPresentRule( + String fieldName, + Function idGetter, + Function[] additionalChecks, + String mapName, + Class mapClass, + ValidationError idNotPresentError, + boolean required +) implements IValidationRule> { + + @SafeVarargs + public static IdPresentRule instance(String fieldName, + Function idGetter, + String mapName, + Class mapClass, + ValidationError idNotPresentError, + boolean required, + Function ... additionalChecks) { + return new IdPresentRule<>(fieldName, idGetter, additionalChecks, mapName, mapClass, idNotPresentError, required); + } + + @SafeVarargs + public static IdPresentRule instance(String fieldName, + Function idGetter, + String mapName, + Class mapClass, + ValidationError idNotPresentError, + Function ... additionalChecks) { + return new IdPresentRule<>(fieldName, idGetter, additionalChecks, mapName, mapClass, idNotPresentError, true); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + Long id = idGetter.apply(validatedObject); + if (id == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : empty(); + Imdg imdg = context.obtainMap(mapName, mapClass); + V fromMap = imdg.getSingleObjectByFieldValues(Map.of("id", id)); + if (fromMap == null) { + return of(idNotPresentError, fieldName); + } + for (Function additionalCheck : additionalChecks) { + ValidationError validationError = additionalCheck.apply(fromMap); + if (validationError != null) + return of(validationError, fieldName); + } + return empty(); + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java new file mode 100644 index 000000000..9d172e0bd --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java @@ -0,0 +1,30 @@ +package ru.spcex.clearing.scheduler.validation.rules.common; + +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.time.LocalTime; +import java.util.Optional; +import java.util.function.Function; + +public record TimeNotBeforeRule(String fieldName, Function getter, boolean required) implements IValidationRule> { + + public static TimeNotBeforeRule instance(String fieldName, Function getter, boolean required) { + return new TimeNotBeforeRule<>(fieldName, getter, required); + } + + public static TimeNotBeforeRule instance(String fieldName, Function getter) { + return new TimeNotBeforeRule<>(fieldName, getter, true); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + LocalTime date = getter.apply(validatedObject); + if (date == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : Optional.empty(); + if (date.isBefore(LocalTime.now())) return of(ValidationError.TaskForPastTime, fieldName); + return Optional.empty(); + } +} diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DateNotBeforeRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DateNotBeforeRuleTest.java new file mode 100644 index 000000000..311bf050c --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DateNotBeforeRuleTest.java @@ -0,0 +1,49 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.validation.rules.common.DateNotBeforeRule; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +class DateNotBeforeRuleTest { + + @Test + public void dateNotBeforeRuleTest() { + Function validatorBuilder = plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + return new ValidatorImpl<>(context, + DateNotBeforeRule.instance("clearingDate", PlannerNewRequest::getClearingDate)); + }; + PlannerNewRequest plannerNewRequest = new PlannerNewRequest(); + + plannerNewRequest.setClearingDate(LocalDate.now().plusDays(1)); + IValidator validator = validatorBuilder.apply(plannerNewRequest); + Collection enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + plannerNewRequest.setClearingDate(LocalDate.now()); + validator = validatorBuilder.apply(plannerNewRequest); + enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + plannerNewRequest.setClearingDate(LocalDate.now().minusDays(1)); + validator = validatorBuilder.apply(plannerNewRequest); + enumMessages = validator.validateAll(); + assertEquals(1, enumMessages.size()); + } + +} \ No newline at end of file diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java index 897cb4a70..3cbcf6698 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java @@ -13,12 +13,16 @@ import ru.clearing.platform.dictionary.TaskStatusDictionary; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; -import ru.spcex.clearing.scheduler.error.PlannerErrors; -import ru.spcex.clearing.scheduler.validation.rules.DictionaryPresentRule; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.DictionaryPresentRule; +import ru.spcex.platform.enumeration.DayStatus; +import ru.spcex.platform.enumeration.Status; +import ru.spcex.platform.enumeration.Task; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumKey; import ru.spcex.platform.utils.validation.IValidator; import ru.spcex.platform.utils.validation.ValidatorImpl; import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; @@ -26,7 +30,6 @@ import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.function.BiConsumer; -import java.util.function.BiFunction; import java.util.function.Function; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -46,85 +49,67 @@ class DictionaryPresentRuleTest { TaskDictionary.class, PlannerNewRequest.class, "task", + Task.values(), PlannerNewRequest::getTask, PlannerNewRequest::setTask); testDictionary(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class, PlannerNewRequest.class, "taskStatus", + Status.values(), PlannerNewRequest::getTaskStatus, PlannerNewRequest::setTaskStatus); - testDictionary(IMDGDistributedNames.Map_TaskDictionary, - TaskDictionary.class, - PlannerNewRequest.class, - "task", - PlannerNewRequest::getTask, - PlannerNewRequest::setTask); testDictionary(IMDGDistributedNames.Map_DayStatusDictionary, DayStatusDictionary.class, ClearingCalendarNewRequest.class, "dayStatus", + DayStatus.values(), ClearingCalendarNewRequest::getDayStatus, ClearingCalendarNewRequest::setDayStatus); } - private void testDictionary(String dictionaryKey, + private void testDictionary(String dictionaryKey, Class dictionaryClass, Class recordClass, String fieldName, + E[] enumValues, Function getter, BiConsumer setter) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Imdg dictionaryImdg = hazelcastServiceTest.getImdg(dictionaryKey, dictionaryClass); - D td1 = dictionaryClass.getConstructor().newInstance(); - td1.setId(1L); - td1.setCode("CSD1"); - td1.setName("TEST NAME 1"); - dictionaryImdg.insert(td1); - D td2 = dictionaryClass.getConstructor().newInstance(); - td2.setId(2L); - td2.setCode("CSD2"); - td2.setName("TEST NAME 2"); - dictionaryImdg.insert(td2); + long idIdx = 0; + for (E enumValue : enumValues) { + D td = dictionaryClass.getConstructor().newInstance(); + td.setId(idIdx++); + td.setCode(enumValue.getKey()); + dictionaryImdg.insert(td); + } - BiFunction validatorBuilder = (plannerNewRequest, required) -> { + Function validatorBuilder = request -> { ImdgValidationContext context = new ImdgValidationContext<>(); - context.setValidatedObject(plannerNewRequest); + context.setValidatedObject(request); context.addImdg(dictionaryKey, dictionaryImdg); return new ValidatorImpl<>(context, DictionaryPresentRule.instance(fieldName, getter, dictionaryKey, - dictionaryClass, - required) + dictionaryClass) ); }; R record = recordClass.getConstructor().newInstance(); - IValidator strictValidator = validatorBuilder.apply(record, true); - IValidator lazyValidator = validatorBuilder.apply(record, false); + IValidator validator = validatorBuilder.apply(record); - setter.accept(record, "CSD1"); - Collection enumMessages = strictValidator.validateAll(); - assertTrue(enumMessages.isEmpty()); + Collection enumMessages; + for (E enumValue : enumValues) { + setter.accept(record, enumValue.getKey()); + enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + } - setter.accept(record, "CSD2"); - enumMessages = strictValidator.validateAll(); - assertTrue(enumMessages.isEmpty()); - - setter.accept(record, null); - enumMessages = strictValidator.validateAll(); + setter.accept(record, "BAD_VALUE"); + enumMessages = validator.validateAll(); assertEquals(1, enumMessages.size()); - assertEquals(PlannerErrors.EmptyRequiredValue, enumMessages.iterator().next().getSubject()); - enumMessages = lazyValidator.validateAll(); - assertTrue(enumMessages.isEmpty()); - - setter.accept(record, "NOT_CSD"); - enumMessages = strictValidator.validateAll(); - assertEquals(1, enumMessages.size()); - assertEquals(PlannerErrors.WrongEnumValue, enumMessages.iterator().next().getSubject()); - enumMessages = lazyValidator.validateAll(); - assertEquals(1, enumMessages.size()); - assertEquals(PlannerErrors.WrongEnumValue, enumMessages.iterator().next().getSubject()); + assertEquals(ValidationError.WrongDictionaryValue, enumMessages.iterator().next().getSubject()); } } \ No newline at end of file diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/EnumPresentRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/EnumPresentRuleTest.java new file mode 100644 index 000000000..8303e0872 --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/EnumPresentRuleTest.java @@ -0,0 +1,97 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.platform.dictionary.AbstractDictionary; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.EnumPresentRule; +import ru.spcex.platform.enumeration.DayStatus; +import ru.spcex.platform.enumeration.Status; +import ru.spcex.platform.enumeration.Task; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumKey; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; +import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { + HazelcastServiceTestConfiguration.class}) +class EnumPresentRuleTest { + @Autowired + @Qualifier("hazelcastServiceTest") + private HazelcastService hazelcastServiceTest; + + @Test + public void enumPresentRuleTest() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + testEnum( + PlannerNewRequest.class, + "task", + Task.values(), + PlannerNewRequest::getTask, + PlannerNewRequest::setTask); + testEnum( + PlannerNewRequest.class, + "taskStatus", + Status.values(), + PlannerNewRequest::getTaskStatus, + PlannerNewRequest::setTaskStatus); + testEnum( + ClearingCalendarNewRequest.class, + "dayStatus", + DayStatus.values(), + ClearingCalendarNewRequest::getDayStatus, + ClearingCalendarNewRequest::setDayStatus); + + } + + private void testEnum(Class recordClass, + String fieldName, + E[] enumValues, + Function getter, + BiConsumer setter) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + + BiFunction validatorBuilder = (request, required) -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(request); + return new ValidatorImpl<>(context, + EnumPresentRule.instance(fieldName, + getter, + enumValues, + required) + ); + }; + R record = recordClass.getConstructor().newInstance(); + IValidator strictValidator = validatorBuilder.apply(record, true); + + Collection enumMessages; + for (E enumValue : enumValues) { + setter.accept(record, enumValue.getKey()); + enumMessages = strictValidator.validateAll(); + assertTrue(enumMessages.isEmpty()); + } + + setter.accept(record, "BAD_VALUE"); + enumMessages = strictValidator.validateAll(); + assertEquals(1, enumMessages.size()); + assertEquals(ValidationError.WrongEnumValue, enumMessages.iterator().next().getSubject()); + } + +} \ No newline at end of file diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java index 3cfb9991d..78cbec5d0 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.test.context.junit.jupiter.SpringExtension; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; -import ru.spcex.clearing.scheduler.validation.rules.FieldRequiredRule; +import ru.spcex.clearing.scheduler.validation.rules.common.FieldRequiredRule; import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.validation.IValidator; diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/IdPresentRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/IdPresentRuleTest.java new file mode 100644 index 000000000..9bc738c22 --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/IdPresentRuleTest.java @@ -0,0 +1,105 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.security.Security; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.IdPresentRule; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; +import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.function.BiConsumer; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { + HazelcastServiceTestConfiguration.class}) +class IdPresentRuleTest { + private final static Long TEST_ID = 777L; + + @Autowired + @Qualifier("hazelcastServiceTest") + private HazelcastService hazelcastServiceTest; + + @Test + public void idPresentRuleTest() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + testIdPresentRule( + "companyId", + PlannerNewRequest::getCompanyId, + PlannerNewRequest::setCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + PlannerNewRequest.class, + ValidationError.CompanyNotFound, + ValidationError.CompanyNotActive + ); + testIdPresentRule( + "securityId", + PlannerNewRequest::getSecurityId, + PlannerNewRequest::setSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + PlannerNewRequest.class, + ValidationError.SecurityNotFound, + ValidationError.SecurityNotActive + ); + } + + private void testIdPresentRule(String fieldName, + Function getter, + BiConsumer setter, + String mapName, + Class mapClass, + Class objClass, + ValidationError notFoundExpectedError, + ValidationError notActiveExpectedError) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Imdg imdg = hazelcastServiceTest.getImdg(mapName, mapClass); + Function validatorBuilder = request -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(request); + context.addImdg(mapName, imdg); + return new ValidatorImpl<>(context, IdPresentRule.instance(fieldName, + getter, + mapName, + mapClass, + notFoundExpectedError, + true, + company -> company.getId().equals(TEST_ID) ? null : notActiveExpectedError + )); + }; + + R obj = objClass.getConstructor().newInstance(); + setter.accept(obj, TEST_ID); + IValidator validator = validatorBuilder.apply(obj); + Collection enumMessages = validator.validateAll(); + assertEquals(1, enumMessages.size()); + assertEquals(notFoundExpectedError, enumMessages.iterator().next().getSubject()); + + D map = mapClass.getConstructor().newInstance(); + map.setId(TEST_ID); + imdg.insert(map); + + enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + } + +} \ No newline at end of file diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/TimeNotBeforeRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/TimeNotBeforeRuleTest.java new file mode 100644 index 000000000..32206cda7 --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/TimeNotBeforeRuleTest.java @@ -0,0 +1,49 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.validation.rules.common.TimeNotBeforeRule; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.time.LocalTime; +import java.util.Collection; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +class TimeNotBeforeRuleTest { + + @Test + public void timeNotBeforeRuleTest() { + Function validatorBuilder = plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + return new ValidatorImpl<>(context, + TimeNotBeforeRule.instance("taskTime", PlannerNewRequest::getTaskTime)); + }; + PlannerNewRequest plannerNewRequest = new PlannerNewRequest(); + + plannerNewRequest.setTaskTime(LocalTime.now().plusMinutes(1)); + IValidator validator = validatorBuilder.apply(plannerNewRequest); + Collection enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + plannerNewRequest.setTaskTime(LocalTime.now().plusSeconds(1)); + validator = validatorBuilder.apply(plannerNewRequest); + enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + plannerNewRequest.setTaskTime(LocalTime.now().minusMinutes(1)); + validator = validatorBuilder.apply(plannerNewRequest); + enumMessages = validator.validateAll(); + assertEquals(1, enumMessages.size()); + } + +} \ No newline at end of file diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/WorkflowStatus.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/WorkflowStatus.java new file mode 100644 index 000000000..0e1ccdd49 --- /dev/null +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/WorkflowStatus.java @@ -0,0 +1,19 @@ +package ru.spcex.platform.enumeration; + +import ru.spcex.platform.utils.enumeration.IEnumKey; + +public enum WorkflowStatus implements IEnumKey { + Active("ACTV"), + Blocked("BLKD"); + + private final String key; + + WorkflowStatus(String key) { + this.key = key; + } + + @Override + public String getKey() { + return key; + } +} From 45e5c588b58b6f2909c2f65722588ed9a356c8d1 Mon Sep 17 00:00:00 2001 From: akulikov Date: Tue, 17 Jan 2023 16:59:07 +0300 Subject: [PATCH 08/14] PlannerTemplateServiceValidation --- .../SchedulerServiceApplication.java | 20 +-- .../scheduler/config/ValidationConfig.java | 85 ------------ .../PlannerTemplateValidationConfig.java | 115 ++++++++++++++++ .../validation/PlannerValidationConfig.java | 127 ++++++++++++++++++ .../config/validation/ValidationConfig.java | 49 +++++++ .../scheduler/error/ValidationError.java | 1 + .../scheduler/service/PlannerService.java | 76 +++++++---- .../service/PlannerTemplateService.java | 84 +++++++++--- .../HazelcastServiceTestConfiguration.java | 7 + .../service/PlannerTemplateServiceTest.java | 4 +- 10 files changed, 420 insertions(+), 148 deletions(-) delete mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/SchedulerServiceApplication.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/SchedulerServiceApplication.java index 8558b06f8..6022af291 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/SchedulerServiceApplication.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/SchedulerServiceApplication.java @@ -2,29 +2,11 @@ package ru.spcex.clearing.scheduler; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ConfigurableApplicationContext; -import ru.spcex.clearing.platform.messaging.domain.BaseRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; -import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; -import ru.spcex.clearing.scheduler.service.PlannerService; @SpringBootApplication public class SchedulerServiceApplication { public static void main(String[] args) { SpringApplication springApplication = new SpringApplication(SchedulerServiceApplication.class); - ConfigurableApplicationContext context = springApplication.run(args); - PlannerService plannerService = context.getBean(PlannerService.class); - try { - Thread.sleep(100000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - var baseRequest = new BaseRequest(); - var plannerNewRequest = new PlannerNewRequest(); - plannerNewRequest.task = "GBAL"; - baseRequest.setId(777L); - baseRequest.setRequestPayload(plannerNewRequest); - RequestInfoUpdate requestInfoUpdate = plannerService.newScheduler(baseRequest); - System.out.println(requestInfoUpdate.toString()); + springApplication.run(args); } } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java deleted file mode 100644 index 28bf7a2c4..000000000 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ValidationConfig.java +++ /dev/null @@ -1,85 +0,0 @@ -package ru.spcex.clearing.scheduler.config; - -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.security.Security; -import ru.clearing.platform.dictionary.TaskDictionary; -import ru.clearing.platform.dictionary.TaskStatusDictionary; -import ru.spcex.clearing.imdg.IMDGDistributedNames; -import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; -import ru.spcex.clearing.scheduler.error.ValidationError; -import ru.spcex.clearing.scheduler.validation.rules.common.*; -import ru.spcex.platform.classes.base.SpcexObjectBase; -import ru.spcex.platform.enumeration.Market; -import ru.spcex.platform.enumeration.WorkflowStatus; -import ru.spcex.platform.imdg.api.Imdg; -import ru.spcex.platform.imdg.api.ImdgProvider; -import ru.spcex.platform.imdg.validation.ImdgValidationContext; -import ru.spcex.platform.utils.validation.IValidator; -import ru.spcex.platform.utils.validation.ValidatorImpl; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; - -@Configuration -public class ValidationConfig { - private final Map> imdgs; - - public ValidationConfig(ImdgProvider imdgProvider) { - this.imdgs = new HashMap<>(); - BiConsumer> addImdg = (s, aClass) -> imdgs.put(s, imdgProvider.getImdg(s, aClass)); - addImdg.accept(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class); - addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class); - addImdg.accept(IMDGDistributedNames.Map_Company, Company.class); - addImdg.accept(IMDGDistributedNames.Map_Security, Security.class); - } - - private Imdg getImdg(String key) { - return imdgs.get(key); - } - - @Bean("plannerNewRequestValidator") - public Function plannerNewRequestValidator() { - return plannerNewRequest -> { - ImdgValidationContext context = new ImdgValidationContext<>(); - context.setValidatedObject(plannerNewRequest); - Consumer addImdg = (s) -> context.addImdg(s, getImdg(s)); - addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); - return new ValidatorImpl<>(context, - DictionaryPresentRule.instance("task", - PlannerNewRequest::getTask, - IMDGDistributedNames.Map_TaskDictionary, - TaskDictionary.class), - TimeNotBeforeRule.instance("taskTime", - PlannerNewRequest::getTaskTime), - DateNotBeforeRule.instance("clearingDate", - PlannerNewRequest::getClearingDate), - EnumPresentRule.instance("market", - PlannerNewRequest::getMarket, - Market.values(), - false), - DictionaryPresentRule.instance("taskStatus", - PlannerNewRequest::getTaskStatus, - IMDGDistributedNames.Map_TaskStatusDictionary, - TaskStatusDictionary.class), - IdPresentRule.instance("companyId", - PlannerNewRequest::getCompanyId, - IMDGDistributedNames.Map_Company, - Company.class, - ValidationError.CompanyNotFound, - company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), - IdPresentRule.instance("securityId", - PlannerNewRequest::getSecurityId, - IMDGDistributedNames.Map_Security, - Security.class, - ValidationError.SecurityNotFound, - security -> WorkflowStatus.Active.getKey().equals(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive) - ); - }; - } - -} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java new file mode 100644 index 000000000..efb0b64ad --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java @@ -0,0 +1,115 @@ +package ru.spcex.clearing.scheduler.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.scheduler.PlannerTemplate; +import ru.clearing.classes.statics.data.security.Security; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateUpdateRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.DictionaryPresentRule; +import ru.spcex.clearing.scheduler.validation.rules.common.IdPresentRule; +import ru.spcex.clearing.scheduler.validation.rules.common.TimeNotBeforeRule; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; + +@Configuration +public class PlannerTemplateValidationConfig { + + @Bean("plannerTemplateNewRequestValidator") + public Function plannerNewRequestValidator(Map> imdgForValidation) { + return plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_Security); + return new ValidatorImpl<>(context, + DictionaryPresentRule.instance("task", + PlannerTemplateNewRequest::getTask, + IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class), + TimeNotBeforeRule.instance("taskTime", + PlannerTemplateNewRequest::getTaskTime), + DictionaryPresentRule.instance("taskStatus", + PlannerTemplateNewRequest::getTaskStatus, + IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class), + IdPresentRule.instance("companyId", + PlannerTemplateNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + IdPresentRule.instance("securityId", + PlannerTemplateNewRequest::getSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + ValidationError.SecurityNotFound, + security -> WorkflowStatus.Active.getKey().equals(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive) + ); + }; + } + + @Bean("plannerTemplateUpdateRequestValidator") + public Function plannerUpdateRequestValidator(Map> imdgForValidation) { + return plannerUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerUpdateRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_Security); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + PlannerTemplateUpdateRequest::getId, + IMDGDistributedNames.Map_PlannerTemplate, + PlannerTemplate.class, + ValidationError.WrongUpdate), + DictionaryPresentRule.instance("task", + PlannerTemplateNewRequest::getTask, + IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class, + false), + TimeNotBeforeRule.instance("taskTime", + PlannerTemplateNewRequest::getTaskTime, + false), + DictionaryPresentRule.instance("taskStatus", + PlannerTemplateNewRequest::getTaskStatus, + IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class, + false), + IdPresentRule.instance("companyId", + PlannerTemplateNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + false, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + IdPresentRule.instance("securityId", + PlannerTemplateNewRequest::getSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + ValidationError.SecurityNotFound, + false, + security -> WorkflowStatus.Active.getKey().equals(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive) + ); + }; + } + +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java new file mode 100644 index 000000000..7c8963650 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java @@ -0,0 +1,127 @@ +package ru.spcex.clearing.scheduler.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.scheduler.Planner; +import ru.clearing.classes.statics.data.security.Security; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerUpdateRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.*; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.enumeration.Market; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; + +@Configuration +public class PlannerValidationConfig { + + @Bean("plannerNewRequestValidator") + public Function plannerNewRequestValidator(Map> imdgForValidation) { + return plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_Security); + return new ValidatorImpl<>(context, + DictionaryPresentRule.instance("task", + PlannerNewRequest::getTask, + IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class), + TimeNotBeforeRule.instance("taskTime", + PlannerNewRequest::getTaskTime), + DateNotBeforeRule.instance("clearingDate", + PlannerNewRequest::getClearingDate), + EnumPresentRule.instance("market", + PlannerNewRequest::getMarket, + Market.values(), + false), + DictionaryPresentRule.instance("taskStatus", + PlannerNewRequest::getTaskStatus, + IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class), + IdPresentRule.instance("companyId", + PlannerNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + IdPresentRule.instance("securityId", + PlannerNewRequest::getSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + ValidationError.SecurityNotFound, + security -> WorkflowStatus.Active.getKey().equals(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive) + ); + }; + } + + @Bean("plannerUpdateRequestValidator") + public Function plannerUpdateRequestValidator(Map> imdgForValidation) { + return plannerUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerUpdateRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_Security); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + PlannerUpdateRequest::getId, + IMDGDistributedNames.Map_Planner, + Planner.class, + ValidationError.WrongUpdate), + DictionaryPresentRule.instance("task", + PlannerUpdateRequest::getTask, + IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class, + false), + TimeNotBeforeRule.instance("taskTime", + PlannerUpdateRequest::getTaskTime, + false), + DateNotBeforeRule.instance("clearingDate", + PlannerUpdateRequest::getClearingDate, + false), + EnumPresentRule.instance("market", + PlannerUpdateRequest::getMarket, + Market.values(), + false), + DictionaryPresentRule.instance("taskStatus", + PlannerUpdateRequest::getTaskStatus, + IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class, + false), + IdPresentRule.instance("companyId", + PlannerUpdateRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + false, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + IdPresentRule.instance("securityId", + PlannerUpdateRequest::getSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + ValidationError.SecurityNotFound, + false, + security -> WorkflowStatus.Active.getKey().equals(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive) + ); + }; + } + +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java new file mode 100644 index 000000000..e4b471c69 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java @@ -0,0 +1,49 @@ +package ru.spcex.clearing.scheduler.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.security.Security; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.scheduler.validation.rules.common.FieldRequiredRule; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; + +@Configuration +public class ValidationConfig { + + @Bean("imdgForValidation") + public Map> imdgForValidation(ImdgProvider imdgProvider) { + final Map> imdg = new HashMap<>(); + BiConsumer> addImdg = (s, aClass) -> imdg.put(s, imdgProvider.getImdg(s, aClass)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class); + addImdg.accept(IMDGDistributedNames.Map_Company, Company.class); + addImdg.accept(IMDGDistributedNames.Map_Security, Security.class); + return imdg; + } + + @Bean("commonDeleteRequestValidator") + public Function commonDeleteRequestValidator(Map> imdgForValidation) { + return commonDeleteRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(commonDeleteRequest); + return new ValidatorImpl<>(context, + FieldRequiredRule.instance("id", CommonDeleteRequest::getId) + ); + }; + } + +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java index bdc24ed06..861e85337 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java @@ -6,6 +6,7 @@ public enum ValidationError implements IEnumId { WrongDictionaryValue(10003L), EmptyRequiredValue(10002L), WrongEnumValue(777L), //todo set code + WrongUpdate(666L), //todo set code TaskForPastDate(7010L), TaskForPastTime(7011L), CompanyNotFound(7014L), diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java index 4a069ec79..b61905894 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java @@ -18,7 +18,6 @@ import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerUpdateReq import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.clearing.platform.messaging.service.Status; -import ru.spcex.clearing.scheduler.validation.IRequestValidator; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.utils.enumeration.EnumMessage; @@ -26,7 +25,6 @@ import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; -import java.util.List; import java.util.Optional; import java.util.function.Function; @@ -36,20 +34,24 @@ public class PlannerService extends QueueConsumer implements InitializingBean { private final ImdgProvider imdgProvider; private final Imdg plannerMap; private final IMessageResolver messageResolver; - private final Function validationFactory; - private final IRequestValidator plannerUpdateRequest = IRequestValidator.PLANNER_UPDATE_REQUEST; - private final IRequestValidator deleteRequestValidator = IRequestValidator.COMMON_DELETE_REQUEST; + private final Function plannerDeleteRequestValidation; + private final Function plannerNewRequestValidation; + private final Function plannerUpdateRequestValidation; @Autowired public PlannerService(Consumer kafkaQueue, Producer kafkaProducer, ImdgProvider imdgProvider, IMessageResolver messageResolver, - @Qualifier("plannerNewRequestValidator") Function plannerNewRequestValidator) { + @Qualifier("commonDeleteRequestValidator") Function plannerDeleteRequestValidator, + @Qualifier("plannerNewRequestValidator") Function plannerNewRequestValidator, + @Qualifier("plannerUpdateRequestValidator") Function plannerUpdateRequestValidator) { super(kafkaQueue, kafkaProducer); this.plannerMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Planner, Planner.class); this.messageResolver = messageResolver; - this.validationFactory = plannerNewRequestValidator; + this.plannerDeleteRequestValidation = plannerDeleteRequestValidator; + this.plannerNewRequestValidation = plannerNewRequestValidator; + this.plannerUpdateRequestValidation = plannerUpdateRequestValidator; this.imdgProvider = imdgProvider; } @@ -59,26 +61,28 @@ public class PlannerService extends QueueConsumer implements InitializingBean { .setFunction(this::newScheduler) .forDestination(Consts.DESTINATION_PLANNER_NEW, callbacks::put); callback(PlannerUpdateRequest.class) - .setConsumer(this::updateScheduler) + .setFunction(this::updateScheduler) .forDestination(Consts.DESTINATION_PLANNER_UPDATE, callbacks::put); callback(CommonDeleteRequest.class) - .setConsumer(this::deleteScheduler) + .setFunction(this::deleteScheduler) .forDestination(Consts.DESTINATION_PLANNER_DELETE, callbacks::put); init(); } - public RequestInfoUpdate newScheduler(BaseRequest userRequest) { + private RequestInfoUpdate newScheduler(BaseRequest userRequest) { PlannerNewRequest req = userRequest.getRequestPayload(); log.debug("PlannerNewRequest received"); - IValidator validator = validationFactory.apply(req); - Optional validationError = validator.tillFirstError(); - if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process PlannerNewRequest id={}: {}", userRequest.getId(), errorMsg); - return new RequestInfoUpdate() - .setId(userRequest.getId()) - .setStatus(Status.Error) - .setMessage(errorMsg); + if (plannerNewRequestValidation != null) { + IValidator validator = plannerNewRequestValidation.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("cannot process PlannerNewRequest id={}: {}", userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } } Planner planner = new Planner(); planner.setCreated(Instant.now()); @@ -94,11 +98,21 @@ public class PlannerService extends QueueConsumer implements InitializingBean { return null; } - private void updateScheduler(BaseRequest userRequest) { + private RequestInfoUpdate updateScheduler(BaseRequest userRequest) { PlannerUpdateRequest req = userRequest.getRequestPayload(); log.debug("PlannerUpdateRequest received id = {}", req.getId()); - List errors = plannerUpdateRequest.validate(req, imdgProvider); - if (IRequestValidator.checkErrorList(errors, log)) return; + if (plannerUpdateRequestValidation != null) { + IValidator validator = plannerUpdateRequestValidation.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("cannot process PlannerUpdateRequest id={}: {}", userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + } Planner planner = plannerMap.getSingleObjectByID(req.getId()); planner.setUpdated(Instant.now()); planner.setTask(req.getTask()); @@ -109,15 +123,27 @@ public class PlannerService extends QueueConsumer implements InitializingBean { planner.setCompanyId(req.getCompanyId()); planner.setSecurityId(req.getSecurityId()); plannerMap.update(planner); + return null; } - private void deleteScheduler(BaseRequest userRequest) { + private RequestInfoUpdate deleteScheduler(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); log.debug("CommonDeleteRequest received id = {}", req.getId()); - List errors = deleteRequestValidator.validate(req, imdgProvider); - if (IRequestValidator.checkErrorList(errors, log)) return; + if (plannerDeleteRequestValidation != null) { + IValidator validator = plannerDeleteRequestValidation.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("cannot process PlannerUpdateRequest id={}: {}", userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + } Planner planner = plannerMap.getSingleObjectByID(req.getId()); plannerMap.delete(planner); + return null; } } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java index 6cf914e9b..63fc0cfce 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java @@ -6,6 +6,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.scheduler.PlannerTemplate; import ru.spcex.clearing.imdg.IMDGDistributedNames; @@ -15,49 +16,73 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; -import ru.spcex.clearing.scheduler.validation.IRequestValidator; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; +import ru.spcex.clearing.platform.messaging.service.Status; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; -import java.util.List; +import java.util.Optional; +import java.util.function.Function; @Service public class PlannerTemplateService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); private final Imdg plannerTemplateMap; private final ImdgProvider imdgProvider; - private final IRequestValidator plannerTemplateNewRequest = IRequestValidator.PLANNER_TEMPLATE_NEW_REQUEST; - private final IRequestValidator plannerTemplateUpdateRequest = IRequestValidator.PLANNER_TEMPLATE_UPDATE_REQUEST; - private final IRequestValidator deleteRequestValidator = IRequestValidator.COMMON_DELETE_REQUEST; + private final IMessageResolver messageResolver; + private final Function plannerTemplateDeleteRequestValidation; + private final Function plannerTemplateNewRequestValidation; + private final Function plannerTemplateUpdateRequestValidation; @Autowired public PlannerTemplateService(Consumer kafkaQueue, Producer kafkaProducer, - ImdgProvider imdgProvider) { + ImdgProvider imdgProvider, + IMessageResolver messageResolver, + @Qualifier("commonDeleteRequestValidator") Function plannerTemplateDeleteRequestValidator, + @Qualifier("plannerTemplateNewRequestValidator") Function plannerTemplateNewRequestValidator, + @Qualifier("plannerTemplateUpdateRequestValidator") Function plannerTemplateUpdateRequestValidator) { super(kafkaQueue, kafkaProducer); this.plannerTemplateMap = imdgProvider.getImdg(IMDGDistributedNames.Map_PlannerTemplate, PlannerTemplate.class); this.imdgProvider = imdgProvider; + this.plannerTemplateDeleteRequestValidation = plannerTemplateDeleteRequestValidator; + this.plannerTemplateNewRequestValidation = plannerTemplateNewRequestValidator; + this.plannerTemplateUpdateRequestValidation = plannerTemplateUpdateRequestValidator; + this.messageResolver = messageResolver; } @Override public void afterPropertiesSet() { callback(PlannerTemplateNewRequest.class) - .setConsumer(this::newTimetable) + .setFunction(this::newTimetable) .forDestination(Consts.DESTINATION_PLANNER_TEMPLATE_NEW, callbacks::put); callback(PlannerTemplateUpdateRequest.class) - .setConsumer(this::updateTimetable) + .setFunction(this::updateTimetable) .forDestination(Consts.DESTINATION_PLANNER_TEMPLATE_UPDATE, callbacks::put); callback(CommonDeleteRequest.class) - .setConsumer(this::deleteTimetable) + .setFunction(this::deleteTimetable) .forDestination(Consts.DESTINATION_PLANNER_TEMPLATE_DELETE, callbacks::put); init(); } - private void newTimetable(BaseRequest userRequest) { + private RequestInfoUpdate newTimetable(BaseRequest userRequest) { PlannerTemplateNewRequest req = userRequest.getRequestPayload(); log.debug("PlannerTemplateNewRequest received"); - List errors = plannerTemplateNewRequest.validate(req, imdgProvider); - if (IRequestValidator.checkErrorList(errors, log)) return; + if (plannerTemplateNewRequestValidation != null) { + IValidator validator = plannerTemplateNewRequestValidation.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("cannot process PlannerTemplateNewRequest id={}: {}", userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + } PlannerTemplate plannerTemplate = new PlannerTemplate(); Instant created = Instant.now(); plannerTemplate.setCreated(created); @@ -68,14 +93,25 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin plannerTemplate.setSecurityId(req.getSecurityId()); plannerTemplateMap.insert(plannerTemplate); log.debug("successfully processed, new id {}", plannerTemplate.getId()); + return null; } - private void updateTimetable(BaseRequest userRequest) { + private RequestInfoUpdate updateTimetable(BaseRequest userRequest) { PlannerTemplateUpdateRequest req = userRequest.getRequestPayload(); log.debug("PlannerTemplateUpdateRequest received"); + if (plannerTemplateUpdateRequestValidation != null) { + IValidator validator = plannerTemplateUpdateRequestValidation.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("cannot process PlannerNewRequest id={}: {}", userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + } PlannerTemplate plannerTemplate = plannerTemplateMap.getSingleObjectByID(req.getId()); - List errors = plannerTemplateUpdateRequest.validate(req, imdgProvider); - if (IRequestValidator.checkErrorList(errors, log)) return; Instant updated = Instant.now(); plannerTemplate.setUpdated(updated); plannerTemplate.setTask(req.getTask()); @@ -85,14 +121,26 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin plannerTemplate.setSecurityId(req.getSecurityId()); plannerTemplateMap.update(plannerTemplate); log.debug("successfully processed, new id {}", plannerTemplate.getId()); + return null; } - private void deleteTimetable(BaseRequest userRequest) { + private RequestInfoUpdate deleteTimetable(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); log.debug("CommonDeleteRequest received id = {}", req.getId()); - List errors = deleteRequestValidator.validate(req, imdgProvider); - if (IRequestValidator.checkErrorList(errors, log)) return; + if (plannerTemplateDeleteRequestValidation != null) { + IValidator validator = plannerTemplateDeleteRequestValidation.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("cannot process PlannerUpdateRequest id={}: {}", userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + } PlannerTemplate plannerTemplate = plannerTemplateMap.getSingleObjectByID(req.getId()); plannerTemplateMap.delete(plannerTemplate); + return null; } } diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/config/HazelcastServiceTestConfiguration.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/config/HazelcastServiceTestConfiguration.java index af55150d0..48b9644d4 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/config/HazelcastServiceTestConfiguration.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/config/HazelcastServiceTestConfiguration.java @@ -10,6 +10,8 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.enumeration.SimpleMessageResolver; import java.util.List; import java.util.Random; @@ -65,4 +67,9 @@ public class HazelcastServiceTestConfiguration { params.setNearCacheConfig(new NearCacheConfig()); return params; } + + @Bean + public IMessageResolver messageResolver() { + return new SimpleMessageResolver(); + } } diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java index ff5ac8109..c9bac35d7 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java @@ -26,6 +26,7 @@ import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateNewRequest; import ru.spcex.clearing.scheduler.service.PlannerTemplateService; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; import java.time.Instant; @@ -47,6 +48,7 @@ class PlannerTemplateServiceTest { private HazelcastService hazelcastServiceTest; private MockConsumer mockConsumer; private MockProducer mockProducer; + private IMessageResolver messageResolver; @BeforeEach void setUp() { @@ -91,7 +93,7 @@ class PlannerTemplateServiceTest { //ACT //service set up - PlannerTemplateService plannerTemplateService = new PlannerTemplateService(mockConsumer, mockProducer, hazelcastServiceTest); + PlannerTemplateService plannerTemplateService = new PlannerTemplateService(mockConsumer, mockProducer, hazelcastServiceTest, messageResolver, null, null, null); //callbacks set up plannerTemplateService.afterPropertiesSet(); From ff8dd10f52b602ed18c3d4510798bc77494cc76e Mon Sep 17 00:00:00 2001 From: akulikov Date: Tue, 17 Jan 2023 17:54:08 +0300 Subject: [PATCH 09/14] ClearingCalendarValidation --- .../ClearingCalendarValidationConfig.java | 100 +++++++ .../PlannerTemplateValidationConfig.java | 19 +- .../validation/PlannerValidationConfig.java | 18 +- .../config/validation/ValidationConfig.java | 14 +- .../scheduler/error/ValidationError.java | 2 +- .../service/ClearingCalendarService.java | 97 ++++--- .../scheduler/service/NewRequestResult.java | 12 - .../scheduler/service/PlannerService.java | 4 +- .../service/PlannerTemplateService.java | 8 +- .../validation/IRequestValidator.java | 247 ------------------ 10 files changed, 217 insertions(+), 304 deletions(-) create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ClearingCalendarValidationConfig.java delete mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/NewRequestResult.java delete mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ClearingCalendarValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ClearingCalendarValidationConfig.java new file mode 100644 index 000000000..c16595d10 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ClearingCalendarValidationConfig.java @@ -0,0 +1,100 @@ +package ru.spcex.clearing.scheduler.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.scheduler.ClearingCalendar; +import ru.clearing.platform.dictionary.DayStatusDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarUpdateRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.DateNotBeforeRule; +import ru.spcex.clearing.scheduler.validation.rules.common.DictionaryPresentRule; +import ru.spcex.clearing.scheduler.validation.rules.common.IdPresentRule; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; + +@Configuration +public class ClearingCalendarValidationConfig { + + @Bean("clearingCalendarNewRequestValidator") + public Function clearingCalendarNewRequestValidator(Map> imdgForValidation) { + return clearingCalendarNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(clearingCalendarNewRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_DayStatusDictionary); + return new ValidatorImpl<>(context, + DateNotBeforeRule.instance("clearingDate", + ClearingCalendarNewRequest::getClearingDate), + IdPresentRule.instance("companyId", + ClearingCalendarNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + DictionaryPresentRule.instance("dayStatus", + ClearingCalendarNewRequest::getDayStatus, + IMDGDistributedNames.Map_DayStatusDictionary, + DayStatusDictionary.class) + ); + }; + } + + @Bean("clearingCalendarUpdateRequestValidator") + public Function clearingCalendarUpdateRequestValidator(Map> imdgForValidation) { + return clearingCalendarUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(clearingCalendarUpdateRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_DayStatusDictionary); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + ClearingCalendarUpdateRequest::getId, + IMDGDistributedNames.Map_ClearingCalendar, + ClearingCalendar.class, + ValidationError.RecordNotFound), + DateNotBeforeRule.instance("clearingDate", + ClearingCalendarUpdateRequest::getClearingDate), + IdPresentRule.instance("companyId", + ClearingCalendarUpdateRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + DictionaryPresentRule.instance("dayStatus", + ClearingCalendarUpdateRequest::getDayStatus, + IMDGDistributedNames.Map_DayStatusDictionary, + DayStatusDictionary.class) + ); + }; + } + + @Bean("clearingCalendarDeleteRequestValidator") + public Function clearingCalendarDeleteRequestValidator() { + return clearingCalendarDeleteRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(clearingCalendarDeleteRequest); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_ClearingCalendar, + ClearingCalendar.class, + ValidationError.RecordNotFound) + ); + }; + } + +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java index efb0b64ad..56c9f706f 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java @@ -8,6 +8,7 @@ import ru.clearing.classes.statics.data.security.Security; import ru.clearing.platform.dictionary.TaskDictionary; import ru.clearing.platform.dictionary.TaskStatusDictionary; import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateUpdateRequest; import ru.spcex.clearing.scheduler.error.ValidationError; @@ -80,7 +81,7 @@ public class PlannerTemplateValidationConfig { PlannerTemplateUpdateRequest::getId, IMDGDistributedNames.Map_PlannerTemplate, PlannerTemplate.class, - ValidationError.WrongUpdate), + ValidationError.RecordNotFound), DictionaryPresentRule.instance("task", PlannerTemplateNewRequest::getTask, IMDGDistributedNames.Map_TaskDictionary, @@ -112,4 +113,20 @@ public class PlannerTemplateValidationConfig { }; } + + @Bean("plannerTemplateDeleteRequestValidator") + public Function plannerTemplateDeleteRequestValidator() { + return plannerTemplateDeleteRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerTemplateDeleteRequest); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_PlannerTemplate, + PlannerTemplate.class, + ValidationError.RecordNotFound) + ); + }; + } + } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java index 7c8963650..16a4e8501 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java @@ -8,6 +8,7 @@ import ru.clearing.classes.statics.data.security.Security; import ru.clearing.platform.dictionary.TaskDictionary; import ru.clearing.platform.dictionary.TaskStatusDictionary; import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerUpdateRequest; import ru.spcex.clearing.scheduler.error.ValidationError; @@ -85,7 +86,7 @@ public class PlannerValidationConfig { PlannerUpdateRequest::getId, IMDGDistributedNames.Map_Planner, Planner.class, - ValidationError.WrongUpdate), + ValidationError.RecordNotFound), DictionaryPresentRule.instance("task", PlannerUpdateRequest::getTask, IMDGDistributedNames.Map_TaskDictionary, @@ -124,4 +125,19 @@ public class PlannerValidationConfig { }; } + @Bean("plannerDeleteRequestValidator") + public Function plannerDeleteRequestValidator() { + return plannerDeleteRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerDeleteRequest); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_Planner, + Planner.class, + ValidationError.RecordNotFound) + ); + }; + } + } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java index e4b471c69..aa06719a5 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java @@ -3,12 +3,15 @@ package ru.spcex.clearing.scheduler.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.scheduler.ClearingCalendar; import ru.clearing.classes.statics.data.security.Security; +import ru.clearing.platform.dictionary.DayStatusDictionary; import ru.clearing.platform.dictionary.TaskDictionary; import ru.clearing.platform.dictionary.TaskStatusDictionary; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; -import ru.spcex.clearing.scheduler.validation.rules.common.FieldRequiredRule; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.IdPresentRule; import ru.spcex.platform.classes.base.SpcexObjectBase; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; @@ -32,16 +35,21 @@ public class ValidationConfig { addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class); addImdg.accept(IMDGDistributedNames.Map_Company, Company.class); addImdg.accept(IMDGDistributedNames.Map_Security, Security.class); + addImdg.accept(IMDGDistributedNames.Map_DayStatusDictionary, DayStatusDictionary.class); return imdg; } @Bean("commonDeleteRequestValidator") - public Function commonDeleteRequestValidator(Map> imdgForValidation) { + public Function commonDeleteRequestValidator() { return commonDeleteRequest -> { ImdgValidationContext context = new ImdgValidationContext<>(); context.setValidatedObject(commonDeleteRequest); return new ValidatorImpl<>(context, - FieldRequiredRule.instance("id", CommonDeleteRequest::getId) + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_ClearingCalendar, + ClearingCalendar.class, + ValidationError.RecordNotFound) ); }; } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java index 861e85337..a0483da4d 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java @@ -6,7 +6,7 @@ public enum ValidationError implements IEnumId { WrongDictionaryValue(10003L), EmptyRequiredValue(10002L), WrongEnumValue(777L), //todo set code - WrongUpdate(666L), //todo set code + RecordNotFound(7006L), TaskForPastDate(7010L), TaskForPastTime(7011L), CompanyNotFound(7014L), diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java index 8131a9626..1f65dd20c 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java @@ -6,6 +6,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.scheduler.ClearingCalendar; import ru.spcex.clearing.imdg.IMDGDistributedNames; @@ -15,50 +16,71 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; -import ru.spcex.clearing.scheduler.validation.IRequestValidator; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; +import ru.spcex.clearing.platform.messaging.service.Status; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; -import java.util.List; -import java.util.stream.Collectors; +import java.util.Optional; +import java.util.function.Function; @Service public class ClearingCalendarService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); - private final ImdgProvider imdgProvider; private final Imdg clearingCalendarMap; - private final IRequestValidator newRequestValidator = IRequestValidator.CLEARING_CALENDAR_NEW_REQUEST; - private final IRequestValidator updateRequestValidator = IRequestValidator.CLEARING_CALENDAR_UPDATE_REQUEST; - private final IRequestValidator deleteRequestValidator = IRequestValidator.COMMON_DELETE_REQUEST; + private final IMessageResolver messageResolver; + private final Function clearingCalendarDeleteRequestValidation; + private final Function clearingCalendarNewRequestValidation; + private final Function clearingCalendarUpdateRequestValidation; @Autowired public ClearingCalendarService(Consumer kafkaQueue, Producer kafkaProducer, - ImdgProvider imdgProvider) { + ImdgProvider imdgProvider, + IMessageResolver messageResolver, + @Qualifier("clearingCalendarDeleteRequestValidator") Function clearingCalendarDeleteRequestValidator, + @Qualifier("clearingCalendarNewRequestValidator") Function clearingCalendarNewRequestValidator, + @Qualifier("clearingCalendarUpdateRequestValidator") Function clearingCalendarUpdateRequestValidator) { super(kafkaQueue, kafkaProducer); this.clearingCalendarMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingCalendar, ClearingCalendar.class); - this.imdgProvider = imdgProvider; + this.clearingCalendarDeleteRequestValidation = clearingCalendarDeleteRequestValidator; + this.clearingCalendarNewRequestValidation = clearingCalendarNewRequestValidator; + this.clearingCalendarUpdateRequestValidation = clearingCalendarUpdateRequestValidator; + this.messageResolver = messageResolver; } @Override public void afterPropertiesSet() { callback(ClearingCalendarNewRequest.class) - .setConsumer(this::newClearingCalendar) + .setFunction(this::newClearingCalendar) .forDestination(Consts.DESTINATION_CLEARING_CALENDAR_NEW, callbacks::put); callback(ClearingCalendarUpdateRequest.class) - .setConsumer(this::updateClearingCalendar) + .setFunction(this::updateClearingCalendar) .forDestination(Consts.DESTINATION_CLEARING_CALENDAR_UPDATE, callbacks::put); callback(CommonDeleteRequest.class) - .setConsumer(this::deleteClearingCalendar) + .setFunction(this::deleteClearingCalendar) .forDestination(Consts.DESTINATION_CLEARING_CALENDAR_DELETE, callbacks::put); init(); } - private void newClearingCalendar(BaseRequest userRequest) { + private RequestInfoUpdate newClearingCalendar(BaseRequest userRequest) { ClearingCalendarNewRequest req = userRequest.getRequestPayload(); log.debug("ClearingCalendarNewRequest received"); - List errors = newRequestValidator.validate(req, imdgProvider); - if (IRequestValidator.checkErrorList(errors, log)) return; + if (clearingCalendarNewRequestValidation != null) { + IValidator validator = clearingCalendarNewRequestValidation.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("cannot process ClearingCalendarNewRequest id={}: {}", userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + } ClearingCalendar clearingCalendar = new ClearingCalendar(); Instant created = Instant.now(); clearingCalendar.setCreated(created); @@ -67,13 +89,24 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi clearingCalendar.setDayStatus(req.getDayStatus()); clearingCalendarMap.insert(clearingCalendar); log.debug("successfully processed, new id {}", clearingCalendar.getId()); + return null; } - private void updateClearingCalendar(BaseRequest userRequest) { + private RequestInfoUpdate updateClearingCalendar(BaseRequest userRequest) { ClearingCalendarUpdateRequest req = userRequest.getRequestPayload(); log.debug("ClearingCalendarUpdateRequest received"); - List errors = updateRequestValidator.validate(req, imdgProvider); - if (IRequestValidator.checkErrorList(errors, log)) return; + if (clearingCalendarUpdateRequestValidation != null) { + IValidator validator = clearingCalendarUpdateRequestValidation.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("cannot process ClearingCalendarUpdateRequest id={}: {}", userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + } Instant updated = Instant.now(); ClearingCalendar clearingCalendar = clearingCalendarMap.getSingleObjectByID(req.getId()); clearingCalendar.setClearingDate(req.getClearingDate()); @@ -82,24 +115,26 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi clearingCalendar.setUpdated(updated); clearingCalendarMap.update(clearingCalendar); log.debug("successfully processed, new id {}", clearingCalendar.getId()); + return null; } - private void deleteClearingCalendar(BaseRequest userRequest) { + private RequestInfoUpdate deleteClearingCalendar(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); - List errors = deleteRequestValidator.validate(req, imdgProvider); - if (IRequestValidator.checkErrorList(errors, log)) return; + if (clearingCalendarDeleteRequestValidation != null) { + IValidator validator = clearingCalendarDeleteRequestValidation.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("cannot process CommonDeleteRequest id={}: {}", userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + } log.debug("CommonDeleteRequest received id = {}", req.getId()); ClearingCalendar clearingCalendar = clearingCalendarMap.getSingleObjectByID(req.getId()); clearingCalendarMap.delete(clearingCalendar); - } - - static boolean checkErrors(List errors, Logger log) { - if (!errors.isEmpty()) { - log.error("Validation error: [{}]", - errors.stream().map(IRequestValidator.ValidationError::toString).collect(Collectors.joining(", ")) - ); - return true; - } - return false; + return null; } } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/NewRequestResult.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/NewRequestResult.java deleted file mode 100644 index 282be46cd..000000000 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/NewRequestResult.java +++ /dev/null @@ -1,12 +0,0 @@ -package ru.spcex.clearing.scheduler.service; - -import ru.spcex.platform.utils.enumeration.EnumMessage; - -public class NewRequestResult { - private EnumMessage error; - - public NewRequestResult(EnumMessage validationError) { - this.error = validationError; - } - -} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java index b61905894..9d1ee12d4 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java @@ -31,7 +31,6 @@ import java.util.function.Function; @Service public class PlannerService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); - private final ImdgProvider imdgProvider; private final Imdg plannerMap; private final IMessageResolver messageResolver; private final Function plannerDeleteRequestValidation; @@ -43,7 +42,7 @@ public class PlannerService extends QueueConsumer implements InitializingBean { Producer kafkaProducer, ImdgProvider imdgProvider, IMessageResolver messageResolver, - @Qualifier("commonDeleteRequestValidator") Function plannerDeleteRequestValidator, + @Qualifier("plannerDeleteRequestValidator") Function plannerDeleteRequestValidator, @Qualifier("plannerNewRequestValidator") Function plannerNewRequestValidator, @Qualifier("plannerUpdateRequestValidator") Function plannerUpdateRequestValidator) { super(kafkaQueue, kafkaProducer); @@ -52,7 +51,6 @@ public class PlannerService extends QueueConsumer implements InitializingBean { this.plannerDeleteRequestValidation = plannerDeleteRequestValidator; this.plannerNewRequestValidation = plannerNewRequestValidator; this.plannerUpdateRequestValidation = plannerUpdateRequestValidator; - this.imdgProvider = imdgProvider; } @Override diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java index 63fc0cfce..97873e004 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java @@ -32,7 +32,6 @@ import java.util.function.Function; public class PlannerTemplateService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); private final Imdg plannerTemplateMap; - private final ImdgProvider imdgProvider; private final IMessageResolver messageResolver; private final Function plannerTemplateDeleteRequestValidation; private final Function plannerTemplateNewRequestValidation; @@ -42,12 +41,11 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin public PlannerTemplateService(Consumer kafkaQueue, Producer kafkaProducer, ImdgProvider imdgProvider, IMessageResolver messageResolver, - @Qualifier("commonDeleteRequestValidator") Function plannerTemplateDeleteRequestValidator, + @Qualifier("plannerTemplateDeleteRequestValidator") Function plannerTemplateDeleteRequestValidator, @Qualifier("plannerTemplateNewRequestValidator") Function plannerTemplateNewRequestValidator, @Qualifier("plannerTemplateUpdateRequestValidator") Function plannerTemplateUpdateRequestValidator) { super(kafkaQueue, kafkaProducer); this.plannerTemplateMap = imdgProvider.getImdg(IMDGDistributedNames.Map_PlannerTemplate, PlannerTemplate.class); - this.imdgProvider = imdgProvider; this.plannerTemplateDeleteRequestValidation = plannerTemplateDeleteRequestValidator; this.plannerTemplateNewRequestValidation = plannerTemplateNewRequestValidator; this.plannerTemplateUpdateRequestValidation = plannerTemplateUpdateRequestValidator; @@ -104,7 +102,7 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin Optional validationError = validator.tillFirstError(); if (validationError.isPresent()) { String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process PlannerNewRequest id={}: {}", userRequest.getId(), errorMsg); + log.error("cannot process PlannerTemplateNewRequest id={}: {}", userRequest.getId(), errorMsg); return new RequestInfoUpdate() .setId(userRequest.getId()) .setStatus(Status.Error) @@ -132,7 +130,7 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin Optional validationError = validator.tillFirstError(); if (validationError.isPresent()) { String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process PlannerUpdateRequest id={}: {}", userRequest.getId(), errorMsg); + log.error("cannot process PlannerTemplateUpdateRequest id={}: {}", userRequest.getId(), errorMsg); return new RequestInfoUpdate() .setId(userRequest.getId()) .setStatus(Status.Error) diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java deleted file mode 100644 index baaee072d..000000000 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/IRequestValidator.java +++ /dev/null @@ -1,247 +0,0 @@ -package ru.spcex.clearing.scheduler.validation; - -import org.slf4j.Logger; -import ru.clearing.platform.dictionary.AbstractDictionary; -import ru.clearing.platform.dictionary.DayStatusDictionary; -import ru.clearing.platform.dictionary.TaskDictionary; -import ru.clearing.platform.dictionary.TaskStatusDictionary; -import ru.spcex.clearing.imdg.IMDGDistributedNames; -import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.schedule.*; -import ru.spcex.platform.enumeration.Market; -import ru.spcex.platform.imdg.api.Imdg; -import ru.spcex.platform.imdg.api.ImdgProvider; -import ru.spcex.platform.utils.enumeration.IEnumKey; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - -public interface IRequestValidator { - List validate(T req, ImdgProvider imdgProvider); - - /** - * Общий запрос на удаление - */ - IRequestValidator COMMON_DELETE_REQUEST = (req, imdgProvider) -> { - var errors = new LinkedList(); - validateLong(req.id, "id", true, errors); - return errors; - }; - - /** - * Запрос на добавление ClearingCalendar - */ - IRequestValidator CLEARING_CALENDAR_NEW_REQUEST = (req, imdgProvider) -> { - var errors = new LinkedList(); - validateDate(req.clearingDate, "clearingDate", true, true, errors); - validateLong(req.companyId, "companyId", false, errors); -// validateEnum(req.dayStatus, "dayStatus", true, errors, DayStatus.values()); - validateDictionary(req.dayStatus, - "dayStatus", - true, - imdgProvider.getImdg(IMDGDistributedNames.Map_DayStatusDictionary, DayStatusDictionary.class), - errors); - return errors; - }; - - /** - * Запрос на обновление ClearingCalendar - */ - IRequestValidator CLEARING_CALENDAR_UPDATE_REQUEST = (req, imdgProvider) -> { - var errors = new LinkedList(); - validateLong(req.id, "id", true, errors); - validateLong(req.companyId, "companyId", false, errors); - validateDate(req.clearingDate, "clearingDate", false, true, errors); -// validateEnum(req.dayStatus, "dayStatus", false, errors, DayStatus.values()); - validateDictionary(req.dayStatus, - "dayStatus", - false, - imdgProvider.getImdg(IMDGDistributedNames.Map_DayStatusDictionary, DayStatusDictionary.class), - errors); - return errors; - }; - - /** - * Запрос на добавление Planner - */ - IRequestValidator PLANNER_NEW_REQUEST = (req, imdgProvider) -> { - var errors = new LinkedList(); -// validateEnum(req.task, "task", true, errors, Task.values()); - validateDictionary(req.task, - "task", - true, - imdgProvider.getImdg(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class), - errors); - validateDate(req.clearingDate, "clearingDate", true, true, errors); - validateTime(req.taskTime, "taskTime", true, true, errors); - validateEnum(req.market, "market", false, errors, Market.values()); -// validateEnum(req.taskStatus, "taskStatus", true, errors, Status.values()); - validateDictionary(req.taskStatus, - "taskStatus", - true, - imdgProvider.getImdg(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class), - errors); - validateLong(req.companyId, "companyId", false, errors); - validateLong(req.securityId, "securityId", false, errors); - return errors; - }; - - /** - * Запрос на обновление Planner - */ - IRequestValidator PLANNER_UPDATE_REQUEST = (req, imdgProvider) -> { - var errors = new LinkedList(); - validateLong(req.id, "id", true, errors); -// validateEnum(req.task, "task", false, errors, Task.values()); - validateDictionary(req.task, - "task", - false, - imdgProvider.getImdg(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class), - errors); - validateDate(req.clearingDate, "clearingDate", false, true, errors); - validateTime(req.taskTime, "taskTime", false, true, errors); - validateEnum(req.market, "market", false, errors, Market.values()); -// validateEnum(req.taskStatus, "taskStatus", false, errors, Status.values()); - validateDictionary(req.taskStatus, - "taskStatus", - false, - imdgProvider.getImdg(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class), - errors); - validateLong(req.companyId, "companyId", false, errors); - validateLong(req.securityId, "securityId", false, errors); - return errors; - }; - - /** - * Запрос на добавление PlannerTemplate - */ - IRequestValidator PLANNER_TEMPLATE_NEW_REQUEST = (req, imdgProvider) -> { - var errors = new LinkedList(); -// validateEnum(req.task, "task", true, errors, Task.values()); - validateDictionary(req.task, - "task", - true, - imdgProvider.getImdg(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class), - errors); - validateTime(req.taskTime, "taskTime", true, true, errors); -// validateEnum(req.taskStatus, "taskStatus", true, errors, Status.values()); - validateDictionary(req.taskStatus, - "taskStatus", - true, - imdgProvider.getImdg(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class), - errors); - validateLong(req.companyId, "companyId", false, errors); - validateLong(req.securityId, "securityId", false, errors); - return errors; - }; - - /** - * Запрос на обновление PlannerTemplate - */ - IRequestValidator PLANNER_TEMPLATE_UPDATE_REQUEST = (req, imdgProvider) -> { - var errors = new LinkedList(); - validateLong(req.id, "id", true, errors); -// validateEnum(req.task, "task", false, errors, Task.values()); - validateDictionary(req.task, - "task", - false, - imdgProvider.getImdg(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class), - errors); - validateTime(req.taskTime, "taskTime", false, true, errors); -// validateEnum(req.taskStatus, "taskStatus", false, errors, Status.values()); - validateDictionary(req.taskStatus, - "taskStatus", - false, - imdgProvider.getImdg(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class), - errors); - validateLong(req.companyId, "companyId", false, errors); - validateLong(req.securityId, "securityId", false, errors); - return errors; - }; - - - - static void validateDictionary(String src, - String fieldName, - boolean required, - Imdg dictionary, - List errors) { - if (src != null) { - boolean correctTask = false; - Collection values = dictionary.getAllValues(); - for (T value : values) correctTask |= src.equalsIgnoreCase(value.getCode()); - if (!correctTask) - errors.add(new ValidationError(fieldName, ErrorType.UNKNOWN_VALUE)); - } else if (required) errors.add(new ValidationError(fieldName, ErrorType.MISSING_REQUIRED)); - } - - static & IEnumKey> void validateEnum(String enumStr, - String fieldName, - boolean required, - List errors, - T... enumSet) { - if (enumStr != null) { - boolean correctTask = IEnumKey.contains(enumStr, enumSet); - if (!correctTask) - errors.add(new ValidationError(fieldName, ErrorType.UNKNOWN_VALUE)); - } else if (required) errors.add(new ValidationError(fieldName, ErrorType.MISSING_REQUIRED)); - } - - static void validateLong(Long value, String fieldName, boolean required, List errors) { - if (value != null) { - if (value < 0 || value == Long.MAX_VALUE) - errors.add(new ValidationError(fieldName, ErrorType.INVALID_VALUE)); - } else if (required) errors.add(new ValidationError(fieldName, ErrorType.MISSING_REQUIRED)); - } - - static void validateDate(LocalDate value, - String fieldName, - boolean required, - boolean checkDate, - List errors) { - if (value != null) { - if (checkDate && (value.isBefore(LocalDate.now()))) - errors.add(new ValidationError(fieldName, ErrorType.INVALID_VALUE)); - } else if (required) errors.add(new ValidationError(fieldName, ErrorType.MISSING_REQUIRED)); - } - - static void validateTime(LocalTime value, - String fieldName, - boolean required, - boolean checkDate, - List errors) { - if (value != null) { - if (checkDate && (value.isBefore(LocalTime.now()))) - errors.add(new ValidationError(fieldName, ErrorType.INVALID_VALUE)); - } else if (required) errors.add(new ValidationError(fieldName, ErrorType.MISSING_REQUIRED)); - } - - /** - * Временный метод - */ - static boolean checkErrorList(List errors, Logger log) { - if (!errors.isEmpty()) { - log.error("Validation idNotPresentError: [{}]", - errors.stream().map(IRequestValidator.ValidationError::toString).collect(Collectors.joining(", ")) - ); - return true; - } - return false; - } - - enum ErrorType { - MISSING_REQUIRED, UNKNOWN_VALUE, INVALID_VALUE - } - - record ValidationError(String fieldName, ErrorType errorType) { - @Override - public String toString() { - return "%s: %s".formatted(fieldName, errorType); - } - } - -} From 84083be396503d7311043227a09bab03efa4f42b Mon Sep 17 00:00:00 2001 From: akulikov Date: Wed, 18 Jan 2023 12:59:47 +0300 Subject: [PATCH 10/14] refactor and docs --- .../config/validation/ValidationConfig.java | 23 ------------------- .../rules/common/DateNotBeforeRule.java | 15 ++++++++++++ .../rules/common/DictionaryPresentRule.java | 22 ++++++++++++++++++ .../rules/common/EnumPresentRule.java | 20 ++++++++++++++++ .../rules/common/FieldRequiredRule.java | 11 +++++++++ .../rules/common/IdPresentRule.java | 16 +++++++++++++ .../rules/common/TimeNotBeforeRule.java | 15 ++++++++++++ 7 files changed, 99 insertions(+), 23 deletions(-) diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java index aa06719a5..d12745c9e 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java @@ -3,26 +3,18 @@ package ru.spcex.clearing.scheduler.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.scheduler.ClearingCalendar; import ru.clearing.classes.statics.data.security.Security; import ru.clearing.platform.dictionary.DayStatusDictionary; import ru.clearing.platform.dictionary.TaskDictionary; import ru.clearing.platform.dictionary.TaskStatusDictionary; import ru.spcex.clearing.imdg.IMDGDistributedNames; -import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; -import ru.spcex.clearing.scheduler.error.ValidationError; -import ru.spcex.clearing.scheduler.validation.rules.common.IdPresentRule; import ru.spcex.platform.classes.base.SpcexObjectBase; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; -import ru.spcex.platform.imdg.validation.ImdgValidationContext; -import ru.spcex.platform.utils.validation.IValidator; -import ru.spcex.platform.utils.validation.ValidatorImpl; import java.util.HashMap; import java.util.Map; import java.util.function.BiConsumer; -import java.util.function.Function; @Configuration public class ValidationConfig { @@ -39,19 +31,4 @@ public class ValidationConfig { return imdg; } - @Bean("commonDeleteRequestValidator") - public Function commonDeleteRequestValidator() { - return commonDeleteRequest -> { - ImdgValidationContext context = new ImdgValidationContext<>(); - context.setValidatedObject(commonDeleteRequest); - return new ValidatorImpl<>(context, - IdPresentRule.instance("id", - CommonDeleteRequest::getId, - IMDGDistributedNames.Map_ClearingCalendar, - ClearingCalendar.class, - ValidationError.RecordNotFound) - ); - }; - } - } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java index aaa94d43e..b1df393c6 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java @@ -9,12 +9,27 @@ import java.time.LocalDate; import java.util.Optional; import java.util.function.Function; +/** + * Проверка поля с LocalDate. Условие проверки: поверяемая дата >= текущая дата + * @param Класс проверяемого объекта + */ public record DateNotBeforeRule(String fieldName, Function getter, boolean required) implements IValidationRule> { + /** + * @param fieldName Название поля класса, используется для передачи ошибки + * @param getter Метод получения проверяемой даты + * @param required Флаг обязательности поля + * @param Класс проверяемого объекта + */ public static DateNotBeforeRule instance(String fieldName, Function getter, boolean required) { return new DateNotBeforeRule<>(fieldName, getter, required); } + /** + * @param fieldName Название поля класса, используется для передачи ошибки + * @param getter Метод получения проверяемой даты + * @param Класс проверяемого объекта + */ public static DateNotBeforeRule instance(String fieldName, Function getter) { return new DateNotBeforeRule<>(fieldName, getter, true); } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java index 68301c308..351b9bc03 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java @@ -11,12 +11,26 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; +/** + * Проверка поля с кодом из словаря (таблицы *_dictionary) + * @param Класс проверяемого объекта + * @param Класс словаря + */ public record DictionaryPresentRule(String fieldName, Function getter, String dictionaryName, Class dictionaryClass, boolean required) implements IValidationRule> { + /** + * @param fieldName Название поля + * @param getter Метод получения проверяемого значения + * @param dictionaryName Название словаря (см. IMDGDistributedNames) + * @param dictionaryClass Класс словаря (классы *Dictionary.class) + * @param required Флаг обязательности + * @param Класс проверяемого объекта + * @param Класс словаря + */ public static DictionaryPresentRule instance(String fieldName, Function getter, String dictionaryName, @@ -25,6 +39,14 @@ public record DictionaryPresentRule(String fiel return new DictionaryPresentRule<>(fieldName, getter, dictionaryName, dictionaryClass, required); } + /** + * @param fieldName Название поля + * @param getter Метод получения проверяемого значения + * @param dictionaryName Название словаря (см. IMDGDistributedNames) + * @param dictionaryClass Класс словаря (классы *Dictionary.class) + * @param Класс проверяемого объекта + * @param Класс словаря + */ public static DictionaryPresentRule instance(String fieldName, Function getter, String dictionaryName, diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java index 6a1cf9e58..a8ab3cd4f 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java @@ -9,11 +9,24 @@ import ru.spcex.platform.utils.validation.IValidationRule; import java.util.Optional; import java.util.function.Function; +/** + * Проверка поля со значением из множества (enum) + * @param Класс проверяемого объекта + * @param Enum + */ public record EnumPresentRule(String fieldName, Function getter, E[] enumValues, boolean required) implements IValidationRule> { + /** + * @param fieldName Название поля + * @param getter Метод получения проверяемого значения + * @param enumValues Значения из проверяемого множества (Enum.values()) + * @param required Флаг обязательности + * @param Класс проверяемого объекта + * @param Enum + */ public static EnumPresentRule instance(String fieldName, Function getter, E[] enumValues, @@ -21,6 +34,13 @@ public record EnumPresentRule(String fieldName, return new EnumPresentRule<>(fieldName, getter, enumValues, required); } + /** + * @param fieldName Название поля + * @param getter Метод получения проверяемого значения + * @param enumValues Значения из проверяемого множества (Enum.values()) + * @param Класс проверяемого объекта + * @param Enum + */ public static EnumPresentRule instance(String fieldName, Function getter, E[] enumValues) { diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/FieldRequiredRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/FieldRequiredRule.java index 80c3e5600..4abc90b45 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/FieldRequiredRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/FieldRequiredRule.java @@ -8,8 +8,19 @@ import ru.spcex.platform.utils.validation.IValidationRule; import java.util.Optional; import java.util.function.Function; +/** + * Проверка обязательности поля (not null) + * @param Класс проверяемого объекта + * @param Класс проверяемого значения + */ public record FieldRequiredRule(String fieldName, Function getter) implements IValidationRule> { + /** + * @param fieldName Название поля + * @param getter Метод получения значения + * @param Класс проверяемого объекта + * @param Класс проверяемого значения + */ public static FieldRequiredRule instance(String fieldName, Function getter) { return new FieldRequiredRule<>(fieldName, getter); } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java index dd71412e0..ce91ee7d2 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java @@ -11,6 +11,11 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; +/** + * Проверка наличия связанного по Id объекта в базе + * @param Класс проверяемого объекта + * @param Класс связанного объекта + */ public record IdPresentRule( String fieldName, Function idGetter, @@ -21,6 +26,17 @@ public record IdPresentRule( boolean required ) implements IValidationRule> { + /** + * @param fieldName Название поля, содержащего Id + * @param idGetter Метод получения Id + * @param mapName Название мапы связанного объекта (см. IMDGDistributedNames) + * @param mapClass Класс связанного объекта + * @param idNotPresentError Ошибка, которая будет возвращена, если Id не найден + * @param required Флаг обязательности + * @param additionalChecks Дополнительные проверки, которые можно провести со связанным объектом + * @param Класс проверяемого объекта + * @param Класс связанного объекта + */ @SafeVarargs public static IdPresentRule instance(String fieldName, Function idGetter, diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java index 9d172e0bd..90287864e 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java @@ -9,12 +9,27 @@ import java.time.LocalTime; import java.util.Optional; import java.util.function.Function; +/** + * Проверка поля с LocalTime. Условие проверки: проверяемое время >= текущее время + * @param Класс проверяемого объекта + */ public record TimeNotBeforeRule(String fieldName, Function getter, boolean required) implements IValidationRule> { + /** + * @param fieldName Название поля класса, используется для передачи ошибки + * @param getter Метод получения проверяемого времени + * @param required Флаг обязательности поля + * @param Класс проверяемого объекта + */ public static TimeNotBeforeRule instance(String fieldName, Function getter, boolean required) { return new TimeNotBeforeRule<>(fieldName, getter, required); } + /** + * @param fieldName Название поля класса, используется для передачи ошибки + * @param getter Метод получения проверяемого времени + * @param Класс проверяемого объекта + */ public static TimeNotBeforeRule instance(String fieldName, Function getter) { return new TimeNotBeforeRule<>(fieldName, getter, true); } From 69f63cbc676fc2e63aa9fa680e5ece2ff306017c Mon Sep 17 00:00:00 2001 From: akulikov Date: Wed, 18 Jan 2023 13:44:26 +0300 Subject: [PATCH 11/14] refactor, test fix --- .../service/ClearingCalendarService.java | 45 ++------------ .../scheduler/service/PlannerService.java | 45 ++------------ .../service/PlannerTemplateService.java | 45 ++------------ .../rules/common/DictionaryPresentRule.java | 10 +++- .../rules/common/IdPresentRule.java | 3 +- .../service/ClearingCalendarServiceTest.java | 60 ++++++++++++++++++- .../service/PlannerTemplateServiceTest.java | 8 ++- .../messaging/service/QueueConsumer.java | 30 ++++++++++ 8 files changed, 121 insertions(+), 125 deletions(-) diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java index 1f65dd20c..adbf15094 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java @@ -17,15 +17,12 @@ import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendar import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; -import ru.spcex.clearing.platform.messaging.service.Status; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; -import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; -import java.util.Optional; import java.util.function.Function; @Service @@ -69,18 +66,8 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi private RequestInfoUpdate newClearingCalendar(BaseRequest userRequest) { ClearingCalendarNewRequest req = userRequest.getRequestPayload(); log.debug("ClearingCalendarNewRequest received"); - if (clearingCalendarNewRequestValidation != null) { - IValidator validator = clearingCalendarNewRequestValidation.apply(req); - Optional validationError = validator.tillFirstError(); - if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process ClearingCalendarNewRequest id={}: {}", userRequest.getId(), errorMsg); - return new RequestInfoUpdate() - .setId(userRequest.getId()) - .setStatus(Status.Error) - .setMessage(errorMsg); - } - } + RequestInfoUpdate requestInfoUpdate = validate(userRequest, clearingCalendarNewRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; ClearingCalendar clearingCalendar = new ClearingCalendar(); Instant created = Instant.now(); clearingCalendar.setCreated(created); @@ -95,18 +82,8 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi private RequestInfoUpdate updateClearingCalendar(BaseRequest userRequest) { ClearingCalendarUpdateRequest req = userRequest.getRequestPayload(); log.debug("ClearingCalendarUpdateRequest received"); - if (clearingCalendarUpdateRequestValidation != null) { - IValidator validator = clearingCalendarUpdateRequestValidation.apply(req); - Optional validationError = validator.tillFirstError(); - if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process ClearingCalendarUpdateRequest id={}: {}", userRequest.getId(), errorMsg); - return new RequestInfoUpdate() - .setId(userRequest.getId()) - .setStatus(Status.Error) - .setMessage(errorMsg); - } - } + RequestInfoUpdate requestInfoUpdate = validate(userRequest, clearingCalendarUpdateRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; Instant updated = Instant.now(); ClearingCalendar clearingCalendar = clearingCalendarMap.getSingleObjectByID(req.getId()); clearingCalendar.setClearingDate(req.getClearingDate()); @@ -120,18 +97,8 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi private RequestInfoUpdate deleteClearingCalendar(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); - if (clearingCalendarDeleteRequestValidation != null) { - IValidator validator = clearingCalendarDeleteRequestValidation.apply(req); - Optional validationError = validator.tillFirstError(); - if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process CommonDeleteRequest id={}: {}", userRequest.getId(), errorMsg); - return new RequestInfoUpdate() - .setId(userRequest.getId()) - .setStatus(Status.Error) - .setMessage(errorMsg); - } - } + RequestInfoUpdate requestInfoUpdate = validate(userRequest, clearingCalendarDeleteRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; log.debug("CommonDeleteRequest received id = {}", req.getId()); ClearingCalendar clearingCalendar = clearingCalendarMap.getSingleObjectByID(req.getId()); clearingCalendarMap.delete(clearingCalendar); diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java index 9d1ee12d4..4f0870dbc 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java @@ -17,15 +17,12 @@ import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewReques import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; -import ru.spcex.clearing.platform.messaging.service.Status; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; -import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; -import java.util.Optional; import java.util.function.Function; @Service @@ -70,18 +67,8 @@ public class PlannerService extends QueueConsumer implements InitializingBean { private RequestInfoUpdate newScheduler(BaseRequest userRequest) { PlannerNewRequest req = userRequest.getRequestPayload(); log.debug("PlannerNewRequest received"); - if (plannerNewRequestValidation != null) { - IValidator validator = plannerNewRequestValidation.apply(req); - Optional validationError = validator.tillFirstError(); - if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process PlannerNewRequest id={}: {}", userRequest.getId(), errorMsg); - return new RequestInfoUpdate() - .setId(userRequest.getId()) - .setStatus(Status.Error) - .setMessage(errorMsg); - } - } + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerNewRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; Planner planner = new Planner(); planner.setCreated(Instant.now()); planner.setTask(req.getTask()); @@ -99,18 +86,8 @@ public class PlannerService extends QueueConsumer implements InitializingBean { private RequestInfoUpdate updateScheduler(BaseRequest userRequest) { PlannerUpdateRequest req = userRequest.getRequestPayload(); log.debug("PlannerUpdateRequest received id = {}", req.getId()); - if (plannerUpdateRequestValidation != null) { - IValidator validator = plannerUpdateRequestValidation.apply(req); - Optional validationError = validator.tillFirstError(); - if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process PlannerUpdateRequest id={}: {}", userRequest.getId(), errorMsg); - return new RequestInfoUpdate() - .setId(userRequest.getId()) - .setStatus(Status.Error) - .setMessage(errorMsg); - } - } + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerUpdateRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; Planner planner = plannerMap.getSingleObjectByID(req.getId()); planner.setUpdated(Instant.now()); planner.setTask(req.getTask()); @@ -127,18 +104,8 @@ public class PlannerService extends QueueConsumer implements InitializingBean { private RequestInfoUpdate deleteScheduler(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); log.debug("CommonDeleteRequest received id = {}", req.getId()); - if (plannerDeleteRequestValidation != null) { - IValidator validator = plannerDeleteRequestValidation.apply(req); - Optional validationError = validator.tillFirstError(); - if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process PlannerUpdateRequest id={}: {}", userRequest.getId(), errorMsg); - return new RequestInfoUpdate() - .setId(userRequest.getId()) - .setStatus(Status.Error) - .setMessage(errorMsg); - } - } + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerDeleteRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; Planner planner = plannerMap.getSingleObjectByID(req.getId()); plannerMap.delete(planner); return null; diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java index 97873e004..2b7c7c76a 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java @@ -17,15 +17,12 @@ import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateN import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; -import ru.spcex.clearing.platform.messaging.service.Status; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; -import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; -import java.util.Optional; import java.util.function.Function; @Service @@ -69,18 +66,8 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin private RequestInfoUpdate newTimetable(BaseRequest userRequest) { PlannerTemplateNewRequest req = userRequest.getRequestPayload(); log.debug("PlannerTemplateNewRequest received"); - if (plannerTemplateNewRequestValidation != null) { - IValidator validator = plannerTemplateNewRequestValidation.apply(req); - Optional validationError = validator.tillFirstError(); - if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process PlannerTemplateNewRequest id={}: {}", userRequest.getId(), errorMsg); - return new RequestInfoUpdate() - .setId(userRequest.getId()) - .setStatus(Status.Error) - .setMessage(errorMsg); - } - } + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerTemplateNewRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; PlannerTemplate plannerTemplate = new PlannerTemplate(); Instant created = Instant.now(); plannerTemplate.setCreated(created); @@ -97,18 +84,8 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin private RequestInfoUpdate updateTimetable(BaseRequest userRequest) { PlannerTemplateUpdateRequest req = userRequest.getRequestPayload(); log.debug("PlannerTemplateUpdateRequest received"); - if (plannerTemplateUpdateRequestValidation != null) { - IValidator validator = plannerTemplateUpdateRequestValidation.apply(req); - Optional validationError = validator.tillFirstError(); - if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process PlannerTemplateNewRequest id={}: {}", userRequest.getId(), errorMsg); - return new RequestInfoUpdate() - .setId(userRequest.getId()) - .setStatus(Status.Error) - .setMessage(errorMsg); - } - } + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerTemplateUpdateRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; PlannerTemplate plannerTemplate = plannerTemplateMap.getSingleObjectByID(req.getId()); Instant updated = Instant.now(); plannerTemplate.setUpdated(updated); @@ -125,18 +102,8 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin private RequestInfoUpdate deleteTimetable(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); log.debug("CommonDeleteRequest received id = {}", req.getId()); - if (plannerTemplateDeleteRequestValidation != null) { - IValidator validator = plannerTemplateDeleteRequestValidation.apply(req); - Optional validationError = validator.tillFirstError(); - if (validationError.isPresent()) { - String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process PlannerTemplateUpdateRequest id={}: {}", userRequest.getId(), errorMsg); - return new RequestInfoUpdate() - .setId(userRequest.getId()) - .setStatus(Status.Error) - .setMessage(errorMsg); - } - } + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerTemplateDeleteRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; PlannerTemplate plannerTemplate = plannerTemplateMap.getSingleObjectByID(req.getId()); plannerTemplateMap.delete(plannerTemplate); return null; diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java index 351b9bc03..a9ff56c9c 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java @@ -3,11 +3,13 @@ package ru.spcex.clearing.scheduler.validation.rules.common; import ru.clearing.platform.dictionary.AbstractDictionary; import ru.spcex.clearing.scheduler.error.ValidationError; 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.imdg.validation.ImdgValidationContext; import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.validation.IValidationRule; -import java.util.Map; +import java.util.Collection; import java.util.Optional; import java.util.function.Function; @@ -63,7 +65,11 @@ public record DictionaryPresentRule(String fiel dictionaryName, dictionaryClass ); - D dictionaryFromMap = dictImdg.getSingleObjectByFieldValues(Map.of("code", enumCode)); + ImdgPredicateBuilder imdgPredicateBuilder = dictImdg.predicateBuilder(); + ImdgPredicate imdgPredicate = imdgPredicateBuilder.equals("code", enumCode); + Collection fromMap = dictImdg.getCollectionObjectsByPredicate(imdgPredicate); + assert fromMap.size() <= 1; + D dictionaryFromMap = fromMap.iterator().next(); if (dictionaryFromMap == null) { return of(ValidationError.WrongDictionaryValue, fieldName); } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java index ce91ee7d2..e87377b56 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java @@ -7,7 +7,6 @@ import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.validation.IValidationRule; -import java.util.Map; import java.util.Optional; import java.util.function.Function; @@ -64,7 +63,7 @@ public record IdPresentRule( Long id = idGetter.apply(validatedObject); if (id == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : empty(); Imdg imdg = context.obtainMap(mapName, mapClass); - V fromMap = imdg.getSingleObjectByFieldValues(Map.of("id", id)); + V fromMap = imdg.getSingleObjectByID(id); if (fromMap == null) { return of(idNotPresentError, fieldName); } diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java index 7307966f9..333ae3179 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java @@ -17,25 +17,40 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.profile.Contact; import ru.clearing.classes.statics.data.scheduler.ClearingCalendar; +import ru.clearing.platform.dictionary.DayStatusDictionary; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.ActionType; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarUpdateRequest; +import ru.spcex.clearing.scheduler.config.validation.ClearingCalendarValidationConfig; +import ru.spcex.clearing.scheduler.config.validation.ValidationConfig; import ru.spcex.clearing.scheduler.service.ClearingCalendarService; +import ru.spcex.platform.enumeration.DayStatus; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.validation.IValidator; import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; import java.time.Instant; import java.time.LocalDate; import java.util.Collections; import java.util.HashMap; +import java.util.function.Function; @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { - HazelcastServiceTestConfiguration.class}) + HazelcastServiceTestConfiguration.class, + ValidationConfig.class, + ClearingCalendarValidationConfig.class +}) class ClearingCalendarServiceTest { private static final int PARTITION = 0; @@ -48,6 +63,18 @@ class ClearingCalendarServiceTest { private MockConsumer mockConsumer; private MockProducer mockProducer; + @Autowired + private IMessageResolver messageResolver; + + @Autowired + private Function clearingCalendarDeleteRequestValidation; + + @Autowired + private Function clearingCalendarNewRequestValidation; + + @Autowired + private Function clearingCalendarUpdateRequestValidation; + @BeforeEach void setUp() { mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST); @@ -61,8 +88,22 @@ class ClearingCalendarServiceTest { */ @Test public void newClearingCalendarInQueue() throws InterruptedException { - //ARRANGE + // Prepare test objects + hazelcastServiceTest.waitAvailable(); + Company company = new Company(); + company.setId(0L); + company.setWorkflowStatus(WorkflowStatus.Active.getKey()); + Imdg companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class); + companyImdg.insert(company); + DayStatus dayStatus = DayStatus.Workday; + DayStatusDictionary dayStatusDictionary = new DayStatusDictionary(); + dayStatusDictionary.setId(0L); + dayStatusDictionary.setCode(dayStatus.getKey()); + Imdg dayStatusDictionaryImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_DayStatusDictionary, DayStatusDictionary.class); + dayStatusDictionaryImdg.insert(dayStatusDictionary); + + //ARRANGE ClearingCalendar clearingCalendar = new ClearingCalendar(); Instant created = Instant.now(); clearingCalendar.setCreated(created); @@ -89,10 +130,23 @@ class ClearingCalendarServiceTest { //ACT //service set up - ClearingCalendarService clearingCalendarService = new ClearingCalendarService(mockConsumer, mockProducer, hazelcastServiceTest); + ClearingCalendarService clearingCalendarService = new ClearingCalendarService(mockConsumer, + mockProducer, + hazelcastServiceTest, + messageResolver, + clearingCalendarDeleteRequestValidation, + clearingCalendarNewRequestValidation, + clearingCalendarUpdateRequestValidation); //callbacks set up clearingCalendarService.afterPropertiesSet(); + + BaseRequest baseRequest = new BaseRequest<>(); + baseRequest.setId(1L); + baseRequest.setActionType(ActionType.NEW); + ClearingCalendarNewRequest newRequest = new ClearingCalendarNewRequest(); + baseRequest.setRequestPayload(newRequest); + IMap iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_ClearingCalendar); //KAFKA HashMap startOffsetsUpdating = new HashMap<>(); diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java index c9bac35d7..98696e3df 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java @@ -93,7 +93,13 @@ class PlannerTemplateServiceTest { //ACT //service set up - PlannerTemplateService plannerTemplateService = new PlannerTemplateService(mockConsumer, mockProducer, hazelcastServiceTest, messageResolver, null, null, null); + PlannerTemplateService plannerTemplateService = new PlannerTemplateService(mockConsumer, + mockProducer, + hazelcastServiceTest, + messageResolver, + null, + null, + null); //callbacks set up plannerTemplateService.afterPropertiesSet(); diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java index 2730b70a5..343e8eca6 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java @@ -16,16 +16,21 @@ import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.logic.functional.BuilderConsumerStep; import ru.spcex.clearing.platform.messaging.logic.functional.ConsumerSpecificClass; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.log.ExceptionUtils; +import ru.spcex.platform.utils.validation.IValidator; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; /** * утилитный класс для обработки сообщений из очереди @@ -155,6 +160,31 @@ public class QueueConsumer implements AutoCloseable { return ConsumerSpecificClass.build(clazz); } + + /** + * Валидация запроса + * @param Класс проверяемого запроса + * @return null если ошибок нет + */ + public RequestInfoUpdate validate(BaseRequest userRequest, + Function validatorBuilder, + IMessageResolver messageResolver) { + if (validatorBuilder != null) { + R req = userRequest.getRequestPayload(); + IValidator validator = validatorBuilder.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("cannot process {} id={}: {}", req.getClass().getSimpleName(), userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + } + return null; + } + @Override public void close() { log.debug("Closing queue consumer {}", getClass().getSimpleName()); From 209edc1a44a54e74fca501ba6dc87bcf3916687a Mon Sep 17 00:00:00 2001 From: akulikov Date: Wed, 18 Jan 2023 15:48:39 +0300 Subject: [PATCH 12/14] ClearingCalendarServiceTest add validation test --- .../ru/spcex/clearing/scheduler/error/ValidationError.java | 2 +- .../validation/rules/common/DictionaryPresentRule.java | 5 ++++- .../scheduler/service/ClearingCalendarServiceTest.java | 4 ++-- .../clearing/platform/messaging/service/QueueConsumer.java | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java index a0483da4d..ea04bfa3a 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java @@ -24,6 +24,6 @@ public enum ValidationError implements IEnumId { @Override public Long getId() { - return null; + return id; } } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java index a9ff56c9c..999f484bb 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java @@ -68,7 +68,10 @@ public record DictionaryPresentRule(String fiel ImdgPredicateBuilder imdgPredicateBuilder = dictImdg.predicateBuilder(); ImdgPredicate imdgPredicate = imdgPredicateBuilder.equals("code", enumCode); Collection fromMap = dictImdg.getCollectionObjectsByPredicate(imdgPredicate); - assert fromMap.size() <= 1; + if (fromMap.isEmpty()) { + return of(ValidationError.WrongDictionaryValue, fieldName); + } + assert fromMap.size() == 1; D dictionaryFromMap = fromMap.iterator().next(); if (dictionaryFromMap == null) { return of(ValidationError.WrongDictionaryValue, fieldName); diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java index 333ae3179..258f6e1a3 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java @@ -107,9 +107,9 @@ class ClearingCalendarServiceTest { ClearingCalendar clearingCalendar = new ClearingCalendar(); Instant created = Instant.now(); clearingCalendar.setCreated(created); - clearingCalendar.setClearingDate(LocalDate.now()); + clearingCalendar.setClearingDate(LocalDate.now().plusDays(1)); clearingCalendar.setCompanyId(0L); - clearingCalendar.setDayStatus("STATUS"); + clearingCalendar.setDayStatus(DayStatus.Workday.getKey()); ClearingCalendarNewRequest clearingCalendarNewRequest = new ClearingCalendarNewRequest(); clearingCalendarNewRequest.setClearingDate(clearingCalendar.getClearingDate()); diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java index 343e8eca6..8fffd91e8 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java @@ -175,7 +175,7 @@ public class QueueConsumer implements AutoCloseable { Optional validationError = validator.tillFirstError(); if (validationError.isPresent()) { String errorMsg = messageResolver.resolve(validationError.get()); - log.error("cannot process {} id={}: {}", req.getClass().getSimpleName(), userRequest.getId(), errorMsg); + 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) From 99c3a8e6559a8fbc7bd4f7cb48859d0e5d5216eb Mon Sep 17 00:00:00 2001 From: akulikov Date: Thu, 19 Jan 2023 11:28:47 +0300 Subject: [PATCH 13/14] PlannerTemplateServiceTest fix --- .../service/PlannerTemplateServiceTest.java | 74 ++++++++++++++++--- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java index 98696e3df..3d6dedc07 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java @@ -17,26 +17,43 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.profile.Contact; import ru.clearing.classes.statics.data.scheduler.PlannerTemplate; +import ru.clearing.classes.statics.data.security.Security; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.ActionType; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateUpdateRequest; +import ru.spcex.clearing.scheduler.config.validation.PlannerTemplateValidationConfig; +import ru.spcex.clearing.scheduler.config.validation.ValidationConfig; import ru.spcex.clearing.scheduler.service.PlannerTemplateService; +import ru.spcex.platform.enumeration.Status; +import ru.spcex.platform.enumeration.Task; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.validation.IValidator; import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; import java.time.Instant; import java.time.LocalTime; import java.util.Collections; import java.util.HashMap; +import java.util.function.Function; @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { - HazelcastServiceTestConfiguration.class}) + HazelcastServiceTestConfiguration.class, + ValidationConfig.class, + PlannerTemplateValidationConfig.class +}) class PlannerTemplateServiceTest { private static final int PARTITION = 0; @@ -48,8 +65,19 @@ class PlannerTemplateServiceTest { private HazelcastService hazelcastServiceTest; private MockConsumer mockConsumer; private MockProducer mockProducer; + + @Autowired private IMessageResolver messageResolver; + @Autowired + private Function plannerTemplateDeleteRequestValidation; + + @Autowired + private Function plannerTemplateNewRequestValidation; + + @Autowired + private Function plannerTemplateUpdateRequestValidation; + @BeforeEach void setUp() { mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST); @@ -63,14 +91,42 @@ class PlannerTemplateServiceTest { */ @Test public void newPlannerTemplateInQueue() throws InterruptedException { + Task testTask = Task.accountBlock; + TaskDictionary taskDictionary = new TaskDictionary(); + taskDictionary.setId(0L); + taskDictionary.setCode(testTask.getKey()); + Imdg taskDictionaryImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class); + taskDictionaryImdg.insert(taskDictionary); + + Status testTaskStatus = Status.Active; + TaskStatusDictionary taskStatusDictionary = new TaskStatusDictionary(); + taskStatusDictionary.setId(0L); + taskStatusDictionary.setCode(testTaskStatus.getKey()); + Imdg taskStatusDictionaryImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class); + taskStatusDictionaryImdg.insert(taskStatusDictionary); + + long testCompanyId = 0L; + Company company = new Company(); + company.setId(testCompanyId); + company.setWorkflowStatus(WorkflowStatus.Active.getKey()); + Imdg companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class); + companyImdg.insert(company); + + long testSecurityId = 0L; + Security security = new Security(); + security.setId(testSecurityId); + security.setWorkflowStatus(WorkflowStatus.Active.getKey()); + Imdg securityImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Security, Security.class); + securityImdg.insert(security); + //ARRANGE Instant created = Instant.now(); PlannerTemplate plannerTemplate = new PlannerTemplate(); - plannerTemplate.setTask("TASK"); - plannerTemplate.setTaskTime(LocalTime.MIDNIGHT); - plannerTemplate.setTaskStatus("TASK_STATUS"); - plannerTemplate.setCompanyId(0L); - plannerTemplate.setSecurityId(10L); + plannerTemplate.setTask(testTask.getKey()); + plannerTemplate.setTaskTime(LocalTime.now().plusHours(1)); + plannerTemplate.setTaskStatus(testTaskStatus.getKey()); + plannerTemplate.setCompanyId(testCompanyId); + plannerTemplate.setSecurityId(testSecurityId); PlannerTemplateNewRequest plannerTemplateNewRequest = new PlannerTemplateNewRequest(); plannerTemplateNewRequest.setTask(plannerTemplate.getTask()); @@ -97,9 +153,9 @@ class PlannerTemplateServiceTest { mockProducer, hazelcastServiceTest, messageResolver, - null, - null, - null); + plannerTemplateDeleteRequestValidation, + plannerTemplateNewRequestValidation, + plannerTemplateUpdateRequestValidation); //callbacks set up plannerTemplateService.afterPropertiesSet(); From 5551702dc9b3b9d4cc42ede33f97be3a2ef99479 Mon Sep 17 00:00:00 2001 From: akulikov Date: Thu, 19 Jan 2023 11:32:15 +0300 Subject: [PATCH 14/14] PlannerTemplateServiceTest fix --- .../clearing/scheduler/service/PlannerTemplateServiceTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java index 3d6dedc07..7fd0b0d66 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java @@ -44,6 +44,7 @@ import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; import java.time.Instant; import java.time.LocalTime; +import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.HashMap; import java.util.function.Function; @@ -195,7 +196,7 @@ class PlannerTemplateServiceTest { Assertions.assertNotNull(plannerTemplateRes.getCreated()); Assertions.assertEquals(plannerTemplate.getTask(), plannerTemplateRes.getTask()); - Assertions.assertEquals(plannerTemplate.getTaskTime(), plannerTemplateRes.getTaskTime()); + Assertions.assertEquals(plannerTemplate.getTaskTime().truncatedTo(ChronoUnit.SECONDS), plannerTemplateRes.getTaskTime().truncatedTo(ChronoUnit.SECONDS)); Assertions.assertEquals(plannerTemplate.getTaskStatus(), plannerTemplateRes.getTaskStatus()); Assertions.assertEquals(plannerTemplate.getCompanyId(), plannerTemplateRes.getCompanyId()); Assertions.assertEquals(plannerTemplate.getSecurityId(), plannerTemplateRes.getSecurityId());