diff --git a/clearing-parent/control-service/pom.xml b/clearing-parent/control-service/pom.xml new file mode 100644 index 000000000..3fed973f9 --- /dev/null +++ b/clearing-parent/control-service/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + control-service + control-service + Control service + SPCEX-3.15.207 + + + clearing-parent + ru.spcex.clearing + SPCEX-3.15.207 + + + + 7.0.1 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.postgresql + postgresql + runtime + + + com.mchange + c3p0 + + + + + net.logstash.logback + logstash-logback-encoder + ${logstash-logback-encoder.version} + + + com.fasterxml.jackson.core + jackson-databind + + + + ru.spcex.platform + platform-enum + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + src/main/resources + + application.properties + + false + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + ${project.artifactId} + + + + + + \ No newline at end of file diff --git a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/config/DataSourceConfiguration.java b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/config/DataSourceConfiguration.java new file mode 100644 index 000000000..7fe03204a --- /dev/null +++ b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/config/DataSourceConfiguration.java @@ -0,0 +1,48 @@ +package ru.spcex.clearing.control.config; + +import com.mchange.v2.c3p0.ComboPooledDataSource; +import java.beans.PropertyVetoException; +import javax.sql.DataSource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import ru.spcex.clearing.control.config.settings.ControlServiceSettings; + +@Configuration +public class DataSourceConfiguration { + private final ControlServiceSettings settings; + + public DataSourceConfiguration(ControlServiceSettings settings) { + this.settings = settings; + } + + @Bean + public DataSource getDataSource() { + ComboPooledDataSource cpds = new ComboPooledDataSource(); + try { + cpds.setDriverClass("org.postgresql.Driver"); + cpds.setJdbcUrl(settings.getDatabase().getUrl()); + cpds.setUser(settings.getDatabase().getUsername()); + cpds.setPassword(settings.getDatabase().getPassword()); + + cpds.setMaxPoolSize(100); + cpds.setMinPoolSize(50); + cpds.setAcquireIncrement(5); + } catch (PropertyVetoException e) { + throw new RuntimeException(e); + } + + return cpds; + } + + @Bean + public JdbcTemplate getJdbcTemplate() { + return new JdbcTemplate(getDataSource()); + } + + @Bean + public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() { + return new NamedParameterJdbcTemplate(getDataSource()); + } +} diff --git a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/config/settings/ControlServiceSettings.java b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/config/settings/ControlServiceSettings.java new file mode 100644 index 000000000..6a3e73ceb --- /dev/null +++ b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/config/settings/ControlServiceSettings.java @@ -0,0 +1,30 @@ +package ru.spcex.clearing.control.config.settings; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties("control-service") +public class ControlServiceSettings { + @NestedConfigurationProperty + private Database database; + + private String resultDirectory; + + public Database getDatabase() { + return database; + } + + public void setDatabase(Database database) { + this.database = database; + } + + public String getResultDirectory() { + return resultDirectory; + } + + public void setResultDirectory(String resultDirectory) { + this.resultDirectory = resultDirectory; + } +} diff --git a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/config/settings/Database.java b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/config/settings/Database.java new file mode 100644 index 000000000..0ae47c5a1 --- /dev/null +++ b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/config/settings/Database.java @@ -0,0 +1,31 @@ +package ru.spcex.clearing.control.config.settings; + +public class Database { + private String username; + private String password; + private String url; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/controller/ControlController.java b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/controller/ControlController.java new file mode 100644 index 000000000..72ee5e8aa --- /dev/null +++ b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/controller/ControlController.java @@ -0,0 +1,33 @@ +package ru.spcex.clearing.control.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.spcex.clearing.control.service.ControlService; +import ru.spcex.platform.enumeration.SessionType; + +@RestController +@RequestMapping("/api/v1/control") +public class ControlController { + private final ControlService controlService; + + public ControlController(ControlService controlService) { + this.controlService = controlService; + } + + @GetMapping("/general-control/{sessionType}") + public String generalControl(@PathVariable("sessionType") SessionType sessionType) { + return controlService.generalControl(sessionType); + } + + @GetMapping("/internal-control/{sessionId}") + public String internalControl(@PathVariable("sessionId") Long sessionId) { + return controlService.internalControl(sessionId); + } + + @GetMapping("/internal-control-finl/{sessionId}") + public String internalControlFinl(@PathVariable("sessionId") Long sessionId) { + return controlService.internalControlFinl(sessionId); + } +} diff --git a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/mapper/ResultContainerMapper.java b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/mapper/ResultContainerMapper.java new file mode 100644 index 000000000..ffc9f91d5 --- /dev/null +++ b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/mapper/ResultContainerMapper.java @@ -0,0 +1,19 @@ +package ru.spcex.clearing.control.mapper; + +import java.sql.ResultSet; +import java.sql.SQLException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; +import ru.spcex.clearing.control.model.ResultContainer; + +@Component +public class ResultContainerMapper implements RowMapper { + @Override + public ResultContainer mapRow(ResultSet rs, int rowNum) throws SQLException { + return new ResultContainer( + rs.getLong("first_table"), + rs.getLong("second_table"), + rs.getLong("diff") + ); + } +} diff --git a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/model/ResultContainer.java b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/model/ResultContainer.java new file mode 100644 index 000000000..63894e134 --- /dev/null +++ b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/model/ResultContainer.java @@ -0,0 +1,4 @@ +package ru.spcex.clearing.control.model; + +public record ResultContainer(Long firstTable, Long secondTable, Long difference) { +} diff --git a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/repository/ControlRepository.java b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/repository/ControlRepository.java new file mode 100644 index 000000000..990be1513 --- /dev/null +++ b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/repository/ControlRepository.java @@ -0,0 +1,91 @@ +package ru.spcex.clearing.control.repository; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import ru.spcex.clearing.control.mapper.ResultContainerMapper; +import ru.spcex.clearing.control.model.ResultContainer; + +@Repository +public class ControlRepository { + private final JdbcTemplate jdbcTemplate; + private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; + private final ResultContainerMapper resultContainerMapper; + + public ControlRepository(JdbcTemplate jdbcTemplate, + NamedParameterJdbcTemplate namedParameterJdbcTemplate, + ResultContainerMapper resultContainerMapper) { + this.jdbcTemplate = jdbcTemplate; + this.namedParameterJdbcTemplate = namedParameterJdbcTemplate; + this.resultContainerMapper = resultContainerMapper; + } + + @Transactional + public ResultContainer getFinlCountDiff() { + String sqlQuery = """ + WITH s_trades_count AS (SELECT COUNT(*) FROM s_trades), + execution_deposit_count AS (SELECT COUNT(*) FROM execution_deposit) + SELECT (SELECT * FROM s_trades_count) AS first_table, + (SELECT * FROM execution_deposit_count) AS second_table, + (SELECT s_trades_count.count - execution_deposit_count.count) AS diff + FROM s_trades_count, + execution_deposit_count; + """; + return jdbcTemplate.queryForObject(sqlQuery, resultContainerMapper); + } + + @Transactional + public ResultContainer getIpoTrdCountDiff() { + String sqlQuery = """ + WITH s_trades_fond_count AS (SELECT COUNT(*) FROM s_trades WHERE section = 'FOND'), + execution_fond_count AS (SELECT COUNT(*) FROM execution_fond) + SELECT (SELECT * FROM s_trades_fond_count) AS first_table, + (SELECT * FROM execution_fond_count) AS second_table, + (SELECT s_trades_fond_count.count - execution_fond_count.count) AS diff + FROM s_trades_fond_count, + execution_fond_count; + """; + return jdbcTemplate.queryForObject(sqlQuery, resultContainerMapper); + } + + @Transactional + public ResultContainer getCurrInitCountDiff() { + String sqlQuery = """ + WITH s_trades_curr_count AS (SELECT COUNT(*) FROM s_trades WHERE section = 'CURR'), + execution_currency_count AS (SELECT COUNT(*) FROM execution_currency) + SELECT (SELECT * FROM s_trades_curr_count) AS first_table, + (SELECT * FROM execution_currency_count) AS second_table, + (SELECT s_trades_curr_count.count - execution_currency_count.count) AS diff + FROM s_trades_curr_count, + execution_currency_count; + """; + return jdbcTemplate.queryForObject(sqlQuery, resultContainerMapper); + } + + @Transactional + public ResultContainer getInternalCountDiff(Long sessionId) { + return new ResultContainer(1L, 2L, 3L); + } + + @Transactional + public ResultContainer getFinlInternalCountDiff(Long sessionId) { + String sqlQuery = """ + WITH payment_instruction_ids AS (SELECT id FROM payment_instruction WHERE session_id = :sessionId), + s_df03_ids AS (SELECT s_df03.id + FROM payment_instruction_ids + LEFT JOIN s_df03 ON payment_instruction_ids.id = s_df03.payment_instruction_id), + payment_instruction_count AS (SELECT COUNT(*) FROM payment_instruction_ids), + s_df03_count AS (SELECT COUNT(*) FROM s_df03_ids) + SELECT (SELECT payment_instruction_count.count FROM payment_instruction_count) AS first_table, + (SELECT s_df03_count.count FROM s_df03_count) AS second_table, + (SELECT payment_instruction_count.count - s_df03_count.count) AS diff + FROM payment_instruction_count, + s_df03_count; + """; + return namedParameterJdbcTemplate.queryForObject(sqlQuery, + new MapSqlParameterSource("sessionId", sessionId), + resultContainerMapper); + } +} diff --git a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/service/ControlService.java b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/service/ControlService.java new file mode 100644 index 000000000..a16223bcb --- /dev/null +++ b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/service/ControlService.java @@ -0,0 +1,97 @@ +package ru.spcex.clearing.control.service; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.time.Instant; +import org.springframework.stereotype.Service; +import ru.spcex.clearing.control.config.settings.ControlServiceSettings; +import ru.spcex.clearing.control.model.ResultContainer; +import ru.spcex.clearing.control.repository.ControlRepository; +import ru.spcex.platform.enumeration.SessionType; +import ru.spcex.platform.utils.collection.Pair; + +@Service +public class ControlService { + private final ControlRepository controlRepository; + private final ControlServiceSettings settings; + private final Path resultDirectory; + + public ControlService(ControlRepository controlRepository, + ControlServiceSettings settings) { + this.controlRepository = controlRepository; + this.settings = settings; + resultDirectory = Path.of(settings.getResultDirectory()); + } + + public String generalControl(SessionType sessionType) { + Pair tables; + ResultContainer resultContainer; + + if (sessionType.equals(SessionType.FINL)) { + tables = new Pair<>("sTrade", "executionDeposit"); + resultContainer = controlRepository.getFinlCountDiff(); + } else if (sessionType.equals(SessionType.IPOB) || sessionType.equals(SessionType.IPOT) || sessionType.equals(SessionType.IPO0) || sessionType.equals(SessionType.TRDT)) { + tables = new Pair<>("sTradeFond", "executionFond"); + resultContainer = controlRepository.getIpoTrdCountDiff(); + } else if (sessionType.equals(SessionType.CURR)) { + tables = new Pair<>("sTradeCurrency", "executionCurrency"); + resultContainer = controlRepository.getCurrInitCountDiff(); + } else { + throw new IllegalStateException("Unexpected value: " + sessionType); + } + + if (resultContainer.difference() != 0) { + writeToCsvFile(sessionType, resultContainer, tables); + } + + return resultContainer.toString(); + } + + public String internalControl(Long sessionId) { + ResultContainer resultContainer = controlRepository.getInternalCountDiff(sessionId); + + if (resultContainer.difference() != 0) { + writeToCsvFileInternal(sessionId, resultContainer); + } + + return resultContainer.toString(); + } + + public String internalControlFinl(Long sessionId) { + ResultContainer resultContainer = controlRepository.getFinlInternalCountDiff(sessionId); + + if (resultContainer.difference() != 0) { + writeToCsvFileInternal(sessionId, resultContainer); + } + + return resultContainer.toString(); + } + + private void writeToCsvFile(SessionType sessionType, ResultContainer resultContainer, Pair tables) { + try (PrintWriter printWriter = new PrintWriter(new FileWriter(resultDirectory.resolve("result-" + sessionType.name() + "-" + Instant.now().getEpochSecond() + ".csv").toFile()))) { + printWriter.printf("session_type,%s,%s,diff%n", tables.getFirst(), tables.getSecond()); + printWriter.printf("%s,%s,%s,%s%n", + sessionType.name(), + resultContainer.firstTable(), + resultContainer.secondTable(), + resultContainer.difference()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void writeToCsvFileInternal(Long sessionId, ResultContainer resultContainer) { + try (PrintWriter printWriter = new PrintWriter(new FileWriter(resultDirectory.resolve("result-internal-" + sessionId + "-" + Instant.now().getEpochSecond() + ".csv").toFile()))) { + printWriter.println("session_id,paymentInstruction,s_df03,diff"); + printWriter.printf("%s,%s,%s,%s%n", + sessionId, + resultContainer.firstTable(), + resultContainer.secondTable(), + resultContainer.difference()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/clearing-parent/control-service/src/main/resources/application.properties b/clearing-parent/control-service/src/main/resources/application.properties new file mode 100644 index 000000000..7e62ee8b0 --- /dev/null +++ b/clearing-parent/control-service/src/main/resources/application.properties @@ -0,0 +1,7 @@ +# Database settings +control-service.database.username=clearing +control-service.database.password=Aa111111 +control-service.database.url=jdbc:postgresql://localhost:5433/clearing + +# Result directory +control-service.result-directory=C:\\Users\\ivan\\Desktop\\result diff --git a/clearing-parent/control-service/src/main/resources/logback.xml b/clearing-parent/control-service/src/main/resources/logback.xml new file mode 100644 index 000000000..84be3d48c --- /dev/null +++ b/clearing-parent/control-service/src/main/resources/logback.xml @@ -0,0 +1,56 @@ + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + utf-8 + + + + + ${LOG_PATH}/${FILE_NAME}-text.log + + + ${FILE_LOG_PATTERN} + utf8 + + + ${LOG_PATH}/${FILE_NAME}-text.%d{yyyy-MM-dd}.%i.gz + + + 100MB + + 10 + + + + + ${LOG_PATH}/${FILE_NAME}-json.log + + + ${LOG_PATH}/${FILE_NAME}-json.%d{yyyy-MM-dd}.%i.gz + + + 100MB + + 10 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/clearing-parent/pom.xml b/clearing-parent/pom.xml index 1537daa9f..899a8047d 100644 --- a/clearing-parent/pom.xml +++ b/clearing-parent/pom.xml @@ -45,6 +45,7 @@ imdg-hist xml-importer xml-exporter + control-service diff --git a/pom.xml b/pom.xml index 2ad22450c..afabeeab2 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,7 @@ ${folder_root_clearing}/clearing-parent/gateway-api ${folder_root_clearing}/clearing-parent/xml-exporter ${folder_root_clearing}/clearing-parent/xml-importer + ${folder_root_clearing}/clearing-parent/control-service 3.12.4 1.7.33 diff --git a/z-distr/pom.xml b/z-distr/pom.xml index e6234289d..f2b7581b1 100644 --- a/z-distr/pom.xml +++ b/z-distr/pom.xml @@ -614,6 +614,29 @@ + + copy-control-service-bin + prepare-package + + copy + + + + + ${folder_root_control-service}/target/control-service.jar + ${folder.clearing.distr.bin}/control-service.jar + + + ${folder_root_control-service}/target/control-service.jar + ${folder.clearing.distr.services}/control-service/control-service.jar + + + ${folder_root_control-service}/src/main/resources/application.properties + ${folder.clearing.distr.settings}/control-service/application.properties + + + + diff --git a/z-distr/src/main/resources/distr/sh/control-service.sh b/z-distr/src/main/resources/distr/sh/control-service.sh new file mode 100644 index 000000000..51e19ca41 --- /dev/null +++ b/z-distr/src/main/resources/distr/sh/control-service.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +CLEARING_HOME=/opt/mfd/clearing/ +cd $CLEARING_HOME/bin + +CMD="java -jar control-service.jar --spring.config.location=$CLEARING_HOME/settings/control-service/" + +$CMD >/dev/null 2>&1 & +