From 62b847fcef4e76d51ed2ba829f229298b87a4049 Mon Sep 17 00:00:00 2001 From: ialbert Date: Thu, 20 Jul 2023 19:26:10 +0300 Subject: [PATCH] http://jira.mfd.msk:8088/browse/CLS-436 --- .../service/CodeStatusComparator.java | 57 ++++++++++++++ .../gatewayapi/service/SecurityService.java | 4 + .../service/processor/ListingMMProcessor.java | 5 ++ .../service/CodeStatusComparatorTest.java | 78 +++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/CodeStatusComparator.java create mode 100644 clearing-parent/gateway-api/src/test/java/ru/spcex/clearing/gatewayapi/service/CodeStatusComparatorTest.java diff --git a/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/CodeStatusComparator.java b/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/CodeStatusComparator.java new file mode 100644 index 000000000..87be61427 --- /dev/null +++ b/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/CodeStatusComparator.java @@ -0,0 +1,57 @@ +package ru.spcex.clearing.gatewayapi.service; + +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.utils.enumeration.IEnumKey; + +import java.util.Comparator; +import java.util.Objects; +import java.util.function.Function; + +public class CodeStatusComparator implements Comparator { + + private final Function codeExtractor; + private final Function workflowStatusExtractor; + + public CodeStatusComparator(Function codeExtractor, Function workflowStatusExtractor) { + this.codeExtractor = codeExtractor; + this.workflowStatusExtractor = workflowStatusExtractor; + } + + public static CodeStatusComparator create(Function codeExtractor, Function workflowStatusExtractor) { + return new CodeStatusComparator(codeExtractor, workflowStatusExtractor); + } + + @Override + public int compare(T o1, T o2) { + if (codeExtractor == null || workflowStatusExtractor == null) throw new IllegalStateException("codeExtractor and workflowStatusExtractor must be set"); + String securitySymbol1 = codeExtractor.apply(o1); + String securitySymbol2 = codeExtractor.apply(o2); + String workflowStatus1 = workflowStatusExtractor.apply(o1); + String workflowStatus2 = workflowStatusExtractor.apply(o2); + + //Если приходят несколько объектов с одним security.security_symbol и разными security.workflow_status, + // просьба сначала обрабатывать записи workflow_status="BLKD", а потом с workflow_status="ACTV". + if (!Objects.equals(securitySymbol1, securitySymbol2)) { + return Objects.compare(securitySymbol1, securitySymbol2, Comparator.naturalOrder()); + } + if (Objects.equals(workflowStatus1, workflowStatus2)) { + return 0; + } + //сначала достаем workflowStatus из объекта + Function statusObtainer = ws -> { + WorkflowStatus workflowStatus = IEnumKey.getEnumByKey(WorkflowStatus.class, ws); + return Objects.requireNonNullElse(workflowStatus, WorkflowStatus.Active); + }; + //потом устанавливаем очередносьб: сначала Blocked + Function statusMapper = ws -> { + if (WorkflowStatus.Blocked.equals(ws)) { + return -1; + } else { + return 1; + } + }; + Integer o1Ws = statusObtainer.andThen(statusMapper).apply(workflowStatus1); + Integer o2Ws = statusObtainer.andThen(statusMapper).apply(workflowStatus2); + return o1Ws.compareTo(o2Ws); + } +} diff --git a/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/SecurityService.java b/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/SecurityService.java index 513660a54..48a8bba01 100644 --- a/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/SecurityService.java +++ b/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/SecurityService.java @@ -34,6 +34,10 @@ public class SecurityService { public void sendRequest(FondListingsRequest request) { List securityList = request.getSecurities(); + CodeStatusComparator comparatorBySecSymbolAndWorkflowStatus = CodeStatusComparator.create( + FondSecurity::getSecuritySymbol, + FondSecurity::getWorkflowStatus); + securityList.sort(comparatorBySecSymbolAndWorkflowStatus); for (FondSecurity security : securityList) { try { log.debug("process security uuid: {}", security.getId()); diff --git a/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/processor/ListingMMProcessor.java b/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/processor/ListingMMProcessor.java index 7b004ad73..6d9817067 100644 --- a/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/processor/ListingMMProcessor.java +++ b/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/service/processor/ListingMMProcessor.java @@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import ru.spcex.clearing.gatewayapi.controller.inbound.request.listing.mkr.ExchangeInstrument; import ru.spcex.clearing.gatewayapi.controller.inbound.request.listing.mkr.MMListingsRequest; +import ru.spcex.clearing.gatewayapi.service.CodeStatusComparator; import ru.spcex.clearing.gatewayapi.service.adapter.MoneyMarketSecurityRequestAdapter; import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSecurityNewGatewayRequest; @@ -30,6 +31,10 @@ public class ListingMMProcessor { public void process(MMListingsRequest request) { List exchangeInstrumentList = request.getExchangeInstrumentList(); + CodeStatusComparator comparatorByCodeAndWorkflowStatus = CodeStatusComparator.create( + ExchangeInstrument::getCode, + ExchangeInstrument::getWorkflowStatus); + exchangeInstrumentList.sort(comparatorByCodeAndWorkflowStatus); for (ExchangeInstrument exchangeInstrument : exchangeInstrumentList) { try { UUID exchangeInstrumentId = exchangeInstrument.getId(); diff --git a/clearing-parent/gateway-api/src/test/java/ru/spcex/clearing/gatewayapi/service/CodeStatusComparatorTest.java b/clearing-parent/gateway-api/src/test/java/ru/spcex/clearing/gatewayapi/service/CodeStatusComparatorTest.java new file mode 100644 index 000000000..7662ceaa5 --- /dev/null +++ b/clearing-parent/gateway-api/src/test/java/ru/spcex/clearing/gatewayapi/service/CodeStatusComparatorTest.java @@ -0,0 +1,78 @@ +package ru.spcex.clearing.gatewayapi.service; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import ru.spcex.clearing.gatewayapi.controller.inbound.request.listing.fond.FondSecurity; +import ru.spcex.platform.enumeration.WorkflowStatus; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CodeStatusComparatorTest { + + private final static FondSecurity secActive = security("a", WorkflowStatus.Active.getKey()); + private final static FondSecurity secBlocked = security("a", WorkflowStatus.Blocked.getKey()); + private final static FondSecurity secNull = security("a", null); + private final static FondSecurity secEmpty = security("a", ""); + private final static FondSecurity secUnparsable = security("a", "ulala"); + private final static FondSecurity secOtherCode = security("b", WorkflowStatus.Blocked.getKey()); + private final static CodeStatusComparator comp = CodeStatusComparator.create( + FondSecurity::getSecuritySymbol, + FondSecurity::getWorkflowStatus); + + @Test + void compare() { + List fondSecurities = Arrays.asList( + security("2", "a", WorkflowStatus.Active.getKey()), + security("1", "a", WorkflowStatus.Blocked.getKey()), + security("3", "b", WorkflowStatus.Blocked.getKey()), + security("4", "b", WorkflowStatus.Active.getKey()), + security("6", "c", WorkflowStatus.Active.getKey()), + security("7", "d", WorkflowStatus.Blocked.getKey()), + security("8", "d", WorkflowStatus.Blocked.getKey()), + security("5", "c", WorkflowStatus.Blocked.getKey()) + ); + //signum(compare(x, y)) == -signum(compare(y, x)) for all x and y + //((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0. + //Finally, the implementor must ensure that compare(x, y)==0 implies that signum(compare(x, z))==signum(compare(y, z)) for all z + fondSecurities.sort(comp); + for (int i = 0; i < fondSecurities.size(); i++) { + assertEquals(Integer.parseInt(fondSecurities.get(i).getShortName()), i + 1); + } + } + + @Test + public void compare2() { + Assertions.assertTrue(comp.compare(secActive, secBlocked) > 0); + Assertions.assertTrue(comp.compare(secBlocked, secActive) < 0); + + Assertions.assertTrue(comp.compare(secActive, secOtherCode) < 0); + Assertions.assertTrue(comp.compare(secOtherCode, secActive) > 0); + + Assertions.assertTrue(comp.compare(secBlocked, secNull) < 0); + Assertions.assertTrue(comp.compare(secNull, secBlocked) > 0); + + Assertions.assertEquals(0, comp.compare(secEmpty, secNull)); + Assertions.assertEquals(0, comp.compare(secNull, secEmpty)); + Assertions.assertEquals(0, comp.compare(secEmpty, secUnparsable)); + + Assertions.assertTrue(comp.compare(secBlocked, secUnparsable) < 0); + } + + + private static FondSecurity security(String shortName, String securitySymbol, String workflowStatus) { + FondSecurity sec = new FondSecurity(); + sec.setShortName(shortName); + sec.setSecuritySymbol(securitySymbol); + sec.setWorkflowStatus(workflowStatus); + return sec; + } + private static FondSecurity security(String securitySymbol, String workflowStatus) { + FondSecurity sec = new FondSecurity(); + sec.setSecuritySymbol(securitySymbol); + sec.setWorkflowStatus(workflowStatus); + return sec; + } +} \ No newline at end of file