Compare commits

..

11 commits

140 changed files with 1050 additions and 4611 deletions

View file

@ -1,23 +0,0 @@
FROM eclipse-temurin:17-jre-alpine
MAINTAINER ru.nbch
VOLUME /opt/app/logs/app
VOLUME /opt/app/logs/json
VOLUME /opt/app/logs/access
VOLUME /opt/app/reports
WORKDIR /opt/app
COPY maven/elastic-apm-agent-1.45.0.jar /opt/app/elastic-apm-agent.jar
COPY maven/credit-tracker.jar /opt/app/credit-tracker.jar
COPY maven/start-credit-tracker.sh /opt/app/start-credit-tracker.sh
COPY maven/credit-tracker.properties /opt/app/credit-tracker.properties
COPY maven/monitoring-request.xsd /opt/app/monitoring-request.xsd
COPY maven/signal-package.xsd /opt/app/signal-package.xsd
COPY maven/ca_nbki.cer /usr/local/share/ca-certificates/corp.crt
RUN apk add --no-cache ca-certificates \
&& update-ca-certificates \
RUN apk add gcompat bash
RUN chmod +x /opt/app/start-credit-tracker.sh
ENTRYPOINT ["/opt/app/start-credit-tracker.sh"]

View file

@ -1,33 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFpTCCA42gAwIBAgIQXRfulgQYrrRFEpmSkmctvzANBgkqhkiG9w0BAQsFADBH
MRMwEQYKCZImiZPyLGQBGRYDbXNrMRQwEgYKCZImiZPyLGQBGRYEbmJraTEaMBgG
A1UEAxMRTkJLSS1Sb290LUNBLTIwMzIwHhcNMTQwNTE1MDYxODMzWhcNMzcwMjAx
MTE1OTEyWjBHMRMwEQYKCZImiZPyLGQBGRYDbXNrMRQwEgYKCZImiZPyLGQBGRYE
bmJraTEaMBgGA1UEAxMRTkJLSS1Sb290LUNBLTIwMzIwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQCjS1l6kx+tjX2PGmQcVw9wg0Q6SCeWbiz7rxAYZPqE
OGckXWWjtfUOc8BhD3+BnC4BQ414X1HP2OWQ97pa2LogTksbpNpJ0+p82IPAYxV+
zpI0FnW09FpzjtB6l/1kE9gKecjBoFG3xDhhFmpzCeK7tsKt94j84XPV/Zo82gYM
egmqhOfQZ+2HAChBj7gaBJALybFN34wkvN9bWdBPmK/j1jQikEAT8QE9qwcdmCKB
snHw+heYX4uJyZEkXEzW8GxQfTaAL+3d8HdRm1ZT/dN9KScF3Tp13LnQPCcixYoB
dF9Pd3P8JDAQX1KUVceLq6e75Q36EQaHHfEA8iQjaKlEzD049QbfAfCzKkSTnxHk
rOGwhm/h3ipwdAL4eqWkXfRriEvQU2fXGYXS0bhDT0/vBVAhHUMZ15/Oww0QSlc9
clpau6rYG4m/Fmm8LPyEHROenbNwu35TqLl+CUFES25aE2oZcH6+SyE5dDgpX9e1
Plt3fT6DuEDuT+rWvm0N8NVPNlQP/1lcbvP1oQrby07LToPatdKF9V5g8MX/19bP
BFsQsUHLlfffWMqqX8W/OPt5da3XL6U7Z8aBdhS7VAqqrvNhAbJBxgyJAzSfSwtZ
K5dZTKrJMZqmosUSIrLVr+9oXlbqJjKGNWQjwCfRQmPPkCpmpy1SRg8NPDoa3OVU
3wIDAQABo4GMMIGJMBMGCSsGAQQBgjcUAgQGHgQAQwBBMAsGA1UdDwQEAwIBhjAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSkqLxdQSQ2+UIWrqSnms7lhp5zLjAQ
BgkrBgEEAYI3FQEEAwIBATAjBgkrBgEEAYI3FQIEFgQUvM7jX4RA4XBrZqhNhpl6
EDcEMZEwDQYJKoZIhvcNAQELBQADggIBAINqzWxlGXFgMwSlWmH4ocDa0A3ip51C
nEaWB58aomzOZYHnNLXj4KiwY59TMDkiRiql4wWCw2AJBVv2//7JwOqrk8rixq02
95NVX9TNefMKY3oo/g9bSqEsxoHgOoXP0QiY4GrYwAL6Bl0d/V9KUw5+BzBx/DKo
ncWD6KHnwFPBnHhIWiFlRAy2dX55rg6YSpB5/IlTQxGTjeg0OjX5w0ZE3L/0GZBl
O5W2E0RvUSErbjzoisxrhG48Mo5TtoGTmazKHRDqRCuZVnV0uEL9XaUOOV3G+LlP
/ujADUkF4iiIgoynB0W30fpwEqQFBSUxe+KzMw10ojaYaSz2g/HEg9ZKxy1a/bDL
6Va+vUMrypg26+MFrEdUwpPuORV1chtah/t+OxSk1dO82cuhjmRHX79mRwqjmXUs
5I/fNey8JWLCAV+Acf24CepdeYzeBGdh94t9FqTWw7aJaN5vL9ghwyG7JT8ozAfp
wYa1vq3nq+7SiELenQYYEUl792V8OsRV6N9nJkoLC12R9HGHjxMja5O2+Sw9LU4p
TjQcJt+qhT/c5+i6tQMjJUCTpXtOkaEezwrPpbUcoluGsz9vxs84eDtHiwumUCGj
XgaMSjcnY35dgne/x3kXcLYazdUYDoyYOEkgKG7ncSFg0lnIgwtYpqW6tzL3t9KN
Tsm6UcBOJAnv
-----END CERTIFICATE-----

View file

@ -1,72 +1,38 @@
server.port=${SERVER_PORT:8099} server.port=8099
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.directory=/opt/app/logs/access
server.tomcat.accesslog.prefix=access_log
server.tomcat.accesslog.suffix=.log
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b
# datasources # datasources
# indic # indic
ct.indic-data-source-settings.driver=com.ibm.db2.jcc.DB2Driver ct.indic-data-source-settings.driver=com.ibm.db2.jcc.DB2Driver
ct.indic-data-source-settings.url=${DB_URL_INDIC:jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=INDIC;} ct.indic-data-source-settings.url=jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=INDIC;
ct.indic-data-source-settings.username=${USERNAME_INDIC:tester} ct.indic-data-source-settings.username=tester
ct.indic-data-source-settings.password=${PASSWORD_INDIC:tester} ct.indic-data-source-settings.password=tester
ct.indic-data-source-settings.maximum-pool-size=${MAXIMUM_POOL_SIZE_INDIC:10}
ct.indic-data-source-settings.minimum-idle=${MINIMUM_IDLE_INDIC:10}
ct.indic-data-source-settings.connection-timeout=${CONNECTION_TIMEOUT_INDIC:10000}
ct.indic-data-source-settings.validation-timeout=${VALIDATION_TIMEOUT_INDIC:5000}
ct.indic-data-source-settings.idle-timeout=${IDLE_TIMEOUT_INDIC:600000}
ct.indic-data-source-settings.max-lifetime=${MAX_LIFETIME_INDIC:1800000}
ct.indic-data-source-settings.keepalive-time=${KEEPALIVE_TIME_INDIC:0}
ct.indic-data-source-settings.leak-detection-threshold=${LEAK_DETECTION_THRESHOLD_INDIC:0}
# signal # signal
ct.signal-data-source-settings.driver=org.postgresql.Driver ct.signal-data-source-settings.driver=org.postgresql.Driver
ct.signal-data-source-settings.url=${DB_URL_SIGNAL:jdbc:postgresql://10.200.200.133:5432/credit_tracker} ct.signal-data-source-settings.url=jdbc:postgresql://10.200.200.133:5432/credit_tracker
ct.signal-data-source-settings.username=${USERNAME_SIGNAL:credit_tracker_user} ct.signal-data-source-settings.username=credit_tracker_user
ct.signal-data-source-settings.password=${PASSWORD_SIGNAL:-} ct.signal-data-source-settings.password=
ct.signal-data-source-settings.maximum-pool-size=${MAXIMUM_POOL_SIZE_SIGNAL:10}
ct.signal-data-source-settings.minimum-idle=${MINIMUM_IDLE_SIGNAL:10}
ct.signal-data-source-settings.connection-timeout=${CONNECTION_TIMEOUT_SIGNAL:10000}
ct.signal-data-source-settings.validation-timeout=${VALIDATION_TIMEOUT_SIGNAL:5000}
ct.signal-data-source-settings.idle-timeout=${IDLE_TIMEOUT_SIGNAL:600000}
ct.signal-data-source-settings.max-lifetime=${MAX_LIFETIME_SIGNAL:1800000}
ct.signal-data-source-settings.keepalive-time=${KEEPALIVE_TIME_SIGNAL:0}
ct.signal-data-source-settings.leak-detection-threshold=${LEAK_DETECTION_THRESHOLD_SIGNAL:0}
# scoring # scoring
ct.scoring-data-source-settings.driver=com.ibm.db2.jcc.DB2Driver ct.scoring-data-source-settings.driver=com.ibm.db2.jcc.DB2Driver
ct.scoring-data-source-settings.url=${DB_URL_SCORING:jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=TEST_2_INDIC;} ct.scoring-data-source-settings.url=jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=TEST_2_INDIC;
ct.scoring-data-source-settings.username=${USERNAME_SCORING:tester} ct.scoring-data-source-settings.username=tester
ct.scoring-data-source-settings.password=${PASSWORD_SCORING:tester} ct.scoring-data-source-settings.password=tester
ct.scoring-data-source-settings.maximum-pool-size=${MAXIMUM_POOL_SIZE_SCORING:10}
ct.scoring-data-source-settings.minimum-idle=${MINIMUM_IDLE_SCORING:10}
ct.scoring-data-source-settings.connection-timeout=${CONNECTION_TIMEOUT_SCORING:10000}
ct.scoring-data-source-settings.validation-timeout=${VALIDATION_TIMEOUT_SCORING:5000}
ct.scoring-data-source-settings.idle-timeout=${IDLE_TIMEOUT_SCORING:600000}
ct.scoring-data-source-settings.max-lifetime=${MAX_LIFETIME_SCORING:1800000}
ct.scoring-data-source-settings.keepalive-time=${KEEPALIVE_TIME_SCORING:0}
ct.scoring-data-source-settings.leak-detection-threshold=${LEAK_DETECTION_THRESHOLD_SCORING:0}
ct.max_xml_file_size=${ACCEPTED_XML_SIZE:1024} spring.servlet.multipart.max-file-size=2048MB
spring.servlet.multipart.max-file-size=${ACCEPTED_ARCHIVE_SIZE:2048MB} spring.servlet.multipart.max-request-size=2048MB
spring.servlet.multipart.max-request-size=${ACCEPTED_ARCHIVE_SIZE:2048MB}
# xsd paths # xsd paths
ct.xsd-validation.monitoring-request-path=monitoring-request.xsd ct.xsd-validation.monitoring-request-path=monitoring-request.xsd
ct.xsd-validation.signal-package-path=signal-package.xsd ct.xsd-validation.signal-package-path=signal-package.xsd
ct.signals-root-uri=${SIGNALS_ROOT_URI:http://10.230.227.102:11094/signalRUalfa/} ct.signals-root-uri=http://10.230.227.102:11094/signalRUalfa/
ct.signals-token=${SIGNALS_TOKEN:gttcHxwcGojoAvZK} ct.signals-token=gttcHxwcGojoAvZK
ct.signals-user=${SIGNALS_USER:0001ZZ000001} ct.signals-user=0001ZZ000001
ct.load-dir=/opt/app/reports
#ct.load-dir=D:\\folder_name\\signals
ct.load-dir=D:\\folder_name\\signals
# min # min
ct.monitoring-interval=${MONITORING_INTERVAL:15} ct.monitoring-interval=15
# days # days
ct.update-flags-cron-expression=${UPDATE_FLAGS_CRON_EXPRESSION:0 0 22 * * *} ct.update-flags-interval=1
ct.days-to-update-flags=${DAYS_TO_UPDATE_FLAGS:30} ct.days-to-update-flags=30
ct.encoding=windows-1251

View file

@ -1,77 +0,0 @@
#commons
APP_VERSION=1.24
REGISTRY_URL=rh8-vm3.nbki.msk:5000
JMX_PORT=
JMX_HOSTNAME=
#volumes
REPORT_DIR=D:\folder_name\signals
LOGS_DIR=D:\folder_name\signals\logs\app
JSON_LOGS_DIR=D:\folder_name\signals\logs\json
ACCESS_LOGS_DIR=D:\folder_name\signals\logs\access
#APM settings
APM_SERVICE_NAME=credit-tracker
APM_SERVER_URLS=test
APM_ENVIRONMENT=test
APM_SERVICE_NODE_NAME=test
HOST_PORT=8081
SERVER_PORT=8099
# datasources
# indic
DB_URL_INDIC=jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=INDIC;
USERNAME_INDIC=tester
PASSWORD_INDIC=tester
MAXIMUM_POOL_SIZE_INDIC=10
MINIMUM_IDLE_INDIC=10
CONNECTION_TIMEOUT_INDIC=10000
VALIDATION_TIMEOUT_INDIC=5000
IDLE_TIMEOUT_INDIC=600000
MAX_LIFETIME_INDIC=1800000
KEEPALIVE_TIME_INDIC=0
LEAK_DETECTION_THRESHOLD_INDIC=0
# signal
DB_URL_SIGNAL=jdbc:postgresql://10.200.200.133:5432/credit_tracker
USERNAME_SIGNAL=credit_tracker_user
PASSWORD_SIGNAL=
MAXIMUM_POOL_SIZE_SIGNAL=10
MINIMUM_IDLE_SIGNAL=10
CONNECTION_TIMEOUT_SIGNAL=10000
VALIDATION_TIMEOUT_SIGNAL=5000
IDLE_TIMEOUT_SIGNAL=600000
MAX_LIFETIME_SIGNAL=1800000
KEEPALIVE_TIME_SIGNAL=0
LEAK_DETECTION_THRESHOLD_SIGNAL=0
# scoring
DB_URL_SCORING=jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=TEST_2_INDIC;
USERNAME_SCORING=tester
PASSWORD_SCORING=tester
MAXIMUM_POOL_SIZE_SCORING=10
MINIMUM_IDLE_SCORING=10
CONNECTION_TIMEOUT_SCORING=10000
VALIDATION_TIMEOUT_SCORING=5000
IDLE_TIMEOUT_SCORING=600000
MAX_LIFETIME_SCORING=1800000
KEEPALIVE_TIME_SCORING=0
LEAK_DETECTION_THRESHOLD_SCORING=0
# размер в mb
ACCEPTED_XML_SIZE=1024
ACCEPTED_ARCHIVE_SIZE=2048MB
SIGNALS_ROOT_URI=http://10.230.227.102:11094/signalRUalfa/
SIGNALS_TOKEN=gttcHxwcGojoAvZK
SIGNALS_USER=0001ZZ000001
# min
MONITORING_INTERVAL=15
# days
UPDATE_FLAGS_CRON_EXPRESSION=0 22 * * *
DAYS_TO_UPDATE_FLAGS=30

View file

@ -1,63 +0,0 @@
services:
credit-tracker:
image: ${REGISTRY_URL}/credit-tracker:${APP_VERSION}
container_name: credit-tracker
restart: always
volumes:
- ${LOGS_DIR}:/opt/app/logs/app
- ${JSON_LOGS_DIR}:/opt/app/logs/json
- ${REPORT_DIR}:/opt/app/reports
- ${ACCESS_LOGS_DIR}:/opt/app/logs/access
ports:
- "${HOST_PORT}:${SERVER_PORT}"
environment:
- TZ=Europe/Moscow
- APM_SERVICE_NAME=${APM_SERVICE_NAME}
- APM_SERVER_URLS=${APM_SERVER_URLS}
- APM_ENVIRONMENT=${APM_ENVIRONMENT}
- APM_SERVICE_NODE_NAME=${APM_SERVICE_NODE_NAME}
- APM_SERVICE_VERSION=${APP_VERSION}
- JMX_PORT=${JMX_PORT}
- JMX_HOSTNAME=${JMX_HOSTNAME}
- SERVER_PORT=${SERVER_PORT}
- DB_URL_INDIC=${DB_URL_INDIC}
- USERNAME_INDIC=${USERNAME_INDIC}
- PASSWORD_INDIC=${PASSWORD_INDIC}
- MAXIMUM_POOL_SIZE_INDIC=${MAXIMUM_POOL_SIZE_INDIC}
- MINIMUM_IDLE_INDIC=${MINIMUM_IDLE_INDIC}
- CONNECTION_TIMEOUT_INDIC=${CONNECTION_TIMEOUT_INDIC}
- VALIDATION_TIMEOUT_INDIC=${VALIDATION_TIMEOUT_INDIC}
- IDLE_TIMEOUT_INDIC=${IDLE_TIMEOUT_INDIC}
- MAX_LIFETIME_INDIC=${MAX_LIFETIME_INDIC}
- KEEPALIVE_TIME_INDIC=${KEEPALIVE_TIME_INDIC}
- LEAK_DETECTION_THRESHOLD_INDIC=${LEAK_DETECTION_THRESHOLD_INDIC}
- DB_URL_SIGNAL=${DB_URL_SIGNAL}
- USERNAME_SIGNAL=${USERNAME_SIGNAL}
- PASSWORD_SIGNAL=${PASSWORD_SIGNAL}
- MAXIMUM_POOL_SIZE_SIGNAL=${MAXIMUM_POOL_SIZE_SIGNAL}
- MINIMUM_IDLE_SIGNAL=${MINIMUM_IDLE_SIGNAL}
- CONNECTION_TIMEOUT_SIGNAL=${CONNECTION_TIMEOUT_SIGNAL}
- VALIDATION_TIMEOUT_SIGNAL=${VALIDATION_TIMEOUT_SIGNAL}
- IDLE_TIMEOUT_SIGNAL=${IDLE_TIMEOUT_SIGNAL}
- MAX_LIFETIME_SIGNAL=${MAX_LIFETIME_SIGNAL}
- KEEPALIVE_TIME_SIGNAL=${KEEPALIVE_TIME_SIGNAL}
- LEAK_DETECTION_THRESHOLD_SIGNAL=${LEAK_DETECTION_THRESHOLD_SIGNAL}
- DB_URL_SCORING=${DB_URL_SCORING}
- USERNAME_SCORING=${USERNAME_SCORING}
- PASSWORD_SCORING=${PASSWORD_SCORING}
- MAXIMUM_POOL_SIZE_SCORING=${MAXIMUM_POOL_SIZE_SCORING}
- MINIMUM_IDLE_SCORING=${MINIMUM_IDLE_SCORING}
- CONNECTION_TIMEOUT_SCORING=${CONNECTION_TIMEOUT_SCORING}
- VALIDATION_TIMEOUT_SCORING=${VALIDATION_TIMEOUT_SCORING}
- IDLE_TIMEOUT_SCORING=${IDLE_TIMEOUT_SCORING}
- MAX_LIFETIME_SCORING=${MAX_LIFETIME_SCORING}
- KEEPALIVE_TIME_SCORING=${KEEPALIVE_TIME_SCORING}
- LEAK_DETECTION_THRESHOLD_SCORING=${LEAK_DETECTION_THRESHOLD_SCORING}
- ACCEPTED_XML_SIZE=${ACCEPTED_XML_SIZE}
- ACCEPTED_ARCHIVE_SIZE=${ACCEPTED_ARCHIVE_SIZE}
- SIGNALS_ROOT_URI=${SIGNALS_ROOT_URI}
- SIGNALS_TOKEN=${SIGNALS_TOKEN}
- SIGNALS_USER=${SIGNALS_USER}
- MONITORING_INTERVAL=${MONITORING_INTERVAL}
- UPDATE_FLAGS_INTERVAL=${UPDATE_FLAGS_INTERVAL}
- DAYS_TO_UPDATE_FLAGS=${DAYS_TO_UPDATE_FLAGS}

431
pom.xml
View file

@ -1,275 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.6</version> <version>3.4.6</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<groupId>ru.nbch</groupId> <groupId>ru.nbch</groupId>
<artifactId>credit-tracker</artifactId> <artifactId>credit_tracker</artifactId>
<version>1.24</version> <version>1.0</version>
<name>credit_tracker</name> <name>credit_tracker</name>
<description>Credit Tracker Application</description> <description>Credit Tracker Application</description>
<properties> <properties>
<java.version>17</java.version> <java.version>17</java.version>
<git.info.prefix>git_info</git.info.prefix> <git.info.prefix>git_info</git.info.prefix>
<git.info.filename>git.properties</git.info.filename> <git.info.filename>git.properties</git.info.filename>
<registry.url>10.230.238.56:5000</registry.url> </properties>
<!-- <registry.url>rh8-vm3.nbki.msk:5000</registry.url>-->
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.mybatis.spring.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId> <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency> <version>3.0.4</version>
<dependency> </dependency>
<groupId>org.mybatis.spring.boot</groupId> <dependency>
<artifactId>mybatis-spring-boot-starter</artifactId> <groupId>org.postgresql</groupId>
<version>3.0.4</version> <artifactId>postgresql</artifactId>
</dependency> <scope>runtime</scope>
<dependency> </dependency>
<groupId>org.postgresql</groupId> <dependency>
<artifactId>postgresql</artifactId> <groupId>com.ibm.db2</groupId>
<scope>runtime</scope> <artifactId>jcc</artifactId>
</dependency> <version>12.1.0.0</version>
<dependency> </dependency>
<groupId>com.ibm.db2</groupId> <dependency>
<artifactId>jcc</artifactId> <groupId>org.projectlombok</groupId>
<version>12.1.0.0</version> <artifactId>lombok</artifactId>
</dependency> <optional>true</optional>
<dependency> </dependency>
<groupId>org.projectlombok</groupId> <dependency>
<artifactId>lombok</artifactId> <groupId>org.slf4j</groupId>
<optional>true</optional> <artifactId>slf4j-api</artifactId>
</dependency> <version>2.0.7</version>
<dependency> </dependency>
<groupId>org.slf4j</groupId> <dependency>
<artifactId>slf4j-api</artifactId> <groupId>ch.qos.logback</groupId>
<version>2.0.7</version> <artifactId>logback-classic</artifactId>
</dependency> <version>1.4.12</version>
<dependency> <exclusions>
<groupId>ch.qos.logback</groupId> <exclusion>
<artifactId>logback-classic</artifactId> <groupId>ch.qos.logback</groupId>
<version>1.4.12</version> <artifactId>logback-core</artifactId>
<exclusions> </exclusion>
<exclusion> </exclusions>
<groupId>ch.qos.logback</groupId> </dependency>
<artifactId>logback-core</artifactId> <dependency>
</exclusion> <groupId>ch.qos.logback</groupId>
</exclusions> <artifactId>logback-core</artifactId>
</dependency> <version>1.5.12</version>
<dependency> </dependency>
<groupId>ch.qos.logback</groupId> <dependency>
<artifactId>logback-core</artifactId> <groupId>org.apache.commons</groupId>
<version>1.5.12</version> <artifactId>commons-lang3</artifactId>
</dependency> <version>3.17.0</version>
<dependency> </dependency>
<groupId>org.apache.commons</groupId> <dependency>
<artifactId>commons-lang3</artifactId> <groupId>commons-io</groupId>
<version>3.17.0</version> <artifactId>commons-io</artifactId>
</dependency> <version>2.18.0</version>
<dependency> </dependency>
<groupId>commons-io</groupId> <!-- JAXB API -->
<artifactId>commons-io</artifactId> <dependency>
<version>2.18.0</version> <groupId>jakarta.xml.bind</groupId>
</dependency> <artifactId>jakarta.xml.bind-api</artifactId>
<!-- JAXB API --> <version>4.0.2</version>
<dependency> </dependency>
<groupId>jakarta.xml.bind</groupId> <!--JAXB runtime implementation: eclipse moxy-->
<artifactId>jakarta.xml.bind-api</artifactId> <dependency>
<version>4.0.2</version> <groupId>org.eclipse.persistence</groupId>
</dependency> <artifactId>org.eclipse.persistence.moxy</artifactId>
<!--JAXB runtime implementation: eclipse moxy--> <version>4.0.2</version>
<dependency> </dependency>
<groupId>org.eclipse.persistence</groupId> <!-- Activation dependency needed for JAXB -->
<artifactId>org.eclipse.persistence.moxy</artifactId> <dependency>
<version>4.0.2</version> <groupId>com.sun.activation</groupId>
</dependency> <artifactId>jakarta.activation</artifactId>
<!-- Activation dependency needed for JAXB --> <version>2.0.1</version>
<dependency> </dependency>
<groupId>com.sun.activation</groupId> <dependency>
<artifactId>jakarta.activation</artifactId> <groupId>org.springframework.boot</groupId>
<version>2.0.1</version> <artifactId>spring-boot-starter-test</artifactId>
</dependency> <scope>test</scope>
<dependency> </dependency>
<groupId>co.elastic.apm</groupId> <dependency>
<artifactId>apm-agent-api</artifactId> <groupId>org.mybatis.spring.boot</groupId>
<version>1.43.0</version> <artifactId>mybatis-spring-boot-starter-test</artifactId>
</dependency> <version>3.0.4</version>
<dependency> <scope>test</scope>
<groupId>com.internetitem</groupId> </dependency>
<artifactId>logback-elasticsearch-appender</artifactId> </dependencies>
<version>1.6</version>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>3.0.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<profiles> <build>
<profile> <finalName>credit-tracker</finalName>
<id>docker-push-dev</id> <plugins>
<build> <plugin>
<plugins> <groupId>pl.project13.maven</groupId>
<plugin> <artifactId>git-commit-id-plugin</artifactId>
<groupId>io.fabric8</groupId> <version>4.9.10</version>
<artifactId>docker-maven-plugin</artifactId> <executions>
<version>0.45.0</version> <execution>
<executions> <id>get-the-git-infos</id>
<execution> <goals>
<id>Build and deploy docker container</id> <goal>revision</goal>
<phase>install</phase> </goals>
<goals> <phase>compile</phase>
<goal>build</goal> </execution>
<goal>push</goal> </executions>
</goals> <configuration>
</execution> <failOnNoGitDirectory>false</failOnNoGitDirectory>
</executions> <dotGitDirectory>${project.basedir}/${git.info.relative.dir}</dotGitDirectory>
<configuration> <generateGitPropertiesFile>true</generateGitPropertiesFile>
<images> <generateGitPropertiesFilename>
<image> ${project.build.outputDirectory}/${git.info.filename}
<name>${project.artifactId}:${project.version}</name> </generateGitPropertiesFilename>
<registry>${registry.url}</registry> <prefix>${git.info.prefix}</prefix>
<build> <includeOnlyProperties>
<dockerFile>${project.basedir}/Dockerfile</dockerFile> <includeOnlyProperty>${git.info.prefix}.commit.id</includeOnlyProperty>
<assembly> <includeOnlyProperty>${git.info.prefix}.branch</includeOnlyProperty>
<inline> <includeOnlyProperty>${git.info.prefix}.build.version</includeOnlyProperty>
<files> <includeOnlyProperty>${git.info.prefix}.build.time</includeOnlyProperty>
<file> <includeOnlyProperty>${git.info.prefix}.closest.tag.name</includeOnlyProperty>
<source> </includeOnlyProperties>
${project.build.directory}/${project.build.finalName}.jar </configuration>
</source> </plugin>
<outputDirectory>.</outputDirectory> <plugin>
</file> <groupId>org.apache.maven.plugins</groupId>
<file> <artifactId>maven-compiler-plugin</artifactId>
<source> <configuration>
${project.basedir}/apm-agent/elastic-apm-agent-1.45.0.jar <annotationProcessorPaths>
</source> <path>
<outputDirectory>.</outputDirectory> <groupId>org.projectlombok</groupId>
</file> <artifactId>lombok</artifactId>
<file> </path>
<source>${project.basedir}/start-credit-tracker.sh</source> </annotationProcessorPaths>
<outputDirectory>.</outputDirectory> </configuration>
</file> </plugin>
<file> <plugin>
<source>${project.basedir}/credit-tracker.properties</source> <groupId>org.springframework.boot</groupId>
<outputDirectory>.</outputDirectory> <artifactId>spring-boot-maven-plugin</artifactId>
</file> <configuration>
<file> <excludes>
<source>${project.basedir}/monitoring-request.xsd</source> <exclude>
<outputDirectory>.</outputDirectory> <groupId>org.projectlombok</groupId>
</file> <artifactId>lombok</artifactId>
<file> </exclude>
<source>${project.basedir}/signal-package.xsd</source> </excludes>
<outputDirectory>.</outputDirectory> </configuration>
</file> </plugin>
<file> </plugins>
<source> </build>
${project.basedir}/ca_nbki.cer
</source>
<outputDirectory>.</outputDirectory>
</file>
</files>
</inline>
</assembly>
<tags>
<tag>${project.version}</tag>
</tags>
</build>
</image>
</images>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<finalName>credit-tracker</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>4.9.10</version>
<executions>
<execution>
<id>get-the-git-infos</id>
<goals>
<goal>revision</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<failOnNoGitDirectory>false</failOnNoGitDirectory>
<dotGitDirectory>${project.basedir}/${git.info.relative.dir}</dotGitDirectory>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>
${project.build.outputDirectory}/${git.info.filename}
</generateGitPropertiesFilename>
<prefix>${git.info.prefix}</prefix>
<includeOnlyProperties>
<includeOnlyProperty>${git.info.prefix}.commit.id</includeOnlyProperty>
<includeOnlyProperty>${git.info.prefix}.branch</includeOnlyProperty>
<includeOnlyProperty>${git.info.prefix}.build.version</includeOnlyProperty>
<includeOnlyProperty>${git.info.prefix}.build.time</includeOnlyProperty>
<includeOnlyProperty>${git.info.prefix}.closest.tag.name</includeOnlyProperty>
</includeOnlyProperties>
</configuration>
</plugin>
</plugins>
</build>
</project> </project>

View file

@ -4,7 +4,6 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import ru.nbch.credit_tracker.service.MonitoringService; import ru.nbch.credit_tracker.service.MonitoringService;
import ru.nbch.credit_tracker.service.UpdateProcessingPackagesService;
import ru.nbch.credit_tracker.service.UpdatingFlagsService; import ru.nbch.credit_tracker.service.UpdatingFlagsService;
@SpringBootApplication @SpringBootApplication
@ -12,12 +11,10 @@ public class CreditTrackerApplication {
public static void main(String[] args) { public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(CreditTrackerApplication.class, args); ConfigurableApplicationContext ctx = SpringApplication.run(CreditTrackerApplication.class, args);
UpdateProcessingPackagesService updateProcessingPackagesService = ctx.getBean(UpdateProcessingPackagesService.class);
MonitoringService monitoringService = ctx.getBean(MonitoringService.class); MonitoringService monitoringService = ctx.getBean(MonitoringService.class);
UpdatingFlagsService updatingFlagsService = ctx.getBean(UpdatingFlagsService.class); UpdatingFlagsService updatingFlagsService = ctx.getBean(UpdatingFlagsService.class);
monitoringService.run(); monitoringService.run();
updatingFlagsService.run(); updatingFlagsService.run();
updateProcessingPackagesService.run();
} }
} }

View file

@ -1,17 +1,16 @@
package ru.nbch.credit_tracker.builder; package ru.nbch.credit_tracker.builder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import ru.nbch.credit_tracker.entities.external_request.signals.Person; import ru.nbch.credit_tracker.entities.signal_package.Person;
import ru.nbch.credit_tracker.service.indic.PersonService; import ru.nbch.credit_tracker.service.indic.PersonService;
import ru.nbch.credit_tracker.utils.CTUtil; import ru.nbch.credit_tracker.utils.CTUtil;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@Slf4j
public class PersonFactoryBuilder { public class PersonFactoryBuilder {
private final static DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("dd.MM.yyyy"); private final static DateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy");
private final static String DEFAULT_DATE = "01.01.2000"; private final static String DEFAULT_DATE = "01.01.2000";
private final static String IP = "0"; private final static String IP = "0";
@ -25,12 +24,10 @@ public class PersonFactoryBuilder {
private final static String CONSENT_HASH = "hash"; private final static String CONSENT_HASH = "hash";
private final static String CONSENT_DIV_CODE = "000-000"; private final static String CONSENT_DIV_CODE = "000-000";
private final static String INQ_PURPOSE = "16"; private final static String INQ_PURPOSE = "16";
private final static String ODT = "Иной документ";
private final static String CONSENT_ISSUE_AUTHORITY = "Кем выдан";
private PersonService.PersonData personData; private PersonService.PersonData personData;
private Long uid; private String uid;
public static PersonFactoryBuilder builder() { public static PersonFactoryBuilder builder() {
return new PersonFactoryBuilder(); return new PersonFactoryBuilder();
@ -41,7 +38,7 @@ public class PersonFactoryBuilder {
return this; return this;
} }
public PersonFactoryBuilder uid(Long uid) { public PersonFactoryBuilder uid(String uid) {
this.uid = uid; this.uid = uid;
return this; return this;
} }
@ -56,24 +53,20 @@ public class PersonFactoryBuilder {
person.setS(nameData.getLastName()); person.setS(nameData.getLastName());
person.setN(nameData.getFirstName()); person.setN(nameData.getFirstName());
person.setM(StringUtils.isNotBlank(nameData.getMiddleName()) ? nameData.getMiddleName() : null); person.setM(StringUtils.isNotBlank(nameData.getMiddleName()) ? nameData.getMiddleName() : null);
person.setD(DATE_FORMAT.format(nameData.getBirthDate())); person.setD(DATE_FORMAT.format(CTUtil.localDatetoDate(nameData.getBirthDate())));
person.setPn(getPn(passportData.getSerNum(), passportData.getIdNum())); person.setPn(getPn(passportData.getSerNum(), passportData.getIdNum()));
person.setPd(DATE_FORMAT.format(LocalDate.now())); // Do not use passport iss_date. Signal service could reject the package person.setPd(passportData.getIssDate() != null ? DATE_FORMAT.format(CTUtil.localDatetoDate(passportData.getIssDate())) : DEFAULT_DATE);
person.setDt(getDt(passportData.getIdType(), passportData.getIdType2())); person.setDt(StringUtils.isNotBlank(passportData.getIdType2()) ? passportData.getIdType2() : passportData.getIdType());
if (person.getDt() != null && person.getDt().equals("999")) {
person.setOdt(ODT);
person.setConsentOdt(ODT);
}
person.setIp(IP); person.setIp(IP);
person.setUid(uid); person.setUid(uid);
person.setOksm(OKSM); person.setOksm(OKSM);
person.setConsentDate(DATE_FORMAT.format(LocalDate.now())); person.setConsentDate(DATE_FORMAT.format(CTUtil.localDatetoDate(LocalDate.now())));
person.setConsentPurpose(CONSENT_PURPOSE); person.setConsentPurpose(CONSENT_PURPOSE);
person.setReportUser(REPORT_USER); person.setReportUser(REPORT_USER);
person.setLiability(LIABILITY); person.setLiability(LIABILITY);
person.setConsentPeriod(CONSENT_PERIOD); person.setConsentPeriod(CONSENT_PERIOD);
person.setAgrDate(DATE_FORMAT.format(LocalDate.now())); person.setAgrDate(DATE_FORMAT.format(CTUtil.localDatetoDate(LocalDate.now())));
person.setReportUserRegNum(REPORT_USER_REG_NUM); person.setReportUserRegNum(REPORT_USER_REG_NUM);
person.setReportUserTaxID(REPORT_USER_TAX_ID); person.setReportUserTaxID(REPORT_USER_TAX_ID);
person.setConsentHash(CONSENT_HASH); person.setConsentHash(CONSENT_HASH);
@ -86,7 +79,6 @@ public class PersonFactoryBuilder {
person.setConsentPd(person.getPd()); person.setConsentPd(person.getPd());
person.setConsentDivCode(CONSENT_DIV_CODE); person.setConsentDivCode(CONSENT_DIV_CODE);
person.setConsentDt(person.getDt()); person.setConsentDt(person.getDt());
person.setConsentIssueAuthority(CONSENT_ISSUE_AUTHORITY);
person.setInqPurpose(INQ_PURPOSE); person.setInqPurpose(INQ_PURPOSE);
return person; return person;
} }
@ -96,29 +88,4 @@ public class PersonFactoryBuilder {
String normIdNum = CTUtil.normalize(idNum); String normIdNum = CTUtil.normalize(idNum);
return StringUtils.isNotBlank(normSerNum) ? normSerNum + normIdNum : normIdNum; return StringUtils.isNotBlank(normSerNum) ? normSerNum + normIdNum : normIdNum;
} }
private String getDt(String idType, String idType2) {
if (StringUtils.isNotBlank(idType2)) {
return idType2;
} else {
return switch (idType) {
case "21" -> "21";
case "22" -> "22.1";
case "09" -> "22.2";
case "26" -> "23";
case "04" -> "24";
case "07" -> "25";
case "14", "03" -> "27";
case "10" -> "31";
case "15" -> "32";
case "13" -> "37";
case "06", "27" -> "28";
case "01", "02" -> "999";
default -> {
log.warn("ID_TYPE2 is blank and no matching found for ID_TYPE {}", idType);
yield "";
}
};
}
}
} }

View file

@ -1,28 +0,0 @@
package ru.nbch.credit_tracker.component;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Slf4j
@Component
public class MapperTimingAspect {
@Around("within(@org.apache.ibatis.annotations.Mapper *)")
public Object timeMapper(ProceedingJoinPoint pjp) throws Throwable {
long start = System.nanoTime();
try {
return pjp.proceed();
} finally {
long tookMs = (System.nanoTime() - start) / 1_000_000;
String method = pjp.getSignature().toShortString();
if (tookMs > 1000) {
log.warn("Slow mapper call {} took {} ms", method, tookMs);
} else {
log.debug("Mapper call {} took {} ms", method, tookMs);
}
}
}
}

View file

@ -1,19 +0,0 @@
package ru.nbch.credit_tracker.config.datasource;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.jdbc.DataSourceBuilder;
import ru.nbch.credit_tracker.config.settings.DataSourceSettings;
public class DatabaseConfig {
protected HikariDataSource createDataSource(DataSourceSettings settings) {
return DataSourceBuilder.create()
.driverClassName(settings.driver())
.url(settings.url())
.username(settings.username())
.password(settings.password())
.type(HikariDataSource.class)
.build();
}
}

View file

@ -7,11 +7,11 @@ import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.config.settings.DataSourceSettings;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.sql.Connection; import java.sql.Connection;
@ -23,32 +23,26 @@ import java.sql.SQLException;
basePackages = "ru.nbch.credit_tracker.mapper.indic", basePackages = "ru.nbch.credit_tracker.mapper.indic",
sqlSessionFactoryRef = "sqlSessionIndic" sqlSessionFactoryRef = "sqlSessionIndic"
) )
public class IndicDataSourceConfig extends DatabaseConfig { public class IndicDataSourceConfig {
@Value("classpath:mybatis/mapper/indic/*.xml") @Value("classpath:mybatis/mapper/indic/*.xml")
private Resource[] resources; private Resource[] resources;
@Bean(name = "indicDataSource") @Bean(name = "indicDataSource")
public DataSource dataSource(CreditTrackerSettings config) throws SQLException { public DataSource dataSource(CreditTrackerSettings config) throws SQLException {
DataSourceSettings indicSetings = config.getIndicDataSourceSettings(); DataSourceBuilder<HikariDataSource> dataSourceBuilder = (DataSourceBuilder<HikariDataSource>) DataSourceBuilder.create();
dataSourceBuilder.driverClassName(config.getIndicDataSourceSettings().driver());
HikariDataSource dataSource = createDataSource(indicSetings); dataSourceBuilder.url(config.getIndicDataSourceSettings().url());
dataSource.setMaximumPoolSize(indicSetings.maximumPoolSize()); dataSourceBuilder.username(config.getIndicDataSourceSettings().username());
dataSource.setMinimumIdle(indicSetings.minimumIdle()); dataSourceBuilder.password(config.getIndicDataSourceSettings().password());
dataSource.setConnectionTimeout(indicSetings.connectionTimeout()); HikariDataSource dataSource = dataSourceBuilder.build();
dataSource.setValidationTimeout(indicSetings.validationTimeout());
dataSource.setIdleTimeout(indicSetings.idleTimeout());
dataSource.setMaxLifetime(indicSetings.maxLifetime());
dataSource.setKeepaliveTime(indicSetings.keepaliveTime());
dataSource.setLeakDetectionThreshold(indicSetings.leakDetectionThreshold());
try (Connection connection = dataSource.getConnection()) { try (Connection connection = dataSource.getConnection()) {
connection.isValid(3); connection.isValid(3);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unable to connect to Indic url={}", indicSetings.url(), e); log.error("Unable to connect to Indic url={}", config.getIndicDataSourceSettings().url(), e);
throw e; throw e;
} }
log.info("Connected to Indic: url={}", indicSetings.url()); log.info("Connected to Indic: url={}", config.getIndicDataSourceSettings().url());
return dataSource; return dataSource;
} }

View file

@ -7,48 +7,41 @@ import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.config.settings.DataSourceSettings;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
@Slf4j @Slf4j
@Configuration @Configuration
@MapperScan( @MapperScan(
basePackages = "ru.nbch.credit_tracker.mapper.scoring", basePackages = "ru.nbch.credit_tracker.mapper.scoring",
sqlSessionFactoryRef = "sqlSessionScoring" sqlSessionFactoryRef = "sqlSessionScoring"
) )
public class ScoringDataSourceConfig extends DatabaseConfig { public class ScoringDataSourceConfig {
@Value("classpath:mybatis/mapper/scoring/*.xml") @Value("classpath:mybatis/mapper/scoring/*.xml")
private Resource[] resources; private Resource[] resources;
@Bean(name = "scoringDataSource") @Bean(name = "scoringDataSource")
public DataSource dataSource(CreditTrackerSettings config) throws SQLException { public DataSource dataSource(CreditTrackerSettings config) throws SQLException {
DataSourceSettings scoringSetings = config.getScoringDataSourceSettings(); DataSourceBuilder<HikariDataSource> dataSourceBuilder = (DataSourceBuilder<HikariDataSource>) DataSourceBuilder.create();
dataSourceBuilder.driverClassName(config.getScoringDataSourceSettings().driver());
HikariDataSource dataSource = createDataSource(scoringSetings); dataSourceBuilder.url(config.getScoringDataSourceSettings().url());
dataSource.setMaximumPoolSize(scoringSetings.maximumPoolSize()); dataSourceBuilder.username(config.getScoringDataSourceSettings().username());
dataSource.setMinimumIdle(scoringSetings.minimumIdle()); dataSourceBuilder.password(config.getScoringDataSourceSettings().password());
dataSource.setConnectionTimeout(scoringSetings.connectionTimeout()); HikariDataSource dataSource = dataSourceBuilder.build();
dataSource.setValidationTimeout(scoringSetings.validationTimeout());
dataSource.setIdleTimeout(scoringSetings.idleTimeout());
dataSource.setMaxLifetime(scoringSetings.maxLifetime());
dataSource.setKeepaliveTime(scoringSetings.keepaliveTime());
dataSource.setLeakDetectionThreshold(scoringSetings.leakDetectionThreshold());
try (Connection connection = dataSource.getConnection()) { try (Connection connection = dataSource.getConnection()) {
connection.isValid(3); connection.isValid(3);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unable to connect to Scoring url={}", scoringSetings.url(), e); log.error("Unable to connect to Scoring url={}", config.getScoringDataSourceSettings().url(), e);
throw e; throw e;
} }
log.info("Connected to Scoring: url={}", scoringSetings.url()); log.info("Connected to Scoring: url={}", config.getScoringDataSourceSettings().url());
return dataSource; return dataSource;
} }

View file

@ -7,11 +7,11 @@ import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.config.settings.DataSourceSettings;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.sql.Connection; import java.sql.Connection;
@ -23,31 +23,25 @@ import java.sql.SQLException;
basePackages = "ru.nbch.credit_tracker.mapper.signal", basePackages = "ru.nbch.credit_tracker.mapper.signal",
sqlSessionFactoryRef = "sqlSessionSignal" sqlSessionFactoryRef = "sqlSessionSignal"
) )
public class SignalDataSourceConfig extends DatabaseConfig { public class SignalDataSourceConfig {
@Value("classpath:mybatis/mapper/signal/*.xml") @Value("classpath:mybatis/mapper/signal/*.xml")
private Resource[] resources; private Resource[] resources;
@Bean(name = "signalDataSource") @Bean(name = "signalDataSource")
public DataSource dataSource(CreditTrackerSettings config) throws SQLException { public DataSource dataSource(CreditTrackerSettings config) throws SQLException {
DataSourceSettings signalSetings = config.getSignalDataSourceSettings(); DataSourceBuilder<HikariDataSource> dataSourceBuilder = (DataSourceBuilder<HikariDataSource>) DataSourceBuilder.create();
dataSourceBuilder.driverClassName(config.getSignalDataSourceSettings().driver());
HikariDataSource dataSource = createDataSource(signalSetings); dataSourceBuilder.url(config.getSignalDataSourceSettings().url());
dataSource.setMaximumPoolSize(signalSetings.maximumPoolSize()); dataSourceBuilder.username(config.getSignalDataSourceSettings().username());
dataSource.setMinimumIdle(signalSetings.minimumIdle()); // dataSourceBuilder.password(config.getSignalDataSourceSettings().password()); TODO uncomment whe password will be set
dataSource.setConnectionTimeout(signalSetings.connectionTimeout()); HikariDataSource dataSource = dataSourceBuilder.build();
dataSource.setValidationTimeout(signalSetings.validationTimeout());
dataSource.setIdleTimeout(signalSetings.idleTimeout());
dataSource.setMaxLifetime(signalSetings.maxLifetime());
dataSource.setKeepaliveTime(signalSetings.keepaliveTime());
dataSource.setLeakDetectionThreshold(signalSetings.leakDetectionThreshold());
try (Connection connection = dataSource.getConnection()) { try (Connection connection = dataSource.getConnection()) {
connection.isValid(3); connection.isValid(3);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unable to connect to Signal url={}", signalSetings.url(), e); log.error("Unable to connect to Signal url={}", config.getSignalDataSourceSettings().url(), e);
throw e; throw e;
} }
log.info("Connected to Signal: url={}", signalSetings.url()); log.info("Connected to Signal: url={}", config.getSignalDataSourceSettings().url());
return dataSource; return dataSource;
} }

View file

@ -1,19 +0,0 @@
package ru.nbch.credit_tracker.config.mdc;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ConditionalOnClass(Aspect.class)
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopMdcConfig {
@Bean
public MdcAspect mdcAspect() {
return new MdcAspect();
}
}

View file

@ -1,49 +0,0 @@
package ru.nbch.credit_tracker.config.mdc;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.MDC;
import ru.nbch.credit_tracker.entities.dto.UserPackage;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
@Slf4j
@Aspect
public class MdcAspect {
// For methods that set an MDC value (from a method argument) and then clear it at the end
@Around("@annotation(setAndClearMdc)")
public Object setAndClearMdcAdvice(ProceedingJoinPoint pjp, SetAndClearMdc setAndClearMdc) throws Throwable {
Object[] args = pjp.getArgs();
int index = setAndClearMdc.argIndex();
Object obj = (args != null && args.length > index) ? args[index] : null;
if (obj instanceof MonitoringRequest request) {
if (request.getPackageName() != null) {
putMdcValue(setAndClearMdc.key(), request.getPackageName());
}
} else if (obj instanceof UserPackage userPackage) {
if (userPackage.getPackageName() != null) {
putMdcValue(setAndClearMdc.key(), userPackage.getPackageName());
}
} else if (obj instanceof String packageName) {
putMdcValue(setAndClearMdc.key(), packageName);
} else {
log.debug("no packageName found for for {}", pjp.toShortString());
}
try {
return pjp.proceed();
} finally {
MDC.remove(setAndClearMdc.key());
}
}
private void putMdcValue(String key, String value) {
try {
MDC.put(key, "[" + value + "] ");
} catch (Throwable e) {
log.error("{}", ExceptionUtils.getStackTrace(e));
}
}
}

View file

@ -1,15 +0,0 @@
package ru.nbch.credit_tracker.config.mdc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// Annotation to set an MDC key based on a method argument and clear it after method execution
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SetAndClearMdc {
String key() default "ru.nbch.credit_tracker.log.mdc.key";
// The index of the method argument to use for the MDC value (defaults to the first argument)
int argIndex() default 0;
}

View file

@ -1,70 +1,35 @@
package ru.nbch.credit_tracker.config.rest; package ru.nbch.credit_tracker.config.rest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException; import ru.nbch.credit_tracker.entities.response.errors.*;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.user_response.errors.*;
import ru.nbch.credit_tracker.enums.SignalError;
import ru.nbch.credit_tracker.exceptions.SignalClientException; import ru.nbch.credit_tracker.exceptions.SignalClientException;
import ru.nbch.credit_tracker.exceptions.SignalException; import ru.nbch.credit_tracker.exceptions.SignalException;
import ru.nbch.credit_tracker.exceptions.SignalServerException;
import ru.nbch.credit_tracker.utils.error.SimpleMessageResolver; import ru.nbch.credit_tracker.utils.error.SimpleMessageResolver;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@Slf4j
@RestControllerAdvice @RestControllerAdvice
public class GlobalExceptionHandler { public class GlobalExceptionHandler {
private final SimpleMessageResolver messageResolver = new SimpleMessageResolver(); private final SimpleMessageResolver messageResolver = new SimpleMessageResolver();
private final String encoding;
public GlobalExceptionHandler(CreditTrackerSettings settings) {
this.encoding = settings.getEncoding();
}
@ExceptionHandler(value = MaxUploadSizeExceededException.class, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<MonitoringError> handleMaxUploadSizeExceeded(MaxUploadSizeExceededException ex) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "xml", Charset.forName(encoding)));
MonitoringError error = new MonitoringError();
error.setStatus("error");
error.setErrorCode(SignalError.ERROR_009.getCode());
error.setErrorText(SignalError.ERROR_009.getKey());
return new ResponseEntity<>(error, headers, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(value = SignalException.class, produces = MediaType.APPLICATION_XML_VALUE) @ExceptionHandler(value = SignalException.class, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<CommonError> handleClientException(SignalException ex) { public ResponseEntity<CommonError> handleClientException(SignalException ex) {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "xml", Charset.forName(encoding))); headers.setContentType(new MediaType("application", "xml", Charset.forName("windows-1251")));
String errorText = messageResolver.resolve(ex.getErrorMessage());
CommonError commonError = getCommonError(ex); CommonError commonError = getCommonError(ex);
commonError.setStatus("error"); commonError.setStatus("error");
commonError.setErrorCode(ex.getErrorMessage().getSubject().getCode()); commonError.setErrorCode(ex.getErrorMessage().getSubject().getErrorCode());
commonError.setErrorText(errorText); commonError.setErrorText(messageResolver.resolve(ex.getErrorMessage()));
if (ex instanceof SignalClientException) { if (ex instanceof SignalClientException) {
String packageName = ((SignalClientException) ex).getPackageName();
if(packageName != null ) {
log.warn("Response error: {}. PackageName: {}", errorText, packageName);
} else {
log.warn("Response error: {}", errorText);
}
return new ResponseEntity<>(commonError, headers, HttpStatus.BAD_REQUEST); return new ResponseEntity<>(commonError, headers, HttpStatus.BAD_REQUEST);
} else { } else {
Exception cause = ((SignalServerException) ex).getCause();
log.error(cause.getMessage(), cause);
return new ResponseEntity<>(commonError, headers, HttpStatus.INTERNAL_SERVER_ERROR); return new ResponseEntity<>(commonError, headers, HttpStatus.INTERNAL_SERVER_ERROR);
} }
} }
@ -74,7 +39,6 @@ public class GlobalExceptionHandler {
switch (ex.getErrorFormat()) { switch (ex.getErrorFormat()) {
case MonitoringError -> commonError = new MonitoringError(); case MonitoringError -> commonError = new MonitoringError();
case MonitoringActivePackagesError -> commonError = new MonitoringActivePackagesError(); case MonitoringActivePackagesError -> commonError = new MonitoringActivePackagesError();
case MonitoringAllPackagesError -> commonError = new MonitoringAllPackagesError();
case MonitoringDownloadError -> commonError = new MonitoringDownloadError(); case MonitoringDownloadError -> commonError = new MonitoringDownloadError();
case MonitoringReportListError -> commonError = new MonitoringReportListError(); case MonitoringReportListError -> commonError = new MonitoringReportListError();
case MonitoringPackageDeleteError -> commonError = new MonitoringPackageDeleteError(); case MonitoringPackageDeleteError -> commonError = new MonitoringPackageDeleteError();

View file

@ -2,7 +2,6 @@ package ru.nbch.credit_tracker.config.rest;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
@ -22,6 +21,6 @@ public class RestConfig {
@Bean(name = "executorService") @Bean(name = "executorService")
public ExecutorService executorService() { public ExecutorService executorService() {
return Executors.newCachedThreadPool(new CustomizableThreadFactory("package-registration-")); return Executors.newCachedThreadPool();
} }
} }

View file

@ -1,132 +0,0 @@
package ru.nbch.credit_tracker.config.rest.filters;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
@Component
@Slf4j
@Order(0)
public class HttpLoggingFilter extends OncePerRequestFilter {
private static final Set<String> SENSITIVE_HEADERS = Set.of("authorization", "cookie", "set-cookie");
private static final int MAX_BODY = 10 * 1024;
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String path = request.getRequestURI();
return path.startsWith("/actuator/health") || path.startsWith("/swagger")
|| path.startsWith("/v3/api-docs") || path.startsWith("/static/") || path.equals("/");
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
long startNs = System.nanoTime();
ContentCachingRequestWrapper req = wrapRequest(request);
ContentCachingResponseWrapper resp = new ContentCachingResponseWrapper(response);
String correlationId = Optional.ofNullable(request.getHeader("X-Correlation-Id"))
.filter(StringUtils::hasText)
.orElse(UUID.randomUUID().toString());
resp.setHeader("X-Correlation-Id", correlationId);
logIncomingRequest(req, correlationId);
try {
chain.doFilter(req, resp);
} finally {
long tookMs = (System.nanoTime() - startNs) / 1_000_000;
Map<String, String> reqParams = paramsMap(req);
Map<String, String> reqHeaders = headersMap(req);
Map<String, String> respHeaders = headersMap(resp);
mask(reqHeaders);
mask(respHeaders);
log.info(
"HTTP (RESPONSE) {} {} | status={} | took={}ms | cid={} | reqHeaders={} | reqParams={} | respHeaders={}",
req.getMethod(),
req.getRequestURI(),
resp.getStatus(),
tookMs,
correlationId,
reqHeaders,
reqParams,
respHeaders
);
resp.copyBodyToResponse();
}
}
private void logIncomingRequest(ContentCachingRequestWrapper req, String correlationId) {
Map<String, String> reqParams = paramsMap(req);
Map<String, String> reqHeaders = headersMap(req);
mask(reqHeaders);
log.info(
"HTTP (REQUEST) {} {} | cid={} | reqHeaders={} | reqParams={}",
req.getMethod(),
req.getRequestURI(),
correlationId,
reqHeaders,
reqParams
);
}
private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) throws IOException {
return (request instanceof ContentCachingRequestWrapper c) ? c : new ContentCachingRequestWrapper(request, MAX_BODY);
}
private static Map<String, String> headersMap(HttpServletRequest req) {
return Collections.list(req.getHeaderNames()).stream()
.collect(Collectors.toMap(h -> h, req::getHeader, (a, b) -> a, LinkedHashMap::new));
}
private static Map<String, String> paramsMap(HttpServletRequestWrapper req) {
Map<String, String> paramsMap = new LinkedHashMap<>();
req.getParameterMap().forEach((k, v) -> {
String params = String.join(", ", v);
paramsMap.put(k, params);
});
try {
Collection<Part> fileParts = req.getParts();
fileParts.forEach(part -> {
paramsMap.put(part.getName(), part.getSubmittedFileName());
});
} catch (Exception e) {
// ignore
}
return paramsMap;
}
private static Map<String, String> headersMap(HttpServletResponse resp) {
return resp.getHeaderNames().stream()
.collect(Collectors.toMap(h -> h, resp::getHeader, (a, b) -> a, LinkedHashMap::new));
}
private static void mask(Map<String, String> headers) {
headers.replaceAll((k, v) -> SENSITIVE_HEADERS.contains(k.toLowerCase()) ? "***" : v);
}
}

View file

@ -1,55 +0,0 @@
package ru.nbch.credit_tracker.config.rest.filters;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import ru.nbch.credit_tracker.config.rest.wrappers.CachedHttpRequestWrapper;
import java.io.IOException;
@Component
@Slf4j
@Order(1)
public class MemberCodeHttpLoggingFilter extends OncePerRequestFilter {
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String path = request.getRequestURI();
return !(path.startsWith("/api/v1/signal/all_packages") || path.startsWith("/api/v1/signal/active_packages"));
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
CachedHttpRequestWrapper req = wrapRequest(request);
String body = IOUtils.toString(req.getBody(), req.getCharacterEncoding());
if (StringUtils.isNotBlank(body)) {
try {
int startIndex = body.indexOf("<UserId>") + 8;
int endIndex = body.indexOf("</UserId>");
String userId = body.substring(startIndex, endIndex);
log.info(
"HTTP (REQUEST) {} {} | memberCode={}",
req.getMethod(),
req.getRequestURI(),
userId.substring(0, 6)
);
} catch (Exception e) {
// ignore
}
}
filterChain.doFilter(req, response);
}
private static CachedHttpRequestWrapper wrapRequest(HttpServletRequest request) throws IOException {
return new CachedHttpRequestWrapper(request);
}
}

View file

@ -1,25 +0,0 @@
package ru.nbch.credit_tracker.config.rest.wrappers;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.Getter;
import java.io.IOException;
@Getter
public class CachedHttpRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public CachedHttpRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.body = request.getInputStream().readAllBytes();
}
@Override
public ServletInputStream getInputStream() {
return new CachedServletInputStream(body);
}
}

View file

@ -1,33 +0,0 @@
package ru.nbch.credit_tracker.config.rest.wrappers;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import java.io.ByteArrayInputStream;
public class CachedServletInputStream extends ServletInputStream {
private final ByteArrayInputStream byteArray;
public CachedServletInputStream(byte[] data) {
this.byteArray = new ByteArrayInputStream(data);
}
public int read() {
return byteArray.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
}

View file

@ -26,11 +26,9 @@ public class CreditTrackerSettings {
private String signalsToken; private String signalsToken;
private String signalsuser; private String signalsuser;
private Long maxXmlFileSize;
private String loadDir; private String loadDir;
private Long monitoringInterval; private Long monitoringInterval;
private String updateFlagsCronExpression; private Long updateFlagsInterval;
private Long daysToUpdateFlags; private Long daysToUpdateFlags;
private String encoding;
} }

View file

@ -4,13 +4,5 @@ public record DataSourceSettings(
String username, String username,
String password, String password,
String url, String url,
String driver, String driver
Integer maximumPoolSize,
Integer minimumIdle,
long connectionTimeout,
long validationTimeout,
long idleTimeout,
long maxLifetime,
long keepaliveTime,
long leakDetectionThreshold
) {} ) {}

View file

@ -3,46 +3,45 @@ package ru.nbch.credit_tracker.config.xml;
import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.JAXBException;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest;
import ru.nbch.credit_tracker.entities.external_response.monitoring_report_file.SgnlReportMonitorigSetupError; import ru.nbch.credit_tracker.entities.response.errors.MonitoringError;
import ru.nbch.credit_tracker.entities.external_response.online_report.SgnlOnlineReport; import ru.nbch.credit_tracker.entities.response.monitoring_signal_response.MonitoringSignalResponse;
import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest; import ru.nbch.credit_tracker.entities.response.online_download.OnlineDownloadReport;
import ru.nbch.credit_tracker.entities.user_request.all_packages.MonitoringAllPackagesRequest; import ru.nbch.credit_tracker.entities.response.online_report.SgnlOnlineReport;
import ru.nbch.credit_tracker.entities.user_response.errors.MonitoringError; import ru.nbch.credit_tracker.entities.response.success.MonitoringResponse;
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse; import ru.nbch.credit_tracker.entities.signal_package.Signals;
import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor; import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor;
import ru.nbch.credit_tracker.service.xml.jaxb.XmlProcessorImplAnyClasses; import ru.nbch.credit_tracker.service.xml.jaxb.XmlProcessorImplAnyClasses;
import ru.nbch.credit_tracker.service.xml.stax.*; import ru.nbch.credit_tracker.service.xml.stax.SgnlReportStatusStaxReader;
import ru.nbch.credit_tracker.service.xml.stax.StaxReader;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
import ru.nbch.credit_tracker.service.xml.stax.XmlProcessorStaxImpl;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
@Configuration @Configuration
public class XmlConfig { public class XmlConfig {
@Bean @Bean
public IXmlProcessor xmlProcessor(CreditTrackerSettings settings) throws JAXBException { public IXmlProcessor xmlProcessor() throws JAXBException {
return new XmlProcessorImplAnyClasses(Charset.forName(settings.getEncoding()), return new XmlProcessorImplAnyClasses(Charset.forName("windows-1251"),
// unmarshalling classes // unmarshalling classes
MonitoringRequest.class,
OnlineDownloadReport.class,
SgnlOnlineReport.class, SgnlOnlineReport.class,
SgnlReportMonitorigSetupError.class,
MonitoringActivePackagesRequest.class,
MonitoringAllPackagesRequest.class,
// marshalling classes // marshalling classes
Signals.class,
MonitoringError.class, MonitoringError.class,
MonitoringSetupResponse.class); MonitoringResponse.class,
MonitoringSignalResponse.class);
} }
@Bean @Bean
public StaxXmlProcessor staxXmlProcessor() { public StaxXmlProcessor staxXmlProcessor() {
List<Supplier<StaxReader<?>>> staxReader = new ArrayList<>(); List<StaxReader<?>> staxReader = new ArrayList<>();
staxReader.add(SgnlReportStatusStaxReader::new); staxReader.add(new SgnlReportStatusStaxReader());
staxReader.add(MonitoringRequestStaxReader::new);
staxReader.add(OnlineDownloadReportPersonsStaxReader::new);
staxReader.add(MonitoringSignalResponseStaxXmlReader::new);
staxReader.add(MonitoringReportErrorsStaxtReader::new);
return new XmlProcessorStaxImpl(staxReader); return new XmlProcessorStaxImpl(staxReader);
} }
} }

View file

@ -5,13 +5,11 @@ import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest; import ru.nbch.credit_tracker.entities.request.active_packages.MonitoringActivePackagesRequest;
import ru.nbch.credit_tracker.entities.user_request.all_packages.MonitoringAllPackagesRequest; import ru.nbch.credit_tracker.entities.response.active_packages.MonitoringActivePackagesResponse;
import ru.nbch.credit_tracker.entities.user_response.active_packages.MonitoringActivePackagesResponse; import ru.nbch.credit_tracker.entities.response.success.MonitoringPackageDeleteResponse;
import ru.nbch.credit_tracker.entities.user_response.all_packages.MonitoringAllPackagesResponse; import ru.nbch.credit_tracker.entities.response.success.MonitoringReportListResponse;
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringPackageDeleteResponse; import ru.nbch.credit_tracker.entities.response.success.MonitoringResponse;
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringReportListResponse;
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse;
import ru.nbch.credit_tracker.facade.SignalFacade; import ru.nbch.credit_tracker.facade.SignalFacade;
@RestController @RestController
@ -25,7 +23,7 @@ public class SignalController {
} }
@PostMapping(value = "/set", produces = MediaType.APPLICATION_XML_VALUE) @PostMapping(value = "/set", produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<MonitoringSetupResponse> setupMonitoring(@RequestParam("file") MultipartFile file) { public ResponseEntity<MonitoringResponse> setupMonitoring(@RequestParam("file") MultipartFile file) {
return signalFacade.setupMonitoring(file); return signalFacade.setupMonitoring(file);
} }
@ -34,11 +32,6 @@ public class SignalController {
return signalFacade.findActivePackages(activePackagesRequest); return signalFacade.findActivePackages(activePackagesRequest);
} }
@PostMapping(value = "/all_packages", consumes = MediaType.APPLICATION_XML_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<MonitoringAllPackagesResponse> findAllPackages(@RequestBody MonitoringAllPackagesRequest allPackagesRequest) {
return signalFacade.findAllPackages(allPackagesRequest);
}
@PostMapping(value = "/delete", params = {"username", "packageName"}, produces = MediaType.APPLICATION_XML_VALUE) @PostMapping(value = "/delete", params = {"username", "packageName"}, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<MonitoringPackageDeleteResponse> deletePackage(@RequestParam("username") String username, @RequestParam("packageName") String packageName) { public ResponseEntity<MonitoringPackageDeleteResponse> deletePackage(@RequestParam("username") String username, @RequestParam("packageName") String packageName) {
return signalFacade.deletePackage(username, packageName); return signalFacade.deletePackage(username, packageName);

View file

@ -8,8 +8,8 @@ import java.time.LocalDateTime;
@Getter @Getter
@Setter @Setter
public class Hit { public class Hit {
private Long id; private Integer id;
private Long packageId; private Integer packageId;
private String subjectId; private String subjectId;
private Integer signalType; private Integer signalType;
private LocalDateTime responseSentAt; private LocalDateTime responseSentAt;

View file

@ -10,13 +10,12 @@ import java.time.LocalDateTime;
@NoArgsConstructor @NoArgsConstructor
@Builder @Builder
public class PhoneFidMap { public class PhoneFidMap {
private Long id; private Integer id;
private Long packageId; private Integer packageId;
private String subjectId; private String subjectId;
private String phone; private String phone;
private Integer fid; private Integer fid;
private Integer flagDebt5000; private Integer flagDebt5000;
private Integer flag90days; private Integer flag90days;
private LocalDateTime calculatedAt; private LocalDateTime calculatedAt;
private String errorText;
} }

View file

@ -10,12 +10,10 @@ import java.time.LocalDateTime;
@Setter @Setter
@Builder @Builder
public class UserPackage { public class UserPackage {
private Long id; private Integer id;
private String userId; private String userId;
private String packageName; private String packageName;
private LocalDateTime createdAt; private LocalDateTime createdAt;
private String status; private String status;
private LocalDateTime deactivatedAt;
private String lastDownloadedReport; private String lastDownloadedReport;
private LocalDateTime monitoringAt;
} }

View file

@ -1,72 +0,0 @@
package ru.nbch.credit_tracker.entities.external_response.monitoring_report_error;
import jakarta.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"id",
"version",
"user",
"reportCreated"
})
@XmlRootElement(name = "Errors")
public class MonitoringReportErrors {
@XmlElement(name = "Id")
protected String id;
@XmlElement(name = "Version")
protected String version;
@XmlElement(name = "User")
protected String user;
@XmlElement(name = "ReportCreated")
protected String reportCreated;
@XmlElement(name = "p")
protected List<P> persons;
public List<P> getPersons() {
if (persons == null) {
persons = new ArrayList<>();
}
return this.persons;
}
private P currentPerson;
public void createCurrentPerson() {
currentPerson = new P();
}
public P getCurrentPerson() {
return currentPerson;
}
public void finalizePerson() {
getPersons().add(currentPerson);
}
@Getter
@Setter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
})
public static class P {
@XmlAttribute(name = "uid")
protected Long uid;
@XmlValue
protected String value;
}
}

View file

@ -1,21 +0,0 @@
package ru.nbch.credit_tracker.entities.external_response.monitoring_report_file;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"filename"
})
public class ErrorsForNextReport {
@XmlElement(name = "filename", required = true)
protected String filename;
}

View file

@ -1,24 +0,0 @@
package ru.nbch.credit_tracker.entities.external_response.monitoring_report_file;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"memberCode",
"packCode"
})
public class InputParams {
@XmlElement(name = "memberCode", required = true)
protected String memberCode;
@XmlElement(name = "packCode", required = true)
protected String packCode;
}

View file

@ -1,20 +0,0 @@
package ru.nbch.credit_tracker.entities.external_response.monitoring_report_file;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"errorsForNextReport"
})
public class OperationReport {
@XmlElement(name = "ErrorsForNextReport")
protected ErrorsForNextReport errorsForNextReport;
}

View file

@ -1,22 +0,0 @@
package ru.nbch.credit_tracker.entities.external_response.monitoring_report_file;
import jakarta.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"inputParams",
"operationReport"
})
@XmlRootElement(name = "SgnlReport")
public class SgnlReportMonitorigSetupError {
@XmlElement(name = "InputParams", required = true)
protected InputParams inputParams;
@XmlElement(name = "OperationReport", required = true)
protected OperationReport operationReport;
}

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_request.active_packages; package ru.nbch.credit_tracker.entities.request.active_packages;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;

View file

@ -0,0 +1,31 @@
package ru.nbch.credit_tracker.entities.request.monitoring_request;
import jakarta.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"userId",
"password",
"packageName",
"subjects"
})
@XmlRootElement(name = "MonitoringRequest")
public class MonitoringRequest {
@XmlElement(name = "UserId", required = true)
protected String userId;
@XmlElement(name = "Password", required = true)
protected String password;
@XmlElement(name = "PackageName", required = true)
protected String packageName;
@XmlElement(name = "Subjects", required = true)
protected Subjects subjects;
}

View file

@ -1,5 +1,5 @@
package ru.nbch.credit_tracker.entities.user_request.monitoring_request; package ru.nbch.credit_tracker.entities.request.monitoring_request;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_request.monitoring_request; package ru.nbch.credit_tracker.entities.request.monitoring_request;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.active_packages; package ru.nbch.credit_tracker.entities.response.active_packages;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.active_packages; package ru.nbch.credit_tracker.entities.response.active_packages;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.active_packages; package ru.nbch.credit_tracker.entities.response.active_packages;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.errors; package ru.nbch.credit_tracker.entities.response.errors;
public interface CommonError { public interface CommonError {
void setStatus(String status); void setStatus(String status);

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.errors; package ru.nbch.credit_tracker.entities.response.errors;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.errors; package ru.nbch.credit_tracker.entities.response.errors;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;
@ -17,9 +17,9 @@ public class MonitoringDownloadError implements CommonError {
@XmlElement(name = "Status", required = true) @XmlElement(name = "Status", required = true)
protected String status; protected String status;
@XmlElement(name = "Code",required = true) @XmlElement(name = "ErrorCode",required = true)
protected String errorCode; protected String errorCode;
@XmlElement(name = "Message",required = true) @XmlElement(name = "ErrorText",required = true)
protected String errorText; protected String errorText;
} }

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.errors; package ru.nbch.credit_tracker.entities.response.errors;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.errors; package ru.nbch.credit_tracker.entities.response.errors;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.errors; package ru.nbch.credit_tracker.entities.response.errors;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;
@ -17,9 +17,9 @@ public class MonitoringReportListError implements CommonError {
@XmlElement(name = "Status", required = true) @XmlElement(name = "Status", required = true)
protected String status; protected String status;
@XmlElement(name = "Code",required = true) @XmlElement(name = "ErrorCode",required = true)
protected String errorCode; protected String errorCode;
@XmlElement(name = "Message",required = true) @XmlElement(name = "ErrorText",required = true)
protected String errorText; protected String errorText;
} }

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.errors; package ru.nbch.credit_tracker.entities.response.external_errors;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.errors; package ru.nbch.credit_tracker.entities.response.external_errors;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.errors; package ru.nbch.credit_tracker.entities.response.external_errors;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response; package ru.nbch.credit_tracker.entities.response.monitoring_signal_response;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;
@ -17,5 +17,5 @@ public class MonitoringSignalResponse {
@XmlElement(name = "PackageName", required = true) @XmlElement(name = "PackageName", required = true)
protected String packageName; protected String packageName;
@XmlElement(name = "Subjects", required = true) @XmlElement(name = "Subjects", required = true)
protected Subjects subjects = new Subjects(); protected Subjects subjects;
} }

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response; package ru.nbch.credit_tracker.entities.response.monitoring_signal_response;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response; package ru.nbch.credit_tracker.entities.response.monitoring_signal_response;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;
@ -24,17 +24,4 @@ public class Signals {
return this.signals; return this.signals;
} }
private Signal currentSignal;
public void createCurrentSignal() {
currentSignal = new Signal();
}
public Signal getCurrentSignal() {
return currentSignal;
}
public void finalizeSignal() {
getSignals().add(currentSignal);
}
} }

View file

@ -1,5 +1,5 @@
package ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response; package ru.nbch.credit_tracker.entities.response.monitoring_signal_response;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;
@ -30,7 +30,7 @@ public class Subject {
@XmlElement(name = "Flag90_12", required = true) @XmlElement(name = "Flag90_12", required = true)
protected Integer flag9012; protected Integer flag9012;
@XmlElement(name = "Signals", required = true) @XmlElement(name = "Signals", required = true)
protected Signals signals = new Signals(); protected Signals signals;
} }

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response; package ru.nbch.credit_tracker.entities.response.monitoring_signal_response;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;
@ -24,18 +24,4 @@ public class Subjects {
return this.subjects; return this.subjects;
} }
private Subject currentSubject;
public void createCurrentSubject() {
currentSubject = new Subject();
}
public Subject getCurrentSubject() {
return currentSubject;
}
public void finalizeSubject() {
getSubjects().add(currentSubject);
}
} }

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.online_download; package ru.nbch.credit_tracker.entities.response.online_download;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;
@ -42,18 +42,4 @@ public class Inquiry {
return this.signals; return this.signals;
} }
private Signal currentSignal;
public void createCurrentSignal() {
currentSignal = new Signal();
}
public Signal getCurrentSignal() {
return currentSignal;
}
public void finalizeSignal() {
getSignals().add(currentSignal);
}
} }

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.online_download; package ru.nbch.credit_tracker.entities.response.online_download;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.online_download; package ru.nbch.credit_tracker.entities.response.online_download;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;
@ -16,7 +16,7 @@ import java.util.List;
public class Person { public class Person {
@XmlAttribute(name = "uid", required = true) @XmlAttribute(name = "uid", required = true)
protected Long uid; protected String uid;
@XmlElement(name = "Inquiry", required = true) @XmlElement(name = "Inquiry", required = true)
protected List<Inquiry> inquiries; protected List<Inquiry> inquiries;
@ -27,18 +27,4 @@ public class Person {
} }
return this.inquiries; return this.inquiries;
} }
private Inquiry currentInquiry;
public void createCurrentInquiry() {
currentInquiry = new Inquiry();
}
public Inquiry getCurrentInquiry() {
return currentInquiry;
}
public void finalizeInquiry() {
getInquiries().add(currentInquiry);
}
} }

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.online_download; package ru.nbch.credit_tracker.entities.response.online_download;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;
@ -24,18 +24,5 @@ public class Persons {
return this.persons; return this.persons;
} }
private Person currentPerson;
public void createCurrentPerson() {
currentPerson = new Person();
}
public Person getCurrentPerson() {
return currentPerson;
}
public void finalizePerson() {
getPersons().add(currentPerson);
}
} }

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.online_download; package ru.nbch.credit_tracker.entities.response.online_download;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.online_report; package ru.nbch.credit_tracker.entities.response.online_report;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.online_report; package ru.nbch.credit_tracker.entities.response.online_report;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.online_report; package ru.nbch.credit_tracker.entities.response.online_report;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.online_report; package ru.nbch.credit_tracker.entities.response.online_report;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_response.online_report; package ru.nbch.credit_tracker.entities.response.online_report;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.success; package ru.nbch.credit_tracker.entities.response.success;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.success; package ru.nbch.credit_tracker.entities.response.success;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.user_response.success; package ru.nbch.credit_tracker.entities.response.success;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;
@ -11,7 +11,7 @@ import lombok.Setter;
"status", "status",
}) })
@XmlRootElement(name = "MonitoringResponse") @XmlRootElement(name = "MonitoringResponse")
public class MonitoringSetupResponse { public class MonitoringResponse {
@XmlElement(name = "Status", required = true) @XmlElement(name = "Status", required = true)
protected String status = "OK"; protected String status = "OK";

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_request.signals; package ru.nbch.credit_tracker.entities.signal_package;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_request.signals; package ru.nbch.credit_tracker.entities.signal_package;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_request.signals; package ru.nbch.credit_tracker.entities.signal_package;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;
@ -15,7 +15,7 @@ public class Person {
@XmlValue @XmlValue
protected String value; protected String value;
@XmlAttribute(name = "uid", required = true) @XmlAttribute(name = "uid", required = true)
protected Long uid; protected String uid;
@XmlAttribute(name = "oksm", required = true) @XmlAttribute(name = "oksm", required = true)
protected String oksm; protected String oksm;
@XmlAttribute(name = "s", required = true) @XmlAttribute(name = "s", required = true)
@ -34,8 +34,6 @@ public class Person {
protected String pd; protected String pd;
@XmlAttribute(name = "dt", required = true) @XmlAttribute(name = "dt", required = true)
protected String dt; protected String dt;
@XmlAttribute(name = "odt")
protected String odt;
@XmlAttribute(name = "ip", required = true) @XmlAttribute(name = "ip", required = true)
protected String ip; protected String ip;
@XmlAttribute(name = "consentDate") @XmlAttribute(name = "consentDate")
@ -75,10 +73,6 @@ public class Person {
protected String consentDivCode; protected String consentDivCode;
@XmlAttribute(name = "consentDt") @XmlAttribute(name = "consentDt")
protected String consentDt; protected String consentDt;
@XmlAttribute(name = "consentOdt")
protected String consentOdt;
@XmlAttribute(name = "consentIssueAuthority")
protected String consentIssueAuthority;
@XmlAttribute(name = "inqPurpose") @XmlAttribute(name = "inqPurpose")
protected String inqPurpose; protected String inqPurpose;

View file

@ -1,4 +1,4 @@
package ru.nbch.credit_tracker.entities.external_request.signals; package ru.nbch.credit_tracker.entities.signal_package;
import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAccessorType;

View file

@ -1,5 +1,5 @@
package ru.nbch.credit_tracker.entities.external_request.signals; package ru.nbch.credit_tracker.entities.signal_package;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.*;
import lombok.Getter; import lombok.Getter;
@ -25,8 +25,6 @@ public class Signals {
protected Conditions conditions; protected Conditions conditions;
@XmlAttribute(name = "online", required = true) @XmlAttribute(name = "online", required = true)
protected String online; protected String online;
@XmlAttribute(name = "processWithErrors", required = true)
protected String processWithErrors;
public Conditions getConditions() { public Conditions getConditions() {
if (conditions == null) { if (conditions == null) {

View file

@ -1,22 +0,0 @@
package ru.nbch.credit_tracker.entities.user_request.all_packages;
import jakarta.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"userId",
"password"
})
@XmlRootElement(name = "MonitoringAllPackagesRequest")
public class MonitoringAllPackagesRequest {
@XmlElement(name = "UserId", required = true)
protected String userId;
@XmlElement(name = "Password", required = true)
protected String password;
}

View file

@ -1,51 +0,0 @@
package ru.nbch.credit_tracker.entities.user_request.monitoring_request;
import jakarta.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"userId",
"password",
"packageName",
"subjects"
})
@XmlRootElement(name = "MonitoringRequest")
public class MonitoringRequest {
@XmlElement(name = "UserId", required = true)
protected String userId;
@XmlElement(name = "Password", required = true)
protected String password;
@XmlElement(name = "PackageName", required = true)
protected String packageName;
@XmlElement(name = "Subjects", required = true)
protected Subjects subjects;
public Subjects getSubjects() {
if (subjects == null) {
subjects = new Subjects();
}
return subjects;
}
private Subject currentSubject;
public void createCurrentSubject() {
currentSubject = new Subject();
}
public Subject getCurrentSubject() {
return currentSubject;
}
public void finalizeSubject() {
getSubjects().getSubject().add(currentSubject);
}
}

View file

@ -1,24 +0,0 @@
package ru.nbch.credit_tracker.entities.user_response.all_packages;
import jakarta.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"status",
"membercode",
"packages"
})
@XmlRootElement(name = "MonitoringAllPackagesResponse")
public class MonitoringAllPackagesResponse {
@XmlElement(name = "Status", required = true)
protected String status;
@XmlElement(name = "Membercode", required = true)
protected String membercode;
@XmlElement(name = "Packages", required = true)
protected PackagesAll packages;
}

View file

@ -1,29 +0,0 @@
package ru.nbch.credit_tracker.entities.user_response.all_packages;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"packageName",
"createdAt",
"status",
"deactivatedAt"
})
public class PackageAll {
@XmlElement(name = "PackageName", required = true)
protected String packageName;
@XmlElement(name = "CreatedAt", required = true)
protected String createdAt;
@XmlElement(name = "Status", required = false)
protected String status;
@XmlElement(name = "DeactivatedAt", required = false)
protected String deactivatedAt;
}

View file

@ -1,26 +0,0 @@
package ru.nbch.credit_tracker.entities.user_response.all_packages;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"packages"
})
public class PackagesAll {
@XmlElement(name = "Package", required = true)
protected List<PackageAll> packages;
public List<PackageAll> getPackages() {
if (packages == null) {
packages = new ArrayList<>();
}
return this.packages;
}
}

View file

@ -1,25 +0,0 @@
package ru.nbch.credit_tracker.entities.user_response.errors;
import jakarta.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MonitoringAllPackagesResponse", propOrder = {
"status",
"errorCode",
"errorText"
})
@XmlRootElement(name = "MonitoringAllPackagesResponse")
public class MonitoringAllPackagesError implements CommonError {
@XmlElement(name = "Status", required = true)
protected String status;
@XmlElement(name = "Code",required = true)
protected String errorCode;
@XmlElement(name = "Message",required = true)
protected String errorText;
}

View file

@ -2,27 +2,24 @@ package ru.nbch.credit_tracker.enums;
public enum SignalError implements IEnumKeyCode { public enum SignalError implements IEnumKeyCode {
ERROR_001("001", "Ошибка распаковки архива"), ERROR_001("001", "Ошибка распаковки архива"),
ERROR_002("002", "Отсутствует обязательный элемент: {}"), ERROR_002("002", "Отсутствует обязательный элемент: "),
ERROR_003("003", "Элемент ClientId не соответствует формату XXXXXXXXX. Id: {}"), ERROR_003("003", "Элемент ClientId не соответствует формату XXXXXXXXX"),
ERROR_004("004", "Указан неуникальный Id в пакете: "),
ERROR_005("005", "Неверный логин или пароль"), ERROR_005("005", "Неверный логин или пароль"),
ERROR_006("006", "Доступ к услуге закрыт, обратитесь к курирующему менеджеру"), ERROR_006("006", "Доступ к услуге закрыт, обратитесь к курирующему менеджеру"),
ERROR_007("007", "В системе уже существует пакет с таким именем"), ERROR_007("007", "В системе уже существует пакет с таким именем"),
ERROR_008("008", "PackageName не соответствует допустимому формату"), ERROR_008("008", "PackageName не соответствует допустимому формату"),
ERROR_009("009", "Превышен допустимый размер пакета"), ERROR_009("009", "Превышен допустимый размер пакета"),
ERROR_010("010", "Идентификатор субъекта (Id) не соответствует допустимому формату: {}"), ERROR_010("010", "Идентификатор субъекта (Id) не соответствует допустимому формату"),
ERROR_011("011", "Получен невалидный XML"), ERROR_011("011", "Получен невалидный XML"),
ERROR_012("012", "Пакет {} не найден"), ERROR_012("012", "Пакет не найден"),
ERROR_013("013", "На стороне сервиса произошла ошибка, попробуйте повторить запрос позже или сообщите в техническую поддержку"), ERROR_013("013", "На стороне сервиса произошла ошибка, попробуйте повторить запрос позже или сообщите в техническую поддержку"),
ERROR_014("014", "Файл с именем {} не найден "), ERROR_014("014", "Файл не найден"),
ERROR_015("015", "У данного пользователя не найдено активных пакетов"), ERROR_015("015", "Клиент с указанным membercode не найден"),
ERROR_016("016", "Нет активного пакета с именем {}"), ERROR_016("016", "Нет активного пакета с именем "),
ERROR_017("017", "При обработке запроса произошла ошибка. Повторите запрос позже или обратитесь в службу технической поддержки"), // TODO get rid of duplicate? ERROR_017("017", "При обработке запроса произошла ошибка. Повторите запрос позже или обратитесь в службу технической поддержки"), // TODO get rid of duplicate?
ERROR_018("018", "Пакет {} находится в обработке. Дождитесь его установки на мониторинг и повторите попытку позже."),
ERROR_019("019", "У данного пользователя не найдено ни одного пакета"),
ERROR_020("020", "Пакет {} был отклонён при установке на мониторинг. Отчеты не формируются."),
ERROR_021("021", "Обработка пакета {} завершилась с ошибкой, отчёты недоступны. Обратитесь в техническую поддержку."),
ERROR_022("022", "Пакет {} снят с мониторинга, отчёты больше недоступны.");
ERROR_100("100", "Непредвиденная ошибка");
private final String code; private final String code;
private final String message; private final String message;

View file

@ -2,7 +2,6 @@ package ru.nbch.credit_tracker.enums;
public enum XmlErrorFormat { public enum XmlErrorFormat {
MonitoringActivePackagesError, MonitoringActivePackagesError,
MonitoringAllPackagesError,
MonitoringDownloadError, MonitoringDownloadError,
MonitoringError, MonitoringError,
MonitoringPackageDeleteError, MonitoringPackageDeleteError,

View file

@ -7,10 +7,7 @@ import ru.nbch.credit_tracker.enums.XmlErrorFormat;
@Getter @Getter
public class SignalClientException extends SignalException { public class SignalClientException extends SignalException {
private final String packageName; public SignalClientException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat) {
public SignalClientException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat, String packageName) {
super(errorMessage, errorFormat); super(errorMessage, errorFormat);
this.packageName = packageName;
} }
} }

View file

@ -1,17 +1,12 @@
package ru.nbch.credit_tracker.exceptions; package ru.nbch.credit_tracker.exceptions;
import lombok.Getter;
import ru.nbch.credit_tracker.enums.EnumKeyMessage; import ru.nbch.credit_tracker.enums.EnumKeyMessage;
import ru.nbch.credit_tracker.enums.XmlErrorFormat; import ru.nbch.credit_tracker.enums.XmlErrorFormat;
@Getter
public class SignalServerException extends SignalException { public class SignalServerException extends SignalException {
private final Exception cause; public SignalServerException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat) {
public SignalServerException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat, Exception cause) {
super(errorMessage, errorFormat); super(errorMessage, errorFormat);
this.cause = cause;
} }
} }

View file

@ -1,55 +1,41 @@
package ru.nbch.credit_tracker.facade; package ru.nbch.credit_tracker.facade;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.io.FileUrlResource; import org.springframework.core.io.FileUrlResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.dto.UserPackage; import ru.nbch.credit_tracker.entities.dto.UserPackage;
import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest; import ru.nbch.credit_tracker.entities.request.active_packages.MonitoringActivePackagesRequest;
import ru.nbch.credit_tracker.entities.user_request.all_packages.MonitoringAllPackagesRequest; import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest; import ru.nbch.credit_tracker.entities.response.active_packages.MonitoringActivePackagesResponse;
import ru.nbch.credit_tracker.entities.user_response.active_packages.MonitoringActivePackagesResponse; import ru.nbch.credit_tracker.entities.response.active_packages.Package;
import ru.nbch.credit_tracker.entities.user_response.active_packages.Package; import ru.nbch.credit_tracker.entities.response.active_packages.Packages;
import ru.nbch.credit_tracker.entities.user_response.active_packages.Packages; import ru.nbch.credit_tracker.entities.response.success.MonitoringPackageDeleteResponse;
import ru.nbch.credit_tracker.entities.user_response.all_packages.MonitoringAllPackagesResponse; import ru.nbch.credit_tracker.entities.response.success.MonitoringReportListResponse;
import ru.nbch.credit_tracker.entities.user_response.all_packages.PackageAll; import ru.nbch.credit_tracker.entities.response.success.MonitoringResponse;
import ru.nbch.credit_tracker.entities.user_response.all_packages.PackagesAll; import ru.nbch.credit_tracker.entities.signal_package.Signals;
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringPackageDeleteResponse;
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringReportListResponse;
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse;
import ru.nbch.credit_tracker.enums.SignalError; import ru.nbch.credit_tracker.enums.SignalError;
import ru.nbch.credit_tracker.enums.Status; import ru.nbch.credit_tracker.enums.Status;
import ru.nbch.credit_tracker.enums.XmlErrorFormat; import ru.nbch.credit_tracker.enums.XmlErrorFormat;
import ru.nbch.credit_tracker.exceptions.SignalClientException; import ru.nbch.credit_tracker.exceptions.SignalClientException;
import ru.nbch.credit_tracker.service.MonitoringErrorProcesingService;
import ru.nbch.credit_tracker.service.SignalService; import ru.nbch.credit_tracker.service.SignalService;
import ru.nbch.credit_tracker.service.indic.PhoneService;
import ru.nbch.credit_tracker.service.scoring.AuthorizationService; import ru.nbch.credit_tracker.service.scoring.AuthorizationService;
import ru.nbch.credit_tracker.service.signal.SignalRestService; import ru.nbch.credit_tracker.service.signal.SignalRestService;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor; import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor;
import ru.nbch.credit_tracker.utils.CTUtil; import ru.nbch.credit_tracker.utils.CTUtil;
import ru.nbch.credit_tracker.utils.ValidationService; import ru.nbch.credit_tracker.utils.ValidationUtil;
import ru.nbch.credit_tracker.utils.ZipUtils; import ru.nbch.credit_tracker.utils.ZipUtils;
import javax.xml.stream.XMLStreamException;
import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
@ -59,43 +45,33 @@ import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp;
@Slf4j @Slf4j
@Service @Service
@EnableAspectJAutoProxy(exposeProxy = true)
public class SignalFacade { public class SignalFacade {
private static final long MAX_XML_FILE_SIZE = 2L * 1024 * 1024 * 1024;
private SignalFacade self;
private final CreditTrackerSettings config; private final CreditTrackerSettings config;
private final AuthorizationService authorizationService; private final AuthorizationService authorizationService;
private final SignalService signalService; private final SignalService signalService;
private final SignalRestService signalRestService; private final SignalRestService signalRestService;
private final MonitoringErrorProcesingService monitoringErrorProcesingService; private final IXmlProcessor xmlProcessor;
private final ValidationService validationService;
private final StaxXmlProcessor staxXmlProcessor;
private final ExecutorService executor; private final ExecutorService executor;
private final long maxXmlFileSize;
public SignalFacade(CreditTrackerSettings config, public SignalFacade(CreditTrackerSettings config,
AuthorizationService authorizationService, AuthorizationService authorizationService,
SignalService signalService, SignalService signalService,
SignalRestService signalRestService, SignalRestService signalRestService,
MonitoringErrorProcesingService monitoringErrorProcesingService, IXmlProcessor xmlProcessor,
ValidationService validationService,
StaxXmlProcessor staxXmlProcessor,
@Qualifier("executorService") ExecutorService executor) { @Qualifier("executorService") ExecutorService executor) {
this.config = config; this.config = config;
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
this.signalService = signalService; this.signalService = signalService;
this.signalRestService = signalRestService; this.signalRestService = signalRestService;
this.monitoringErrorProcesingService = monitoringErrorProcesingService; this.xmlProcessor = xmlProcessor;
this.validationService = validationService;
this.staxXmlProcessor = staxXmlProcessor;
this.executor = executor; this.executor = executor;
this.maxXmlFileSize = config.getMaxXmlFileSize() * 1024 * 1024;
} }
public ResponseEntity<MonitoringSetupResponse> setupMonitoring(MultipartFile file) { public ResponseEntity<MonitoringResponse> setupMonitoring(MultipartFile file) {
// первичные валидации // первичные валидации
if (file.isEmpty() || !isZipFile(file)) { if (file.isEmpty() || !isZipFile(file)) {
throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError); throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
@ -103,16 +79,15 @@ public class SignalFacade {
// Валидация Архива на количетсво файлов, размер и расширение // Валидация Архива на количетсво файлов, размер и расширение
MonitoringRequest monitoringRequest; MonitoringRequest monitoringRequest;
Long packageId; Integer packageId;
ZipInputStream zipInputStream = null; ZipInputStream zipInputStream = null;
String filePath;
try { try {
zipInputStream = new ZipInputStream(file.getInputStream()); zipInputStream = new ZipInputStream(file.getInputStream());
Optional<ZipEntry> xmlFileEntry = ZipUtils.extractValidEntry(zipInputStream); Optional<ZipEntry> xmlFileEntry = ZipUtils.extractValidEntry(zipInputStream);
if (xmlFileEntry.isEmpty()) { if (xmlFileEntry.isEmpty()) {
throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError); throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
} }
if (xmlFileEntry.get().getSize() > maxXmlFileSize) { if (xmlFileEntry.get().getSize() > MAX_XML_FILE_SIZE) {
throw clientExcp(SignalError.ERROR_009, XmlErrorFormat.MonitoringError); throw clientExcp(SignalError.ERROR_009, XmlErrorFormat.MonitoringError);
} }
@ -120,18 +95,19 @@ public class SignalFacade {
zipInputStream = new ZipInputStream(file.getInputStream()); zipInputStream = new ZipInputStream(file.getInputStream());
zipInputStream.getNextEntry(); zipInputStream.getNextEntry();
filePath = writeTmpFile(zipInputStream); monitoringRequest = xmlProcessor.read(zipInputStream, MonitoringRequest.class);
} catch (Exception e) { } catch (Exception e) {
if (e instanceof SignalClientException) { if (e instanceof SignalClientException) {
throw (SignalClientException) e; throw (SignalClientException) e;
} }
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e); log.error(e.getMessage(), e);
throw serverExcp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError);
} finally { } finally {
if (zipInputStream != null) { if (zipInputStream != null) {
try { try {
zipInputStream.close(); zipInputStream.close();
} catch (IOException e) { } catch (IOException e) {
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e); throw serverExcp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError);
} }
} }
} }
@ -139,16 +115,10 @@ public class SignalFacade {
// валидация xml // валидация xml
try { try {
monitoringRequest = readAndValidateMonitoringRequest(filePath); ValidationUtil.validateMonitoringRequest(monitoringRequest);
} catch (Exception e) { } catch (SignalClientException e) {
CTUtil.removeFile(filePath); signalService.rejectPackage(monitoringRequest);
if (e.getCause() instanceof XMLStreamException) { throw e;
throw clientExcp(SignalError.ERROR_011, XmlErrorFormat.MonitoringError);
}
if (e instanceof SignalClientException) {
throw (SignalClientException) e;
}
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
} }
try { try {
@ -156,100 +126,46 @@ public class SignalFacade {
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(monitoringRequest.getUserId(), monitoringRequest.getPassword()); AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(monitoringRequest.getUserId(), monitoringRequest.getPassword());
if (!authResult.isSuccess()) { if (!authResult.isSuccess()) {
signalService.rejectPackage(monitoringRequest); signalService.rejectPackage(monitoringRequest);
throw clientExcp(authResult.getError(), monitoringRequest.getPackageName(), XmlErrorFormat.MonitoringError); throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringError);
} }
// проверка на уникальность пакета // проверка на уникальность пакета
if (signalService.isPackageNotUnique(monitoringRequest)) { if (signalService.isPackageNotUnique(monitoringRequest)) {
signalService.rejectPackage(monitoringRequest); signalService.rejectPackage(monitoringRequest);
throw clientExcp(SignalError.ERROR_007, monitoringRequest.getPackageName(), XmlErrorFormat.MonitoringError); throw clientExcp(SignalError.ERROR_007, XmlErrorFormat.MonitoringError);
} }
packageId = signalService.registerPackage(monitoringRequest); packageId = signalService.registerPackage(monitoringRequest);
log.info("Package registered. PackageId {}. Status: {}", packageId, Status.PROCESSING.name());
} catch (Exception e) { } catch (Exception e) {
CTUtil.removeFile(filePath);
if (e instanceof SignalClientException) { if (e instanceof SignalClientException) {
throw (SignalClientException) e; throw (SignalClientException) e;
} }
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e); log.error(e.getMessage(), e);
throw serverExcp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError);
} }
// в отдельном потоке запускаем регистрацию субъектов, поиск фидов и расчет флагов просрочек // в отдельном потоке запускаем поиск фидов и расчет флагов просрочек
getCurrentProxy().registerFidsAndDebts(packageId, monitoringRequest.getPackageName(), filePath); registerFidsAndDebts(packageId, monitoringRequest.getPackageName());
return ResponseEntity.ok().body(new MonitoringSetupResponse()); return ResponseEntity.ok().body(new MonitoringResponse());
} }
private MonitoringRequest readAndValidateMonitoringRequest(String filePath) { private void registerFidsAndDebts(Integer packageId, String packageName) {
MonitoringRequest monitoringRequest;
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) {
monitoringRequest = staxXmlProcessor.read(in, MonitoringRequest.class,
request -> {
try {
validationService.validateMonitoringRequest(request);
} catch (SignalClientException e) {
if (request != null) {
signalService.rejectPackage(request);
}
request = null;
throw e;
}
request.getSubjects().getSubject().clear();
},
request -> request.getSubjects().getSubject().isEmpty()
,
40000, "/MonitoringRequest/Subjects/Subject");
} catch (IOException e) {
throw new RuntimeException("Error while parsing and validating monitoring request", e);
}
return monitoringRequest;
}
private String writeTmpFile(ZipInputStream zipInputStream) throws IOException {
String folderPath = config.getLoadDir() + File.separator + "tmp_folder" + File.separator;
String filePath = folderPath + UUID.randomUUID() + "monitoring_request.xml";
CTUtil.createFolder(folderPath);
try (OutputStream out = Files.newOutputStream(Path.of(filePath))) {
byte[] buffer = new byte[8 * 1024 * 1024];
int bytesRead;
while ((bytesRead = zipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
return filePath;
}
}
@SetAndClearMdc(argIndex = 1)
public void registerFidsAndDebts(Long packageId, String packageName, String filePath) {
Map<String, String> context = MDC.getCopyOfContextMap();
executor.execute(() -> { executor.execute(() -> {
if (context != null) {
MDC.setContextMap(context);
}
try { try {
signalService.registerSubjects(filePath, packageId); List<PhoneService.FidsPhoneData> phoneFidsData = signalService.registerSubjectsFidAndDebts(packageId);
CTUtil.removeFile(filePath); if (!phoneFidsData.isEmpty()) {
SignalService.UpdateResult updateResult = signalService.updateSubjects(packageId, null); Signals signals = signalService.buildSignals(packageId, phoneFidsData);
if (updateResult.isNoFidsFound()) { // TODO validate xsd?
log.info("No fids found for PackageId: {} PackageName: {}. Package status ON_MONITORING. No registration in signal service.", packageId, packageName); if (signalRestService.update(signals)) {
signalService.updatePackageStatus(packageId, Status.ON_MONITORING); log.info("Package was successfully registered in signal service. PackageId: {} PackageName: {}", packageId, packageName);
return; signalService.updatePackageStatus(packageId, Status.ON_MONITORING);
} } else {
if (signalRestService.setupMonitoring(packageId)) { log.info("Package registration was rejected by signal service. PackageId: {} PackageName: {}", packageId, packageName);
LocalDateTime monitoringAt = LocalDateTime.now(); signalService.updatePackageStatus(packageId, Status.ERROR);
log.info("Package was successfully registered in signal service. PackageId: {} PackageName: {}, MonitoringAt: {}", packageId, packageName, monitoringAt); }
signalService.updatePackageOnMonitoringSuccess(packageId, monitoringAt);
monitoringErrorProcesingService.findErrors(packageId);
} else {
log.info("Package registration was rejected by signal service. PackageId: {} PackageName: {}", packageId, packageName);
signalService.updatePackageStatus(packageId, Status.ERROR);
} }
} catch (Exception e) { } catch (Exception e) {
CTUtil.removeFile(filePath);
signalService.updatePackageStatus(packageId, Status.ERROR); signalService.updatePackageStatus(packageId, Status.ERROR);
log.error("Ошибка при поиске фидов или расчете флагов просрочек. Package_id {}", packageId, e); log.error("Ошибка при поиске фидов или расчете флагов просрочек. Package_id {}", packageId, e);
} }
@ -258,8 +174,8 @@ public class SignalFacade {
private boolean isZipFile(MultipartFile file) { private boolean isZipFile(MultipartFile file) {
return file.getContentType() != null && return file.getContentType() != null &&
(file.getContentType().equals("application/zip") || file.getContentType().equals("application/x-zip-compressed")) || (file.getContentType().equals("application/zip") || file.getContentType().equals("application/x-zip-compressed")) ||
file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".zip"); file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".zip");
} }
public ResponseEntity<MonitoringActivePackagesResponse> findActivePackages(MonitoringActivePackagesRequest activePackagesRequest) { public ResponseEntity<MonitoringActivePackagesResponse> findActivePackages(MonitoringActivePackagesRequest activePackagesRequest) {
@ -290,43 +206,8 @@ public class SignalFacade {
if (e instanceof SignalClientException) { if (e instanceof SignalClientException) {
throw (SignalClientException) e; throw (SignalClientException) e;
} }
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringActivePackagesError, e); log.error(e.getMessage(), e);
} throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringActivePackagesError);
}
public ResponseEntity<MonitoringAllPackagesResponse> findAllPackages(MonitoringAllPackagesRequest allPackagesRequest) {
try {
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(allPackagesRequest.getUserId(), allPackagesRequest.getPassword());
if (!authResult.isSuccess()) {
throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringAllPackagesError);
}
List<UserPackage> activePackages = signalService.findAllPackages(allPackagesRequest.getUserId());
if (!activePackages.isEmpty()) {
MonitoringAllPackagesResponse response = new MonitoringAllPackagesResponse();
response.setStatus("OK");
response.setMembercode(allPackagesRequest.getUserId().substring(0, 6));
PackagesAll packages = new PackagesAll();
activePackages.forEach(data -> {
PackageAll pack = new PackageAll();
pack.setPackageName(data.getPackageName());
pack.setCreatedAt(data.getCreatedAt() != null ? data.getCreatedAt().toString() : null);
pack.setStatus(data.getStatus());
if (data.getStatus().equals(Status.DELETED.name())) {
pack.setDeactivatedAt(data.getDeactivatedAt() != null ? data.getDeactivatedAt().toString() : null);
}
packages.getPackages().add(pack);
});
response.setPackages(packages);
return ResponseEntity.ok(response);
} else {
throw clientExcp(SignalError.ERROR_019, XmlErrorFormat.MonitoringAllPackagesError);
}
} catch (Exception e) {
if (e instanceof SignalClientException) {
throw (SignalClientException) e;
}
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringAllPackagesError, e);
} }
} }
@ -351,26 +232,15 @@ public class SignalFacade {
if (e instanceof SignalClientException) { if (e instanceof SignalClientException) {
throw (SignalClientException) e; throw (SignalClientException) e;
} }
throw serverExcp(SignalError.ERROR_017, XmlErrorFormat.MonitoringPackageDeleteError, e); log.error(e.getMessage(), e);
throw serverExcp(SignalError.ERROR_017, XmlErrorFormat.MonitoringPackageDeleteError);
} }
} }
public ResponseEntity<MonitoringReportListResponse> getReportList(String username, String packageName) { public ResponseEntity<MonitoringReportListResponse> getReportList(String username, String packageName) {
try { try {
if (signalService.isPackagesByStatusExist(username, packageName, Status.PROCESSING)) { if (!signalService.isPackageExists(username, packageName)) {
throw clientExcp(SignalError.ERROR_018, XmlErrorFormat.MonitoringReportListError, packageName); throw clientExcp(SignalError.ERROR_016, XmlErrorFormat.MonitoringReportListError, packageName);
}
if (signalService.isPackagesByStatusExist(username, packageName, Status.REJECTED)) {
throw clientExcp(SignalError.ERROR_020, XmlErrorFormat.MonitoringReportListError, packageName);
}
if (signalService.isPackagesByStatusExist(username, packageName, Status.ERROR)) {
throw clientExcp(SignalError.ERROR_021, XmlErrorFormat.MonitoringReportListError, packageName);
}
if (signalService.isPackagesByStatusExist(username, packageName, Status.DELETED)) {
throw clientExcp(SignalError.ERROR_022, XmlErrorFormat.MonitoringReportListError, packageName);
}
if (!signalService.isPackagesByStatusExist(username, packageName, Status.ON_MONITORING)) {
throw clientExcp(SignalError.ERROR_012, XmlErrorFormat.MonitoringReportListError, packageName);
} }
String memberCode = username.substring(0, 6); String memberCode = username.substring(0, 6);
@ -378,35 +248,42 @@ public class SignalFacade {
String dirPath = config.getLoadDir() + File.separator + memberCode; String dirPath = config.getLoadDir() + File.separator + memberCode;
File folder = new File(dirPath); File folder = new File(dirPath);
MonitoringReportListResponse.Reports reports = new MonitoringReportListResponse.Reports();
if (folder.exists() && folder.isDirectory()) { if (folder.exists() && folder.isDirectory()) {
MonitoringReportListResponse.Reports reports = new MonitoringReportListResponse.Reports();
File[] files = folder.listFiles(); File[] files = folder.listFiles();
if (files != null) { if (files == null) {
for (File file : files) { throw clientExcp(SignalError.ERROR_012, XmlErrorFormat.MonitoringReportListError, packageName);
if (file.isFile() && file.getName().startsWith(filePrefix)) { }
reports.getReports().add(file.getName()); for (File file : files) {
} if (file.isFile() && file.getName().startsWith(filePrefix)) {
reports.getReports().add(file.getName());
} }
} }
if (reports.getReports().isEmpty()) {
throw clientExcp(SignalError.ERROR_012, XmlErrorFormat.MonitoringReportListError, packageName);
} else {
MonitoringReportListResponse response = new MonitoringReportListResponse();
response.setPackageName(packageName);
response.setReports(reports);
return ResponseEntity.ok(response);
}
} else {
log.error("Пакет {} был найден в бд для memberCode {}, но ни одного архива не было найдено в папке {}", packageName, username, dirPath);
throw clientExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError, packageName);
} }
MonitoringReportListResponse response = new MonitoringReportListResponse();
response.setPackageName(packageName);
response.setReports(reports);
return ResponseEntity.ok(response);
} catch (Exception e) { } catch (Exception e) {
if (e instanceof SignalClientException) { if (e instanceof SignalClientException) {
throw (SignalClientException) e; throw (SignalClientException) e;
} }
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError, e); log.error(e.getMessage(), e);
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError);
} }
} }
public ResponseEntity<Resource> downloadFile(String fileName) { public ResponseEntity<Resource> downloadFile(String fileName) {
try { try {
String memberCode = CTUtil.getMemberCodeFromFileName(fileName); String memberCode = CTUtil.getMemberCodeFromFileName(fileName);
if (memberCode == null) {
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError, fileName);
}
String dirPath = config.getLoadDir() + File.separator + memberCode; String dirPath = config.getLoadDir() + File.separator + memberCode;
File folder = new File(dirPath); File folder = new File(dirPath);
@ -416,21 +293,15 @@ public class SignalFacade {
return ResponseEntity.ok().body(new FileUrlResource(file.getPath())); return ResponseEntity.ok().body(new FileUrlResource(file.getPath()));
} }
} else { } else {
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError, fileName); throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError);
} }
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError, fileName); throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError);
} catch (Exception e) { } catch (Exception e) {
if (e instanceof SignalClientException) { if (e instanceof SignalClientException) {
throw (SignalClientException) e; throw (SignalClientException) e;
} }
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringDownloadError, e); log.error(e.getMessage(), e);
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringDownloadError);
} }
} }
private SignalFacade getCurrentProxy() {
if (self == null) {
self = (SignalFacade) AopContext.currentProxy();
}
return self;
}
} }

View file

@ -3,23 +3,19 @@ package ru.nbch.credit_tracker.mapper.signal;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap; import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.Subject; import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject;
import java.util.List; import java.util.List;
@Mapper @Mapper
public interface PhoneFidMapMapper { public interface PhoneFidMapMapper {
void registerSubjects(@Param("subjects") List<Subject> subjects, @Param("packageId") Long packageId); void registerSubjects(@Param("subjects") List<Subject> subjects, @Param("packageId") Integer packageId);
List<PhoneFidMap> findFullPhoneFidMap(@Param("packageId") Long packageId, @Param("offset") int offset, @Param("limit") int limit); List<PhoneFidMap> findPhoneFidMaps(@Param("packageId") Integer packageId);
List<PhoneFidMap> findFullPhoneFidMap(@Param("packageId") Integer packageId);
void updatePhoneFidMaps(@Param("subjects") List<PhoneFidMap> subjects); void updatePhoneFidMaps(@Param("subjects") List<PhoneFidMap> subjects);
void updatePhoneFidMapsErrors(@Param("subjects") List<PhoneFidMap> subjects);
PhoneFidMap findPhoneFidMapById(@Param("id") Long packageId);
boolean hasNonNullFids(@Param("packageId") Long packageId);
boolean hasOldRow(@Param("packageId") Long packageId, @Param("daysCount") Integer daysCount);
} }

View file

@ -14,23 +14,18 @@ public interface UserPackageMapper {
boolean isPackageExists(@Param("userId") String userId, @Param("packageName") String packageName, @Param("status") String status); boolean isPackageExists(@Param("userId") String userId, @Param("packageName") String packageName, @Param("status") String status);
boolean hasActivePackages(@Param("userId") String userId, @Param("packageName") String packageName, @Param("statuses") List<String> statuses);
void deletePackage(@Param("userId") String userId, @Param("packageName") String packageName, @Param("status") String newStatus, @Param("previousStatus") String previousStatus, @Param("deactivatedAt") LocalDateTime deactivatedAt); void deletePackage(@Param("userId") String userId, @Param("packageName") String packageName, @Param("status") String newStatus, @Param("previousStatus") String previousStatus, @Param("deactivatedAt") LocalDateTime deactivatedAt);
Long insertPackage(@Param("userPackage") UserPackage userPackage); Integer insertPackage(@Param("userPackage") UserPackage userPackage);
void updatePackageStatus(@Param("packageId") Long packageId, @Param("status") String status); void updatePackageStatus(@Param("packageId") Integer packageId, @Param("status") String status);
void updatePackageLastDownloadedReport(@Param("id") Long id, @Param("fileName") String fileName); void updatePackageLastDownloadedReport(@Param("id") Integer id, @Param("fileName") String fileName);
void updatePackageOnMonitoringSuccess(@Param("id") Long id, @Param("monitoringAt") LocalDateTime monitoringAt); UserPackage findPackage(@Param("id") Integer id);
UserPackage findPackage(@Param("id") Long id); List<UserPackage> findUserPackages(@Param("userId") String userId, @Param("status") String status);
List<UserPackage> findUserPackages(@Param("userId") String userId, @Param("statuses") List<String> status);
List<UserPackage> findAllPackagesByStatus(@Param("status") String status); List<UserPackage> findAllPackagesByStatus(@Param("status") String status);
List<UserPackage> findAllPackagesByUserId(@Param("userId") String userId);
} }

View file

@ -1,59 +0,0 @@
package ru.nbch.credit_tracker.service;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
import ru.nbch.credit_tracker.entities.dto.UserPackage;
import ru.nbch.credit_tracker.service.signal.SignalRestService;
import ru.nbch.credit_tracker.utils.CTUtil;
@Slf4j
@Service
@EnableAspectJAutoProxy(exposeProxy = true)
public class MonitoringErrorProcesingService {
private MonitoringErrorProcesingService self;
private final SignalService signalService;
private final SignalRestService signalRestService;
public MonitoringErrorProcesingService(SignalService signalService, SignalRestService signalRestService) {
this.signalService = signalService;
this.signalRestService = signalRestService;
}
public void findErrors(Long packageId) {
UserPackage userPackage = signalService.findPackage(packageId);
getCurrentProxy().processPackage(userPackage, packageId);
}
@SetAndClearMdc
public void processPackage(UserPackage userPackage, Long packageId) {
if (userPackage != null) {
String packCode = userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName();
log.info("Проверка на ошибки при постановке на мониторинг. packCode={}, packageId={}", packCode, packageId);
String fileName = signalRestService.getErrorFileName(packageId, packCode);
if (StringUtils.isNotBlank(fileName)) {
String filePath = signalRestService.loadErrorFile(packageId, fileName);
if (StringUtils.isNotBlank(filePath)) {
try {
signalService.updateSubjectsErrors(filePath, packageId);
} catch (Exception e) {
log.error("Ошибка при записи сообщений об ошибках в сформированных субъектах для мониторинга. Package_id = {}", packageId, e);
}
CTUtil.removeFile(filePath);
}
}
}
}
private MonitoringErrorProcesingService getCurrentProxy() {
if (self == null) {
self = (MonitoringErrorProcesingService) AopContext.currentProxy();
}
return self;
}
}

View file

@ -1,67 +1,55 @@
package ru.nbch.credit_tracker.service; package ru.nbch.credit_tracker.service;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.dto.Hit; import ru.nbch.credit_tracker.entities.dto.Hit;
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap; import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
import ru.nbch.credit_tracker.entities.dto.UserPackage; import ru.nbch.credit_tracker.entities.dto.UserPackage;
import ru.nbch.credit_tracker.entities.external_response.online_download.Inquiry; import ru.nbch.credit_tracker.entities.response.monitoring_signal_response.*;
import ru.nbch.credit_tracker.entities.external_response.online_download.Person; import ru.nbch.credit_tracker.entities.response.online_download.Inquiry;
import ru.nbch.credit_tracker.entities.external_response.online_download.Persons; import ru.nbch.credit_tracker.entities.response.online_download.OnlineDownloadReport;
import ru.nbch.credit_tracker.entities.external_response.online_report.Report; import ru.nbch.credit_tracker.entities.response.online_download.Person;
import ru.nbch.credit_tracker.entities.external_response.online_report.SgnlOnlineReport; import ru.nbch.credit_tracker.entities.response.online_report.Report;
import ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response.MonitoringSignalResponse; import ru.nbch.credit_tracker.entities.response.online_report.SgnlOnlineReport;
import ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response.Signal;
import ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response.Signals;
import ru.nbch.credit_tracker.entities.user_response.monitoring_signal_response.Subject;
import ru.nbch.credit_tracker.service.signal.SignalRestService; import ru.nbch.credit_tracker.service.signal.SignalRestService;
import ru.nbch.credit_tracker.service.xml.stax.MonitoringSignalResponseStaxXmlWriter; import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
import ru.nbch.credit_tracker.utils.CTUtil; import ru.nbch.credit_tracker.utils.CTUtil;
import java.io.*; import java.io.ByteArrayInputStream;
import java.nio.file.Files; import java.io.File;
import java.nio.file.Path; import java.io.FileOutputStream;
import java.nio.charset.Charset;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.*;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
/**
* Сервис периодического опроса официального сервиса сигналов на наличие новых отчетов по пакетам находящимся в статусе ON_MONITORING
*/
@Slf4j @Slf4j
@Service @Service
public class MonitoringService { public class MonitoringService {
private final SignalRestService signalRestService; private final SignalRestService signalRestService;
private final SignalService signalService; private final SignalService signalService;
private final StaxXmlProcessor staxXmlProcessor; private final IXmlProcessor xmlProcessor;
private final CreditTrackerSettings config; private final CreditTrackerSettings config;
public MonitoringService(SignalRestService signalRestService, public MonitoringService(SignalRestService signalRestService,
SignalService signalService, SignalService signalService,
StaxXmlProcessor staxXmlProcessor, IXmlProcessor xmlProcessor,
CreditTrackerSettings config) { CreditTrackerSettings config) {
this.signalRestService = signalRestService; this.signalRestService = signalRestService;
this.signalService = signalService; this.signalService = signalService;
this.staxXmlProcessor = staxXmlProcessor; this.xmlProcessor = xmlProcessor;
this.config = config; this.config = config;
} }
public void run() { public void run() {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("monitoring-")); ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
long period = config.getMonitoringInterval() != null ? config.getMonitoringInterval() : 15; long period = config.getMonitoringInterval() != null ? config.getMonitoringInterval() : 15;
scheduler.scheduleAtFixedRate(this::monitor, 0, period, TimeUnit.MINUTES); scheduler.scheduleAtFixedRate(this::monitor, 0, period, TimeUnit.MINUTES);
} }
@ -70,144 +58,71 @@ public class MonitoringService {
log.info("Start monitoring"); log.info("Start monitoring");
List<UserPackage> packages = signalService.findPackagesOnMonitoring(); List<UserPackage> packages = signalService.findPackagesOnMonitoring();
for (UserPackage userPackage : packages) { for (UserPackage userPackage : packages) {
MDC.put("ru.nbch.credit_tracker.log.mdc.key", "[" + userPackage.getPackageName() +"]"); log.info("Processing package {}", userPackage.getPackageName());
processPackage(userPackage); SgnlOnlineReport onlineReports = signalRestService.getReports(userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName());
MDC.remove("ru.nbch.credit_tracker.log.mdc.key");
if (onlineReports == null) {
log.info("No reports found for package {}", userPackage.getPackageName());
continue;
}
List<String> fileNames = onlineReports.getOperationReport().getReports().getReports().stream().map(Report::getFilename)
.filter(fileName -> CTUtil.parseDateFromReportFileName(fileName) != null).toList(); // TODO оптимизировать
if (fileNames.isEmpty()) {
log.info("No new report found for package {}", userPackage.getPackageName());
continue;
}
Optional<String> newReport = Optional.of(fileNames)
.orElseGet(Collections::emptyList)
.stream().max(Comparator.comparing(CTUtil::parseDateFromReportFileName)); // отфильтровали только те имена, которые парсятся в дату, так что null тут не придет
LocalDateTime lastDownloadedReportDate = CTUtil.parseDateFromReportFileName(userPackage.getLastDownloadedReport());
if (userPackage.getLastDownloadedReport() != null) {
log.info("Last downloaded report found for package {}. Last Downloaded Report Name: {}", userPackage.getPackageName(), userPackage.getLastDownloadedReport());
} else {
log.info("Last Downloaded Report Name is empty");
}
OnlineDownloadReport report = null;
if (userPackage.getLastDownloadedReport() == null && newReport.isPresent()) {
report = loadReport(newReport.get()); // по этому пакету еще не было загруженных отчетов, продолжаем работу с полученным
} else if (lastDownloadedReportDate != null && newReport.isPresent()) {
LocalDateTime newReportDate = CTUtil.parseDateFromReportFileName(newReport.get());
if (newReportDate.isAfter(lastDownloadedReportDate)) {
report = loadReport(newReport.get()); // полученный отчет новее записанного в базу
}
}
if (report == null) {
log.info("Report was not loaded for package {}", userPackage.getPackageName());
continue;
}
MonitoringSignalResponse response = generateResponse(userPackage, report.getPersons().getPersons());
String fileName = createResponseFile(userPackage, response);
if (fileName != null) {
log.info("New report fileName: {}", fileName);
updateSignalHits(userPackage, response, fileName);
signalService.updateLastDownloadedReport(userPackage.getId(), newReport.get());
} else {
log.info("Report was not created for package {}", userPackage.getPackageName());
}
} }
log.info("Finish monitoring"); log.info("Finish monitoring");
} }
private void processPackage(UserPackage userPackage) { private MonitoringSignalResponse generateResponse(UserPackage userPackage, List<Person> persons) {
log.info("Processing package");
if (!signalService.hasNonNullfids(userPackage.getId())) {
log.info("Package has no fids. Package will be skipped.");
return;
}
SgnlOnlineReport onlineReports = signalRestService.getReports(userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName());
if (onlineReports == null) {
log.info("No reports found for package");
return;
}
// Формируем список имен файлов, по которым сработали сигналы. Сюда входят только те имена, у которых парсится дата формирования отчета
List<String> fileNames = onlineReports.getOperationReport().getReports().getReports().stream().map(Report::getFilename)
.filter(fileName -> CTUtil.parseDateFromReportFileName(fileName) != null).toList();
if (fileNames.isEmpty()) {
log.info("No new report found for package");
return;
}
LocalDateTime lastDownloadedReportDate = CTUtil.parseDateFromReportFileName(userPackage.getLastDownloadedReport());
if (lastDownloadedReportDate != null) {
// Отбираем только те отчеты, дата которых позже даты последнего загруженного отчета
fileNames = fileNames.stream()
.filter(fileName -> CTUtil.parseDateFromReportFileName(fileName).isAfter(lastDownloadedReportDate)) // отфильтровали только те имена, которые парсятся в дату, так что null тут не придет
.sorted(Comparator.comparing(CTUtil::parseDateFromReportFileName)) // Сортируем по дате
.toList();
} else {
fileNames = fileNames.stream()
.sorted(Comparator.comparing(CTUtil::parseDateFromReportFileName)) // Сортируем по дате
.toList();
}
if (StringUtils.isNotBlank(userPackage.getLastDownloadedReport())) {
log.info("Last downloaded report found for package. Last Downloaded Report Name: {}", userPackage.getLastDownloadedReport());
} else {
log.info("Last Downloaded Report Name is empty");
}
for (String newReport : fileNames) {
try {
String loadedReportPath = null;
if (StringUtils.isBlank(userPackage.getLastDownloadedReport())) {
loadedReportPath = loadReport(userPackage.getId(), newReport); // по этому пакету еще не было загруженных отчетов, продолжаем работу с полученным
} else if (lastDownloadedReportDate != null) {
LocalDateTime newReportDate = CTUtil.parseDateFromReportFileName(newReport);
if (newReportDate.isAfter(lastDownloadedReportDate)) {
loadedReportPath = loadReport(userPackage.getId(), newReport); // полученный отчет новее записанного в базу
}
}
if (loadedReportPath == null) {
log.info("Report was not loaded for package");
continue;
}
String responsePath = generateResponse(userPackage, loadedReportPath);
String fileName = null;
if (responsePath != null) {
fileName = createResponseFile(userPackage, responsePath);
}
if (fileName != null) {
log.info("New report fileName: {}", fileName);
updateSignalHits(userPackage, responsePath, fileName);
signalService.updateLastDownloadedReport(userPackage.getId(), newReport);
} else {
log.info("Report was not created for package");
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
/**
* Формирует результирующий xml файл для конечного пользователя на основе файла из официального сервиса сигналов
* @return Путь к временному рещультирующему файлу
*/
private String generateResponse(UserPackage userPackage, String loadedReportPath) {
AtomicBoolean generateResponse = new AtomicBoolean(false); // Выставляется в true, если хотя бы один субъект с мониторинга подошел под условие срабатывания сигнала. В этом случае отчет сохраняется
String folderPath = config.getLoadDir() + File.separator + "tmp_folder" + File.separator;
String responsePath = folderPath + UUID.randomUUID() + "_response_output.xml";
CTUtil.createFolder(folderPath);
MonitoringSignalResponse response = new MonitoringSignalResponse(); MonitoringSignalResponse response = new MonitoringSignalResponse();
response.setPackageName(userPackage.getPackageName()); // Имя пакета, переданного при установке response.setPackageName(userPackage.getPackageName()); // Имя пакета, переданного при установке
Subjects subjects = new Subjects();
// Запись в результрующий файл List<PhoneFidMap> phoneFidMapList = signalService.findFullSubjectsData(userPackage.getId());
MonitoringSignalResponseStaxXmlWriter staxXmlWriter = new MonitoringSignalResponseStaxXmlWriter(config.getEncoding());
staxXmlWriter.writeWithStax(responsePath, response,
writer -> {
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(loadedReportPath)), 8 * 1024 * 1024)) {
staxXmlProcessor.read(in, Persons.class,
personsData -> { // как только считали пачку Persons сразу записали ее в результирующий файл
List<Subject> subjectsBatch = processPersons(personsData.getPersons());
if (!subjectsBatch.isEmpty()) {
generateResponse.set(true);
}
writer.accept(subjectsBatch);
personsData.getPersons().clear(); // чистим список для экономии памяти
},
pesons -> pesons.getPersons().isEmpty()
,
10000,
"/Report/Persons/Person");
} catch (IOException e) {
throw new RuntimeException("Error while parsing nbki downloaded report", e);
}
});
CTUtil.removeFile(loadedReportPath);
if (!generateResponse.get()) { // ни один субъект не подошел под условие, удаляем временный отчет
CTUtil.removeFile(responsePath);
return null;
}
return responsePath;
}
private List<Subject> processPersons(List<Person> persons) {
List<Subject> subjects = new ArrayList<>();
for (Person person : persons) { for (Person person : persons) {
Signals signals = new Signals(); Signals signals = new Signals();
for (Inquiry inquiry : person.getInquiries()) { for (Inquiry inquiry : person.getInquiries()) {
// Отбираем только тех фл, у которых bus_category in (MFO, MKK, MFK) и есть сигналы с кодом 16 // Отбираем только тех фл, у которых bus_category in (MFO, MKK, MFK) и есть сигналы с кодом 16
if (!CTUtil.checkBusCategory(inquiry.getBusCategory()) || inquiry.getSignals().stream().noneMatch(signal -> signal.getN().equals(16))) { if (!CTUtil.checkBusCategory(inquiry.getBusCategory()) && inquiry.getSignals().stream().anyMatch(signal -> signal.getN().equals(16))) {
continue; continue;
} }
Signal signal = new Signal(); Signal signal = new Signal();
@ -219,101 +134,84 @@ public class MonitoringService {
// Если есть хотя бы один заполненный сигнал, значит заполняем остальные данные // Если есть хотя бы один заполненный сигнал, значит заполняем остальные данные
if (!signals.getSignals().isEmpty()) { if (!signals.getSignals().isEmpty()) {
PhoneFidMap subjectData = signalService.findPhoneFidMapById(person.getUid()); phoneFidMapList.stream().filter(p -> p.getSubjectId().equals(person.getUid())).findFirst().ifPresent(subjectData -> {
if (subjectData != null) {
Subject subject = new Subject(); Subject subject = new Subject();
subject.setId(subjectData.getSubjectId()); // Уникальный идентификатор субъекта (равен Id из XML-пакета при установке мониторинга) subject.setId(subjectData.getSubjectId()); // Уникальный идентификатор субъекта (равен Id из XML-пакета при установке мониторинга)
subject.setClientId(subjectData.getPhone()); subject.setClientId(subjectData.getPhone());
subject.setFlagDebt5000(subjectData.getFlagDebt5000()); subject.setFlagDebt5000(subjectData.getFlagDebt5000());
subject.setFlag9012(subjectData.getFlag90days()); subject.setFlag9012(subjectData.getFlag90days());
subject.setSignals(signals); subject.setSignals(signals);
subjects.add(subject); subjects.getSubjects().add(subject);
} });
} }
} }
return subjects; response.setSubjects(subjects);
return response;
} }
/** private String createResponseFile(UserPackage userPackage, MonitoringSignalResponse response) {
* Архивирует результирующий xml файл для пользователя
* @return Путь к результрующему файлу. Пример <loadDir>/<member_code>/0001ZZ_MY_BATCH_TEST_0717_04_20250723_101929.zip
*/
private String createResponseFile(UserPackage userPackage, String responsePath) {
try { try {
String fileName = CTUtil.generateResponseReportFileName(userPackage.getUserId(), userPackage.getPackageName()); String fileName = CTUtil.generateResponseReportFileName(userPackage.getUserId(), userPackage.getPackageName());
Thread.sleep(1000); // Если отчеты формируются слишком быстро, нужно подождать секунду, тк в имени отчета LocalDateTime до секунд String filePath = config.getLoadDir() + File.separator + userPackage.getUserId().substring(0, 6) + File.separator;
String folderPath = config.getLoadDir() + File.separator + userPackage.getUserId().substring(0, 6) + File.separator;
File folder = new File(folderPath); File folder = new File(filePath);
if (!folder.exists()) { if (!folder.exists()) {
folder.mkdir(); folder.mkdir();
} }
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(responsePath)), 8 * 1024 * 1024); String xmlStr = xmlProcessor.asString(response, true);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(folderPath + fileName + ".zip"));
ZipOutputStream zos = new ZipOutputStream(bos)) { byte[] xmlBytes = xmlStr.getBytes(Charset.forName("windows-1251"));
try (FileOutputStream fos = new FileOutputStream(filePath + fileName + ".zip");
ZipOutputStream zos = new ZipOutputStream(fos)) {
ZipEntry zipEntry = new ZipEntry(fileName + ".xml"); ZipEntry zipEntry = new ZipEntry(fileName + ".xml");
zos.putNextEntry(zipEntry); zos.putNextEntry(zipEntry);
byte[] buffer = new byte[8 * 1024 * 1024]; zos.write(xmlBytes);
int bytesRead;
while ((bytesRead = in.read(buffer)) > 0) {
zos.write(buffer, 0, bytesRead);
}
zos.finish();
zos.closeEntry(); zos.closeEntry();
} }
return fileName; return fileName;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) { } catch (Exception e) {
log.error("Ошибка при записи отчета пользователя в файл: ", e); log.error("Ошибка при записи отчета пользователя в файл: ", e);
} }
CTUtil.removeFile(responsePath);
return null; return null;
} }
private void updateSignalHits(UserPackage userPackage, String responsePath, String reportFileName) { private void updateSignalHits(UserPackage userPackage, MonitoringSignalResponse response, String reportFileName) {
log.info("Updating signal hits for {}", userPackage.getPackageName()); log.info("Updating signal hits for {}", userPackage.getPackageName());
LocalDateTime responseSentAt = LocalDateTime.now(); LocalDateTime responseSentAt = LocalDateTime.now();
// Считываем результирующий файл пачками и обновляем таблицу hits List<Hit> hits = new ArrayList<>();
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(responsePath)), 8 * 1024 * 1024)) { response.getSubjects().getSubjects().forEach(subject -> {
staxXmlProcessor.read(in, MonitoringSignalResponse.class, subject.getSignals().getSignals().forEach(signal -> {
response -> { // как только считали пачку Subjects сразу обновлям таблицу hits Hit hit = new Hit();
List<Hit> hits = new ArrayList<>(); hit.setPackageId(userPackage.getId());
response.getSubjects().getSubjects().forEach(subject -> { hit.setSubjectId(subject.getId());
subject.getSignals().getSignals().forEach(signal -> { hit.setSignalType(1);
Hit hit = new Hit(); hit.setResponseSentAt(responseSentAt);
hit.setPackageId(userPackage.getId()); hit.setReportFileName(reportFileName);
hit.setSubjectId(subject.getId()); hits.add(hit);
hit.setSignalType(1); });
hit.setResponseSentAt(responseSentAt); });
hit.setReportFileName(reportFileName); signalService.insertHits(hits);
hits.add(hit);
});
if (!hits.isEmpty()) {
signalService.insertHits(hits);
}
});
response.getSubjects().getSubjects().clear(); // чистим список для экономии памяти
},
response -> response.getSubjects().getSubjects().isEmpty()
,
10000,
"/MonitoringSignalResponse/Subjects/Subject");
} catch (IOException e) {
throw new RuntimeException("Error while updating hits", e);
}
CTUtil.removeFile(responsePath); // удалям результирующий xml файл с диска (Он уже заархивирован к этому моменту)
log.info("Signal hits updated for package {}", userPackage.getPackageName()); log.info("Signal hits updated for package {}", userPackage.getPackageName());
} }
public String loadReport(Long packageId, String reportName) { private OnlineDownloadReport loadReport(String reportName) {
return signalRestService.downloadReport(packageId, reportName); byte[] archive = signalRestService.downloadReport(reportName);
if (archive == null) {
return null;
}
OnlineDownloadReport report;
try (GZIPInputStream zipInputStream = new GZIPInputStream(new ByteArrayInputStream(archive))) {
report = xmlProcessor.read(zipInputStream, OnlineDownloadReport.class);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
return report;
} }
} }

View file

@ -1,7 +1,5 @@
package ru.nbch.credit_tracker.service; package ru.nbch.credit_tracker.service;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.builder.PersonFactoryBuilder; import ru.nbch.credit_tracker.builder.PersonFactoryBuilder;
@ -9,11 +7,11 @@ import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.dto.Hit; import ru.nbch.credit_tracker.entities.dto.Hit;
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap; import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
import ru.nbch.credit_tracker.entities.dto.UserPackage; import ru.nbch.credit_tracker.entities.dto.UserPackage;
import ru.nbch.credit_tracker.entities.external_request.signals.Auth; import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest;
import ru.nbch.credit_tracker.entities.external_request.signals.Person; import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject;
import ru.nbch.credit_tracker.entities.external_request.signals.Signals; import ru.nbch.credit_tracker.entities.signal_package.Auth;
import ru.nbch.credit_tracker.entities.external_response.monitoring_report_error.MonitoringReportErrors; import ru.nbch.credit_tracker.entities.signal_package.Person;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest; import ru.nbch.credit_tracker.entities.signal_package.Signals;
import ru.nbch.credit_tracker.enums.Status; import ru.nbch.credit_tracker.enums.Status;
import ru.nbch.credit_tracker.service.indic.FlagsService; import ru.nbch.credit_tracker.service.indic.FlagsService;
import ru.nbch.credit_tracker.service.indic.PersonService; import ru.nbch.credit_tracker.service.indic.PersonService;
@ -21,19 +19,12 @@ import ru.nbch.credit_tracker.service.indic.PhoneService;
import ru.nbch.credit_tracker.service.signal.HitsService; import ru.nbch.credit_tracker.service.signal.HitsService;
import ru.nbch.credit_tracker.service.signal.PhoneFidMapService; import ru.nbch.credit_tracker.service.signal.PhoneFidMapService;
import ru.nbch.credit_tracker.service.signal.UserPackageService; import ru.nbch.credit_tracker.service.signal.UserPackageService;
import ru.nbch.credit_tracker.service.xml.stax.SignalsStaxXmlWriter;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
import ru.nbch.credit_tracker.utils.CTUtil;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.ArrayList;
import java.util.function.Consumer; import java.util.List;
import java.util.function.Predicate; import java.util.Map;
import java.util.Objects;
@Slf4j @Slf4j
@Service @Service
@ -46,7 +37,6 @@ public class SignalService {
private final PhoneService phoneService; private final PhoneService phoneService;
private final FlagsService flagsService; private final FlagsService flagsService;
private final PersonService personService; private final PersonService personService;
private final StaxXmlProcessor staxXmlProcessor;
private final int batchSize = 10000; private final int batchSize = 10000;
@ -56,8 +46,7 @@ public class SignalService {
PhoneFidMapService phoneFidMapService, PhoneFidMapService phoneFidMapService,
PhoneService phoneService, PhoneService phoneService,
FlagsService flagsService, FlagsService flagsService,
PersonService personService, PersonService personService) {
StaxXmlProcessor staxXmlProcessor) {
this.config = config; this.config = config;
this.hitsService = hitsService; this.hitsService = hitsService;
this.userPackageService = userPackageService; this.userPackageService = userPackageService;
@ -65,126 +54,76 @@ public class SignalService {
this.phoneService = phoneService; this.phoneService = phoneService;
this.flagsService = flagsService; this.flagsService = flagsService;
this.personService = personService; this.personService = personService;
this.staxXmlProcessor = staxXmlProcessor;
} }
public boolean isPackageNotUnique(MonitoringRequest request) { public boolean isPackageNotUnique(MonitoringRequest request) {
return userPackageService.isPackageNotUnique(request.getUserId(), request.getPackageName()); return userPackageService.isPackageNotUnique(request.getUserId(), request.getPackageName());
} }
public Long registerPackage(MonitoringRequest request) { public Integer registerPackage(MonitoringRequest request) {
UserPackage userPackage = UserPackage.builder() UserPackage userPackage = UserPackage.builder()
.userId(request.getUserId()) .userId(request.getUserId())
.packageName(request.getPackageName()) .packageName(request.getPackageName())
.createdAt(LocalDateTime.now()) .createdAt(LocalDateTime.now())
.status(Status.PROCESSING.name()) .status(Status.PROCESSING.name())
.build(); .build();
return userPackageService.insertPackage(userPackage); Integer packageId = userPackageService.insertPackage(userPackage);
} List<Subject> subjects = request.getSubjects().getSubject();
for (int i = 0; i < subjects.size(); i += batchSize) {
public void registerSubjects(String filePath, Long packageId) { int end = Math.min(i + batchSize, subjects.size());
log.info("Start registering subjects. PackageId: {}", packageId); phoneFidMapService.registerSubjects(subjects.subList(i, end), packageId); // TODO преобразовывать список в List<PhoneFidMap> ?
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) {
staxXmlProcessor.read(in, MonitoringRequest.class,
request -> {
if (!request.getSubjects().getSubject().isEmpty()) {
phoneFidMapService.registerSubjects(request.getSubjects().getSubject(), packageId);
log.trace("Registered subject's batch. Total count: {}. PackageId: {}", request.getSubjects().getSubject().size(), packageId);
request.getSubjects().getSubject().clear();
}
},
request -> request.getSubjects().getSubject().isEmpty()
,
batchSize, "/MonitoringRequest/Subjects/Subject");
} catch (IOException e) {
throw new RuntimeException("Error while parsing monitoring request", e);
} }
log.info("Subjects were registered. PackageId: {}", packageId); return packageId;
} }
/** public List<PhoneService.FidsPhoneData> registerSubjectsFidAndDebts(Integer packageId) {
* Обрабатывает все PhoneFidMap по packageId, выгружая их пачками и фильтруя по переданному фильтру List<PhoneFidMap> subjects = phoneFidMapService.findPhoneFidMaps(packageId);
*/ return updateFlags(subjects, packageId);
public UpdateResult updateSubjects(Long packageId, Predicate<PhoneFidMap> filter) {
boolean updated = false;
boolean noFidsFound = true;
int offset = 0;
List<PhoneFidMap> batch;
do {
batch = phoneFidMapService.findFullPhoneFidMap(packageId, offset, batchSize);
List<PhoneFidMap> filteredItems;
if (filter != null) {
filteredItems = batch.stream().filter(filter).toList();
} else {
filteredItems = batch;
}
if (!updated && !filteredItems.isEmpty()) {
updated = true;
}
if (!filteredItems.isEmpty()) {
boolean fidsFound = updateFlags(filteredItems, packageId);
if (noFidsFound) {
noFidsFound = !fidsFound;
}
}
offset += batchSize;
} while (!batch.isEmpty());
return new UpdateResult(updated, noFidsFound);
} }
/** public List<PhoneService.FidsPhoneData> updateFlags(List<PhoneFidMap> subjects, Integer packageId) {
* Обрабатывает пачку PhoneFidMap: обновляет фиды и флаги просрочек List<PhoneService.FidsPhoneData> fidsPhoneDataList = phoneService.findFidsPhoneData(subjects);
* @return fidsFound true - если хотя бы по одному номеру был найден фид, false - в противном случае
*/
public boolean updateFlags(List<PhoneFidMap> subjects, Long packageId) {
log.info("Start calculating fids and flags for subjects batch. PackageId: {}", packageId);
Map<String, Integer> fidsMap = phoneService.findFidsPhoneData(subjects);
LocalDateTime calculatedAt = LocalDateTime.now(); LocalDateTime calculatedAt = LocalDateTime.now();
boolean fidsFound = fidsMap.values().stream().anyMatch(Objects::nonNull); for (int i = 0; i < fidsPhoneDataList.size(); i += batchSize) {
Map<Integer, FlagsService.FlagsData> flagsDataMap = flagsService.findFlags(fidsMap.values().stream().filter(Objects::nonNull).toList()); int end = Math.min(i + batchSize, fidsPhoneDataList.size());
List<PhoneFidMap> subjectToUpdate = new ArrayList<>(); List<PhoneService.FidsPhoneData> currentList = fidsPhoneDataList.subList(i, end);
Map<Integer, FlagsService.FlagsData> flagsDataMap = flagsService.findFlags(currentList.stream().map(PhoneService.FidsPhoneData::getFid).filter(Objects::nonNull).toList());
List<PhoneFidMap> subjectToUpdate = new ArrayList<>();
subjects.forEach(subject -> { currentList.forEach(data -> {
Integer fid = fidsMap.get("9" + subject.getPhone()); PhoneFidMap subject;
if (fid != null) { if (data.getFid() != null) {
FlagsService.FlagsData flagsData = flagsDataMap.get(fid); FlagsService.FlagsData flagsData = flagsDataMap.get(data.getFid());
subject = PhoneFidMap.builder() subject = PhoneFidMap.builder()
.id(subject.getId()) .id(data.getId())
.packageId(packageId) .packageId(packageId)
.subjectId(subject.getSubjectId()) .subjectId(data.getSubjectId())
.phone(subject.getPhone()) .phone(data.getPhone())
.fid(fid) .fid(data.getFid())
.flagDebt5000(flagsData.getFlagDebt5000()) .flagDebt5000(flagsData.getFlagDebt5000())
.flag90days(flagsData.getFlag90days()) .flag90days(flagsData.getFlag90days())
.calculatedAt(calculatedAt) .calculatedAt(calculatedAt)
.build(); .build();
} else { } else {
subject = PhoneFidMap.builder() subject = PhoneFidMap.builder()
.id(subject.getId()) .id(data.getId())
.packageId(packageId) .packageId(packageId)
.subjectId(subject.getSubjectId()) .subjectId(data.getSubjectId())
.phone(subject.getPhone()) .phone(data.getPhone())
.calculatedAt(calculatedAt) .calculatedAt(calculatedAt)
.build(); .build();
}
subjectToUpdate.add(subject);
});
int updateBatchSize = batchSize / 8; // 8 параметров на одну запись для обновления. Максимальное количество параметров ~65000
for (int j = 0; j < subjectToUpdate.size(); j += updateBatchSize) {
int endIndex = Math.min(j + updateBatchSize, subjectToUpdate.size());
phoneFidMapService.updatePhoneFidMaps(subjectToUpdate.subList(j, endIndex));
} }
subjectToUpdate.add(subject);
});
int updateBatchSize = batchSize / 9; // 9 параметров на одну запись для обновления. Максимальное количество параметров ~65000
for (int j = 0; j < subjectToUpdate.size(); j += updateBatchSize) {
int endIndex = Math.min(j + updateBatchSize, subjectToUpdate.size());
phoneFidMapService.updatePhoneFidMaps(subjectToUpdate.subList(j, endIndex));
log.trace("Updated fids and flags for subject's batch from: {} to: {}. Total count: {}. PackageId: {}", j, endIndex, subjectToUpdate.size(), packageId);
} }
log.info("Finish calculating fids and flags for subjects. PackageId: {}. Batch size: {}", packageId, subjects.size()); return fidsPhoneDataList;
return fidsFound;
} }
public void rejectPackage(MonitoringRequest request) { public void rejectPackage(MonitoringRequest request) {
@ -197,82 +136,40 @@ public class SignalService {
userPackageService.insertPackage(userPackage); userPackageService.insertPackage(userPackage);
} }
public void updatePackageStatus(Long packageId, Status status) { public void updatePackageStatus(Integer packageId, Status status) {
userPackageService.updatePackageStatus(packageId, status); userPackageService.updatePackageStatus(packageId, status);
} }
public void updatePackageOnMonitoringSuccess(Long packageId, LocalDateTime monitoringAt) { public Signals buildSignals(Integer packageId, List<PhoneService.FidsPhoneData> fids) {
userPackageService.updatePackageOnMonitoringSuccess(packageId, monitoringAt);
}
/**
* Формирует файл запроса в официальный сервис сигналов, выгружая паспортные данные пачками и сразу записывая их в файл
*
* @return Путь к файлу запроса к официальному сервису сигналов на постановку на мониторинг
*/
public String writeSignals(Long packageId) {
String folderPath = config.getLoadDir() + File.separator + "tmp_folder" + File.separator;
String filePath = folderPath + UUID.randomUUID() + "_output.xml";
CTUtil.createFolder(folderPath);
Signals signals = buildSignals(packageId);
SignalsStaxXmlWriter signalsStaxXmlWriter = new SignalsStaxXmlWriter(config.getEncoding());
signalsStaxXmlWriter.writeWithStax(filePath,
signals,
writer -> buildPersons(packageId, writer));
return filePath;
}
private Signals buildSignals(Long packageId) {
UserPackage userPackage = userPackageService.findPackage(packageId); UserPackage userPackage = userPackageService.findPackage(packageId);
Signals signals = new Signals(); Signals signals = new Signals();
signals.setOnline("2"); // Всегда=2 (только онлайн-сигналы) signals.setOnline("2"); // Всегда=2 (только онлайн-сигналы)
signals.setProcessWithErrors("1"); // Всегда=1 (обработать пакет полностью, по обнаруженным ошибкам (при наличии) сформировать файл отказа, записи без ошибок установить на мониторинг)
signals.setId(userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName()); // <MEMBERCODE>_<PackageName> signals.setId(userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName()); // <MEMBERCODE>_<PackageName>
Auth auth = new Auth(); Auth auth = new Auth();
auth.setUser(config.getSignalsuser()); auth.setUser(config.getSignalsuser());
signals.setAuth(auth); signals.setAuth(auth);
for (int i = 0; i < fids.size(); i += batchSize) {
int end = Math.min(i + batchSize, fids.size());
List<Person> persons = findPersons(fids.subList(i, end));
if (!persons.isEmpty()) {
signals.getConditions().getPersons().getPerson().addAll(persons);
}
}
return signals; return signals;
} }
/** private List<Person> findPersons(List<PhoneService.FidsPhoneData> fidsPhoneData) {
* Обрабатывает все PhoneFidMap по packageId, выгружая их пачками и фильтруя по переданному фильтру.
* writer записывает пачку сразу в файл
*/
private void buildPersons(Long packageId, Consumer<List<Person>> writer) {
int offset = 0;
List<PhoneFidMap> batch;
do {
batch = phoneFidMapService.findFullPhoneFidMap(packageId, offset, batchSize);
List<Person> persons = findPersons(batch);
if (!persons.isEmpty()) {
writer.accept(persons); // записывает пачку Persons в файл
}
offset += batchSize;
} while (!batch.isEmpty());
}
/**
* Формирует список Person для постановки на мониторинг в официальный сервис сигналов на основе списка PhoneFidMap
*/
private List<Person> findPersons(List<PhoneFidMap> subjects) {
if (subjects.isEmpty()) {
return Collections.emptyList();
}
List<Person> persons = new ArrayList<>(); List<Person> persons = new ArrayList<>();
Map<Integer, PersonService.PersonData> personFidMap = personService.findPersonData(subjects.stream() Map<Integer, PersonService.PersonData> personFidMap = personService.findPersonData(fidsPhoneData.stream()
.map(PhoneFidMap::getFid) .map(PhoneService.FidsPhoneData::getFid)
.filter(Objects::nonNull).toList()); .filter(Objects::nonNull).toList());
subjects.forEach(data -> { fidsPhoneData.forEach(data -> {
if (data.getFid() != null) { if (data.getFid() != null) {
PersonService.PersonData personData = personFidMap.get(data.getFid()); PersonService.PersonData personData = personFidMap.get(data.getFid());
Person person = PersonFactoryBuilder.builder() Person person = PersonFactoryBuilder.builder()
.personData(personData) .personData(personData)
.uid(data.getId()) .uid(data.getSubjectId())
.build(); .build();
if (person != null) { if (person != null) {
persons.add(person); persons.add(person);
@ -282,49 +179,14 @@ public class SignalService {
return persons; return persons;
} }
public void updateSubjectsErrors(String filePath, Long packageId) {
log.info("Start updating subjects errors. PackageId: {}", packageId);
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) {
staxXmlProcessor.read(in, MonitoringReportErrors.class,
request -> {
if (!request.getPersons().isEmpty()) {
List<PhoneFidMap> subjects = request.getPersons().stream().map(p -> {
log.warn("Ошибка при формировании субъекта. package_id = {}, id = {}. Описание: {}", packageId, p.getUid(), p.getValue());
return PhoneFidMap.builder()
.id(p.getUid())
.errorText(p.getValue())
.build();
}).toList();
phoneFidMapService.updatePhoneFidMapsErrors(subjects);
log.trace("Updated subject's batch. Total count: {}. PackageId: {}", request.getPersons().size(), packageId);
request.getPersons().clear();
}
},
request -> request.getPersons().isEmpty()
,
batchSize, "/Errors/p");
} catch (IOException e) {
throw new RuntimeException("Error while parsing MonitoringReportErrors", e);
}
log.info("Subject's errors were updated. PackageId: {}", packageId);
}
public List<UserPackage> findActivePackages(String userId) { public List<UserPackage> findActivePackages(String userId) {
return userPackageService.findUserPackages(userId, Status.ON_MONITORING); return userPackageService.findUserPackages(userId, Status.ON_MONITORING);
} }
public List<UserPackage> findAllPackages(String userId) {
return userPackageService.findAllPackagesByUserId(userId);
}
public boolean isPackageExists(String username, String packageName) { public boolean isPackageExists(String username, String packageName) {
return userPackageService.isPackageExists(username, packageName, Status.ON_MONITORING); return userPackageService.isPackageExists(username, packageName, Status.ON_MONITORING);
} }
public boolean isPackagesByStatusExist(String username, String packageName, Status status) {
return userPackageService.hasActivePackages(username, packageName, status);
}
public void deletePackage(String username, String packageName, LocalDateTime deactivatedAt) { public void deletePackage(String username, String packageName, LocalDateTime deactivatedAt) {
userPackageService.deletePackage(username, packageName, Status.DELETED, Status.ON_MONITORING, deactivatedAt); userPackageService.deletePackage(username, packageName, Status.DELETED, Status.ON_MONITORING, deactivatedAt);
} }
@ -333,34 +195,15 @@ public class SignalService {
return userPackageService.findAllPackagesByStatus(Status.ON_MONITORING); return userPackageService.findAllPackagesByStatus(Status.ON_MONITORING);
} }
public List<UserPackage> findPackagesOnProcessing() { public List<PhoneFidMap> findFullSubjectsData(Integer packageId) {
return userPackageService.findAllPackagesByStatus(Status.PROCESSING); return phoneFidMapService.findFullPhoneFidMap(packageId);
} }
public void insertHits(List<Hit> hits) { public void insertHits(List<Hit> hits) {
hitsService.insertHits(hits); hitsService.insertHits(hits);
} }
public void updateLastDownloadedReport(Long id, String fileName) { public void updateLastDownloadedReport(Integer id, String fileName) {
userPackageService.updatePackageLastDownloadedReport(id, fileName); userPackageService.updatePackageLastDownloadedReport(id, fileName);
} }
public PhoneFidMap findPhoneFidMapById(Long id) {
return phoneFidMapService.findPhoneFidMapById(id);
}
public boolean hasNonNullfids(Long packageId) {
return phoneFidMapService.hasNonNullfids(packageId);
}
public UserPackage findPackage(Long packageId) {
return userPackageService.findPackage(packageId);
}
@Getter
@AllArgsConstructor
public static class UpdateResult {
private boolean updated;
private boolean noFidsFound;
}
} }

View file

@ -1,76 +0,0 @@
package ru.nbch.credit_tracker.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
import ru.nbch.credit_tracker.entities.dto.UserPackage;
import ru.nbch.credit_tracker.enums.Status;
import ru.nbch.credit_tracker.service.signal.SignalRestService;
import java.util.List;
/**
* Сервис для завершения обработки пакетов находящихся в статусе PROCESSING
* Запускается при старте приложения и отрабатывает 1 раз
*/
@Slf4j
@Service
@EnableAspectJAutoProxy(exposeProxy = true)
public class UpdateProcessingPackagesService {
private UpdateProcessingPackagesService self;
private final SignalService signalService;
private final SignalRestService signalRestService;
private final MonitoringErrorProcesingService monitoringErrorProcesingService;
public UpdateProcessingPackagesService(SignalService signalService,
SignalRestService signalRestService,
MonitoringErrorProcesingService monitoringErrorProcesingService) {
this.signalService = signalService;
this.signalRestService = signalRestService;
this.monitoringErrorProcesingService = monitoringErrorProcesingService;
}
public void run() {
log.info("Start updating processing packages");
List<UserPackage> packages = signalService.findPackagesOnProcessing();
for (UserPackage userPackage : packages) {
log.info("Updating flags for Package {}", userPackage.getPackageName());
getCurrentProxy().process(userPackage.getId(), userPackage.getPackageName());
}
log.info("Finish updating processing packages");
}
@SetAndClearMdc(argIndex = 1)
public void process(Long packageId, String packageName) {
try {
SignalService.UpdateResult updateResult = signalService.updateSubjects(packageId, null);
if (updateResult.isNoFidsFound()) {
log.info("No fids found for PackageId: {} . Package status ON_MONITORING. No registration in signal service.", packageId);
signalService.updatePackageStatus(packageId, Status.ON_MONITORING);
return;
}
if (signalRestService.setupMonitoring(packageId)) {
log.info("Package was successfully registered in signal service. PackageId: {}", packageId);
signalService.updatePackageStatus(packageId, Status.ON_MONITORING);
monitoringErrorProcesingService.findErrors(packageId);
} else {
log.info("Package registration was rejected by signal service. PackageId: {}", packageId);
signalService.updatePackageStatus(packageId, Status.ERROR);
}
} catch (Exception e) {
signalService.updatePackageStatus(packageId, Status.ERROR);
log.error("Ошибка при поиске фидов или расчете флагов просрочек. Package_id {}", packageId, e);
}
}
private UpdateProcessingPackagesService getCurrentProxy() {
if (self == null) {
self = (UpdateProcessingPackagesService) AopContext.currentProxy();
}
return self;
}
}

View file

@ -1,82 +1,66 @@
package ru.nbch.credit_tracker.service; package ru.nbch.credit_tracker.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
import ru.nbch.credit_tracker.entities.dto.UserPackage;
import ru.nbch.credit_tracker.entities.signal_package.Signals;
import ru.nbch.credit_tracker.enums.Status;
import ru.nbch.credit_tracker.service.indic.PhoneService;
import ru.nbch.credit_tracker.service.signal.SignalRestService;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.List; import java.util.List;
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.Executors;
import org.slf4j.MDC; import java.util.concurrent.ScheduledExecutorService;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import java.util.concurrent.TimeUnit;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.dto.UserPackage;
import ru.nbch.credit_tracker.enums.Status;
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
import ru.nbch.credit_tracker.service.signal.SignalRestService;
/**
* Сервис периодического обновления фидов и флагов просрочек по пакетам находящимся в статусе ON_MONITORING
* По обновленным пакетам формируется новый запрос постановки на мониторинг в официальный сервис сигналов
*/
@Slf4j @Slf4j
@Service @Service
public class UpdatingFlagsService { public class UpdatingFlagsService {
private final SignalService signalService; private final SignalService signalService;
private final SignalRestService signalRestService; private final SignalRestService signalRestService;
private final MonitoringErrorProcesingService monitoringErrorProcesingService;
private final Long daysToUpdateFlags; private final Long daysToUpdateFlags;
private final String updateFlagsCronExpression; private final Long updateFlagsInterval;
private final PhoneFidMapMapper phoneFidMapMapper;
public UpdatingFlagsService(SignalService signalService, public UpdatingFlagsService(SignalService signalService,
SignalRestService signalRestService, SignalRestService signalRestService,
MonitoringErrorProcesingService monitoringErrorProcesingService, CreditTrackerSettings config) {
CreditTrackerSettings config,
PhoneFidMapMapper phoneFidMapMapper) {
this.signalService = signalService; this.signalService = signalService;
this.signalRestService = signalRestService; this.signalRestService = signalRestService;
this.monitoringErrorProcesingService = monitoringErrorProcesingService;
this.daysToUpdateFlags = config.getDaysToUpdateFlags() != null ? config.getDaysToUpdateFlags() : 1; this.daysToUpdateFlags = config.getDaysToUpdateFlags() != null ? config.getDaysToUpdateFlags() : 1;
this.updateFlagsCronExpression = config.getUpdateFlagsCronExpression() != null ? config.getUpdateFlagsCronExpression() : "*/10 * * * * *"; this.updateFlagsInterval = config.getUpdateFlagsInterval() != null ? config.getUpdateFlagsInterval() : 1;
this.phoneFidMapMapper = phoneFidMapMapper;
} }
public void run() { public void run() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.setPoolSize(1); scheduler.scheduleAtFixedRate(this::update, 0, updateFlagsInterval, TimeUnit.DAYS);
scheduler.initialize();
scheduler.schedule(this::update, new CronTrigger(updateFlagsCronExpression));
} }
public void update() { private void update() {
log.info("Start updating flags"); log.info("Start updating flags");
List<UserPackage> packages = signalService.findPackagesOnMonitoring(); List<UserPackage> packages = signalService.findPackagesOnMonitoring();
for (UserPackage userPackage : packages) { for (UserPackage userPackage : packages) {
MDC.put("ru.nbch.credit_tracker.log.mdc.key", "[" + userPackage.getPackageName() +"]"); log.info("Updating flags for Package {}", userPackage.getPackageName());
log.info("Check on updating flags for Package {}", userPackage.getPackageName()); List<PhoneFidMap> subjects = signalService.findFullSubjectsData(userPackage.getId())
boolean hasOldRow = phoneFidMapMapper.hasOldRow(userPackage.getId(), daysToUpdateFlags.intValue()); .stream().filter(subject -> subject.getCalculatedAt() != null && hasDaysPassed(subject.getCalculatedAt())).toList();
log.info("There are {} old rows", hasOldRow ? "exist" : "doesn't exist"); updateFlags(userPackage.getId(), subjects, userPackage.getPackageName());
if (hasOldRow) {
updateFlags(userPackage);
}
MDC.remove("ru.nbch.credit_tracker.log.mdc.key");
} }
log.info("Finish updating flags"); log.info("Finish updating flags");
} }
private void updateFlags(UserPackage userPackage) { private void updateFlags(Integer packageId, List<PhoneFidMap> subjects, String packageName) {
Long packageId = userPackage.getId();
String packageName = userPackage.getPackageName();
try { try {
signalService.updatePackageStatus(packageId, Status.PROCESSING); signalService.updatePackageStatus(packageId, Status.PROCESSING);
SignalService.UpdateResult updateResult = signalService.updateSubjects(packageId, null); List<PhoneService.FidsPhoneData> phoneFidsData = signalService.updateFlags(subjects, packageId);
if (updateResult.isUpdated()) { if (!phoneFidsData.isEmpty()) {
if (signalRestService.setupMonitoring(packageId)) { Signals signals = signalService.buildSignals(packageId, phoneFidsData);
LocalDateTime monitoringAt = userPackage.getMonitoringAt() != null ? userPackage.getMonitoringAt() : LocalDateTime.now(); if (signalRestService.update(signals)) {
log.info("Flags were updated successfully. PackageId: {} PackageName: {} MonitoringAt: {}. Package status changed to ON_MONITORING", packageId, packageName, monitoringAt); log.info("Flags were updated successfully. PackageId: {} PackageName: {}. Package status changed to ON_MONITORING", packageId, packageName);
signalService.updatePackageOnMonitoringSuccess(packageId, monitoringAt); signalService.updatePackageStatus(packageId, Status.ON_MONITORING);
monitoringErrorProcesingService.findErrors(packageId);
} else { } else {
log.info("Updated package registration was rejected by signal service. PackageId: {} PackageName: {}", packageId, packageName); log.info("Updated package registration was rejected by signal service. PackageId: {} PackageName: {}", packageId, packageName);
signalService.updatePackageStatus(packageId, Status.ERROR); signalService.updatePackageStatus(packageId, Status.ERROR);

View file

@ -70,27 +70,23 @@ public class PersonService {
} }
private Map<Integer, PassportData> findPassportData(List<Integer> fids) { private Map<Integer, PassportData> findPassportData(List<Integer> fids) {
Map<Integer, PassportData> resultMap = new HashMap<>(); Map<Integer, PassportData> passportDataMap = new HashMap<>();
List<PassportData> passports = mapper.findPassportData(fids); List<PassportData> passports = mapper.findPassportData(fids);
Map<Integer, List<PassportData>> passportsMap = passports.stream()
.collect(Collectors.groupingBy(PassportData::getFid));
fids.forEach(fid -> { fids.forEach(fid -> {
PassportData passport = findPassport(passportsMap.get(fid)); PassportData passport = findPassport(passports.stream()
.filter(passportData -> passportData.getFid().equals(fid))
.collect(Collectors.toList()));
if (passport != null) { if (passport != null) {
resultMap.put(fid, passport); passportDataMap.put(fid, passport);
} }
}); });
return resultMap; return passportDataMap;
} }
private PassportData findPassport(List<PassportData> passports) { private PassportData findPassport(List<PassportData> passports) {
if (passports == null || passports.isEmpty()) {
return null;
}
List<PassportData> documents = passports.stream() List<PassportData> documents = passports.stream()
.filter(this::isDUL) .filter(this::isDUL)
.toList(); // берем только ДУЛ .toList(); // берем только ДУЛ
@ -143,7 +139,7 @@ public class PersonService {
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
idType2 = null; idType2 = null;
} }
return (idType != null && idType <= 30 && idType != 12) || (idType2 != null && (idType2 >= 1 || idType2 <= 999)); return (idType != null && idType <= 30) || (idType2 != null && (idType2 >= 1 || idType2 <= 999));
} }
private boolean requiredFieldPresent(NameData nameData, PassportData passportData) { private boolean requiredFieldPresent(NameData nameData, PassportData passportData) {

View file

@ -1,5 +1,6 @@
package ru.nbch.credit_tracker.service.indic; package ru.nbch.credit_tracker.service.indic;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -7,10 +8,7 @@ import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
import ru.nbch.credit_tracker.mapper.indic.PhoneMapper; import ru.nbch.credit_tracker.mapper.indic.PhoneMapper;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Comparator; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@ -22,13 +20,28 @@ public class PhoneService {
this.mapper = mapper; this.mapper = mapper;
} }
/** public List<FidsPhoneData> findFidsPhoneData(List<PhoneFidMap> subjects) {
* Ищет фиды по номерам телефона List<FidsPhoneData> fidsPhoneDataList = new ArrayList<>();
* @return Map: key - номер телефона; value - fid int batchSize = 10000;
*/ for (int i = 0; i < subjects.size(); i += batchSize) {
public Map<String, Integer> findFidsPhoneData(List<PhoneFidMap> subjects) { int end = Math.min(i + batchSize, subjects.size());
List<String> phones = subjects.stream().map(subject -> "9" + subject.getPhone()).toList(); List<PhoneFidMap> currentSubjects = subjects.subList(i, end);
return convertFidsDataToMap(mapper.findFids(phones)); List<String> phones = currentSubjects.stream().map(subject -> "9" + subject.getPhone()).toList();
List<FidsData> fidsData = mapper.findFids(phones);
Map<String, Integer> fidsMap = convertFidsDataToMap(fidsData);
currentSubjects.forEach(subject -> {
String phone = "9" + subject.getPhone();
Integer fid = fidsMap.get(phone);
if (fid != null) {
fidsPhoneDataList.add(new FidsPhoneData(subject.getId(), fid, subject.getPhone(), subject.getSubjectId()));
} else {
fidsPhoneDataList.add(new FidsPhoneData(subject.getId(), null, subject.getPhone(), subject.getSubjectId()));
}
});
}
return fidsPhoneDataList;
} }
private Map<String, Integer> convertFidsDataToMap(List<FidsData> fidsData) { private Map<String, Integer> convertFidsDataToMap(List<FidsData> fidsData) {
@ -48,6 +61,16 @@ public class PhoneService {
)); ));
} }
@Getter
@Setter
@AllArgsConstructor
public static class FidsPhoneData {
private Integer id;
private Integer fid;
private String phone;
private String subjectId;
}
@Getter @Getter
@Setter @Setter
public static class FidsData { public static class FidsData {

View file

@ -4,7 +4,6 @@ import jakarta.xml.bind.DatatypeConverter;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.enums.SignalError; import ru.nbch.credit_tracker.enums.SignalError;
import ru.nbch.credit_tracker.mapper.scoring.ModelUsersMapper; import ru.nbch.credit_tracker.mapper.scoring.ModelUsersMapper;
@ -14,23 +13,17 @@ import java.util.List;
@Service @Service
public class AuthorizationService { public class AuthorizationService {
private static final String SGNL_CODE = "SGNL"; private static final String SGNL_CODE = "SGNL";
private static final String SALT = "-*-XUSER_"; private static final String SALT = "-*-XUSER_"; // TODO move salt to props?
private final ModelUsersMapper mapper; private final ModelUsersMapper mapper;
private final String encoding;
public AuthorizationService(ModelUsersMapper mapper, public AuthorizationService(ModelUsersMapper mapper) {
CreditTrackerSettings settings) {
this.mapper = mapper; this.mapper = mapper;
this.encoding = settings.getEncoding();
} }
public AuthResult findAuthInfo(String userId, String password) throws Exception { public AuthResult findAuthInfo(String userId, String password) throws Exception {
if (userId.length() > 12) {
return new AuthResult(false, SignalError.ERROR_005);
}
String hashedPassword = hashPassword(password); String hashedPassword = hashPassword(password);
List<String> productCodes = mapper.findUserProductCodes(userId, hashedPassword); List<String> productCodes = mapper.findUserProductCodes(userId, hashedPassword); // TODO столбец username имеет ограничение на длину. Добавить обработку или валиться с 500?
if (productCodes.isEmpty()) { if (productCodes.isEmpty()) {
return new AuthResult(false, SignalError.ERROR_005); return new AuthResult(false, SignalError.ERROR_005);
} }
@ -43,7 +36,7 @@ public class AuthorizationService {
private String hashPassword(String password) throws Exception { private String hashPassword(String password) throws Exception {
try { try {
MessageDigest md = MessageDigest.getInstance("MD5"); MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest((SALT + password).getBytes(encoding)); byte[] messageDigest = md.digest((SALT + password).getBytes("windows-1251"));
return DatatypeConverter.printHexBinary(messageDigest).toLowerCase(); return DatatypeConverter.printHexBinary(messageDigest).toLowerCase();
} catch (Exception e) { } catch (Exception e) {
throw new Exception("Unable to hash password", e); throw new Exception("Unable to hash password", e);

View file

@ -2,7 +2,7 @@ package ru.nbch.credit_tracker.service.signal;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap; import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.Subject; import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject;
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper; import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
import java.util.List; import java.util.List;
@ -16,27 +16,19 @@ public class PhoneFidMapService {
this.mapper = mapper; this.mapper = mapper;
} }
public void registerSubjects(List<Subject> subjects, Long packageId) { public void registerSubjects(List<Subject> subjects, Integer packageId) {
mapper.registerSubjects(subjects, packageId); mapper.registerSubjects(subjects, packageId);
} }
public List<PhoneFidMap> findFullPhoneFidMap(Long packageId, int offset, int limit) { public List<PhoneFidMap> findPhoneFidMaps(Integer packageId) {
return mapper.findFullPhoneFidMap(packageId, offset, limit); return mapper.findPhoneFidMaps(packageId);
}
public List<PhoneFidMap> findFullPhoneFidMap(Integer packageId) {
return mapper.findFullPhoneFidMap(packageId);
} }
public void updatePhoneFidMaps(List<PhoneFidMap> subjects) { public void updatePhoneFidMaps(List<PhoneFidMap> subjects) {
mapper.updatePhoneFidMaps(subjects); mapper.updatePhoneFidMaps(subjects);
} }
public void updatePhoneFidMapsErrors(List<PhoneFidMap> subjects) {
mapper.updatePhoneFidMapsErrors(subjects);
}
public PhoneFidMap findPhoneFidMapById(Long id) {
return mapper.findPhoneFidMapById(id);
}
public boolean hasNonNullfids(Long packageId) {
return mapper.hasNonNullFids(packageId);
}
} }

View file

@ -3,7 +3,7 @@ package ru.nbch.credit_tracker.service.signal;
import jakarta.xml.bind.DatatypeConverter; import jakarta.xml.bind.DatatypeConverter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.FileUrlResource; import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.*; import org.springframework.http.*;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -11,25 +11,17 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.external_response.errors.SgnlReport; import ru.nbch.credit_tracker.entities.response.external_errors.SgnlReport;
import ru.nbch.credit_tracker.entities.external_response.monitoring_report_file.SgnlReportMonitorigSetupError; import ru.nbch.credit_tracker.entities.response.online_report.SgnlOnlineReport;
import ru.nbch.credit_tracker.entities.external_response.online_report.SgnlOnlineReport; import ru.nbch.credit_tracker.entities.signal_package.Signals;
import ru.nbch.credit_tracker.service.SignalService;
import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor; import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor; import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
import ru.nbch.credit_tracker.utils.CTUtil;
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.nio.charset.Charset;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.Base64; import java.util.Base64;
import java.util.UUID;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
@Slf4j @Slf4j
@ -39,38 +31,25 @@ public class SignalRestService {
private static String UPDATE_URI = "update"; private static String UPDATE_URI = "update";
private static String DELETE_URI = "delete"; private static String DELETE_URI = "delete";
private static String GET_REPORTS_URI = "onlinereport"; private static String GET_REPORTS_URI = "onlinereport";
private static String GET_REPORT_URI = "report"; private static String DOWNLOAD_REPORT_URI = "onlinedownload";
private static String DOWNLOAD_REPORT_URI = "download";
private static String DOWNLOAD_ONLINE_REPORT_URI = "onlinedownload";
private final RestTemplate restTemplate; private final RestTemplate restTemplate;
private final IXmlProcessor xmlProcessor; private final IXmlProcessor xmlProcessor;
private final StaxXmlProcessor staxProcessor; private final StaxXmlProcessor staxProcessor;
private final SignalService signalService;
private final String authToken; private final String authToken;
private final CreditTrackerSettings config;
public SignalRestService(@Qualifier(value = "restTemplate") RestTemplate restTemplate, public SignalRestService(@Qualifier(value = "restTemplate") RestTemplate restTemplate,
IXmlProcessor xmlProcessor, IXmlProcessor xmlProcessor,
StaxXmlProcessor staxProcessor, StaxXmlProcessor staxProcessor,
SignalService signalService,
CreditTrackerSettings config) throws Exception { CreditTrackerSettings config) throws Exception {
this.restTemplate = restTemplate; this.restTemplate = restTemplate;
this.xmlProcessor = xmlProcessor; this.xmlProcessor = xmlProcessor;
this.staxProcessor = staxProcessor; this.staxProcessor = staxProcessor;
this.signalService = signalService;
this.config = config;
this.authToken = buildToken(config.getSignalsToken(), config.getSignalsuser()); this.authToken = buildToken(config.getSignalsToken(), config.getSignalsuser());
} }
/** public boolean update(Signals signals) throws Exception {
* Ставит пакет на мониторинг в официальный сервис сигналов Resource request = compressFile(signals);
* @return true - если пакет успешно поставился на мониторинг. false - в противном случае
*/
public boolean setupMonitoring(Long packageId) throws Exception {
String path = signalService.writeSignals(packageId);
Resource request = compressFile(path);
MultiValueMap<String, Resource> body = new LinkedMultiValueMap<>(); MultiValueMap<String, Resource> body = new LinkedMultiValueMap<>();
body.add("file", request); body.add("file", request);
@ -85,8 +64,6 @@ public class SignalRestService {
if (response.getStatusCode().value() == 302) { if (response.getStatusCode().value() == 302) {
// good response // good response
CTUtil.removeFile(path);
CTUtil.removeFile(path + ".gz");
return true; return true;
} else if (response.getStatusCode().value() == 200 && response.getBody() != null) { } else if (response.getStatusCode().value() == 200 && response.getBody() != null) {
SgnlReport error = staxProcessor.read(response.getBody(), SgnlReport.class); SgnlReport error = staxProcessor.read(response.getBody(), SgnlReport.class);
@ -95,80 +72,11 @@ public class SignalRestService {
} else { } else {
log.error("неизвестная ошибка при постановке пакета на мониторинг в официальный сервис сигналов: {}", response.getBody()); log.error("неизвестная ошибка при постановке пакета на мониторинг в официальный сервис сигналов: {}", response.getBody());
} }
CTUtil.removeFile(path);
CTUtil.removeFile(path + ".gz");
return false; return false;
} }
return false; return false;
} }
/**
* @return имя файла с ошибками по поставленному на мониторинг отчету
*/
public String getErrorFileName(Long packageId, String packCode) {
String url = GET_REPORT_URI + "?packCode=" + packCode;
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
String.class
);
String answer = response.getBody();
SgnlReport error = staxProcessor.read(answer, SgnlReport.class);
if (error.getError().getDescription() != null) {
log.error("Ошибка при получении имени файла ошибки из сервиса НБКИ. packCode={}. Описание: {}", packCode, error.getError().getDescription());
return null;
}
try {
SgnlReportMonitorigSetupError report = xmlProcessor.read(answer, SgnlReportMonitorigSetupError.class);
if (report.getOperationReport().getErrorsForNextReport() != null) {
String fileName = report.getOperationReport().getErrorsForNextReport().getFilename();
log.warn("Найдены ошибки по пакету. packCode={}, packageId={}, fileName = {}", packCode, packageId, fileName);
return fileName;
} else {
log.info("Пакет был поставлен на мониторинг без ошибок. packCode={}, packageId={}", packCode, packageId);
}
} catch (Exception e) {
log.error("Ошибка при получении имени файла ошибки из сервиса НБКИ. Код ошибки: {} packCode={}", response.getStatusCode().value(), packCode);
}
return null;
}
/**
* Загружает .gz отчет ошибок из официального сервиса сигналов, разархивирует в tmp_folder
*
* @return путь к разархивированному файлу. Пример: <loadDir>/tmp_folder/<package_id>/0001XX_MY_BATCH_223112.1.errors.xml.gz
*/
public String loadErrorFile(Long packageId, String fileName) {
String url = DOWNLOAD_REPORT_URI + "?fNameRequest=" + fileName;
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<byte[]> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
byte[].class
);
return unzipReport(response, packageId, fileName);
}
/**
* Удаляет пакет с мониторинга
*/
public void deletePackage(String username, String packageName) { public void deletePackage(String username, String packageName) {
String packCode = username.substring(0, 6) + "_" + packageName; String packCode = username.substring(0, 6) + "_" + packageName;
String url = DELETE_URI + "?packCode=" + packCode; String url = DELETE_URI + "?packCode=" + packCode;
@ -191,9 +99,6 @@ public class SignalRestService {
} }
} }
/**
* @return Список отчетов, по которым сработали сигналы из официального сервиса сигналов
*/
public SgnlOnlineReport getReports(String packCode) { public SgnlOnlineReport getReports(String packCode) {
String url = GET_REPORTS_URI + "?packCode=" + packCode; String url = GET_REPORTS_URI + "?packCode=" + packCode;
@ -224,13 +129,8 @@ public class SignalRestService {
} }
} }
/** public byte[] downloadReport(String reportName) {
* Загружает .gz отчет из официального сервиса сигналов, разархивирует в tmp_folder String url = DOWNLOAD_REPORT_URI + "?fNameReport=" + reportName;
*
* @return путь к разархивированному файлу. Пример: <loadDir>/tmp_folder/<package_id>/0001XX_MY_BATCH_204.1.online.2025-07-08T20-00-46.xml.gz.xml
*/
public String downloadReport(Long packageId, String reportName) {
String url = DOWNLOAD_ONLINE_REPORT_URI + "?fNameReport=" + reportName;
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken); headers.setBasicAuth(authToken);
@ -244,41 +144,18 @@ public class SignalRestService {
byte[].class byte[].class
); );
return unzipReport(response,packageId, reportName); byte[] answer = response.getBody();
} if (isXmlError(response.getBody())) {
SgnlReport error = staxProcessor.read(answer, SgnlReport.class);
private String unzipReport(ResponseEntity<byte[]> response, Long packageId, String reportName) {
boolean isGzipped = response.getHeaders().getContentType() != null
&& response.getHeaders().getContentType().toString().equals("application/x-gzip");
if (!isGzipped && isXmlError(response.getBody())) {
SgnlReport error = staxProcessor.read(response.getBody(), SgnlReport.class);
if (error.getError().getDescription() != null) { if (error.getError().getDescription() != null) {
log.error("Ошибка при скачивание отчета. fNameReport={}. Описание: {}", reportName, error.getError().getDescription()); log.error("Ошибка при скачивание отчета. fNameReport={}. Описание: {}", reportName, error.getError().getDescription());
return null; return null;
} }
log.error("Неизвестная ошибка при скачивание отчета. fNameReport={}", reportName); log.error("Неизвестная ошибка при скачивание отчета. fNameReport={}", reportName);
return null; return null;
} else {
String folderPath = config.getLoadDir() + File.separator + "tmp_folder" + File.separator;
String filePath = folderPath + UUID.randomUUID() + reportName + ".xml";
CTUtil.createFolder(folderPath);
try (InputStream in = new GZIPInputStream(new ByteArrayInputStream(response.getBody()));
OutputStream out = Files.newOutputStream(Path.of(filePath))) {
byte[] buffer = new byte[8 * 1024 * 1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
return filePath;
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
} }
return answer;
} }
private String buildToken(String signalsToken, String signalsuser) throws Exception { private String buildToken(String signalsToken, String signalsuser) throws Exception {
@ -294,20 +171,20 @@ public class SignalRestService {
} }
} }
public Resource compressFile(String path) throws Exception { private Resource compressFile(Signals signals) throws Exception {
try (InputStream in = Files.newInputStream(Path.of(path)); String requestData = xmlProcessor.asString(signals, false);
OutputStream out = Files.newOutputStream(Path.of(path + ".gz"));
GZIPOutputStream gzipOut = new GZIPOutputStream(out)) {
byte[] buffer = new byte[8 * 1024 * 1024]; ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int bytesRead; try (GZIPOutputStream gzipStream = new GZIPOutputStream(byteStream)) {
while ((bytesRead = in.read(buffer)) > 0) { gzipStream.write(requestData.getBytes(Charset.forName("windows-1251")));
gzipOut.write(buffer, 0, bytesRead);
}
gzipOut.finish();
return new FileUrlResource(path + ".gz");
} }
return new ByteArrayResource(byteStream.toByteArray()) {
@Override
public String getFilename() {
return "arhive.gz";
}
};
} }
private boolean isXmlError(byte[] data) { private boolean isXmlError(byte[] data) {

View file

@ -6,7 +6,6 @@ import ru.nbch.credit_tracker.enums.Status;
import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper; import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List; import java.util.List;
@Service @Service
@ -26,40 +25,28 @@ public class UserPackageService {
return mapper.isPackageExists(userId.substring(0, 6), packageName, status.name()); return mapper.isPackageExists(userId.substring(0, 6), packageName, status.name());
} }
public boolean hasActivePackages(String userId, String packageName, Status... status) {
return mapper.hasActivePackages(userId.substring(0, 6), packageName, Arrays.stream(status).map(Enum::name).toList());
}
public void deletePackage(String userId, String packageName, Status newStatus, Status previousStatus, LocalDateTime deactivatedAt) { public void deletePackage(String userId, String packageName, Status newStatus, Status previousStatus, LocalDateTime deactivatedAt) {
mapper.deletePackage(userId.substring(0, 6), packageName, newStatus.name(), previousStatus.name(), deactivatedAt); mapper.deletePackage(userId.substring(0, 6), packageName, newStatus.name(), previousStatus.name(), deactivatedAt);
} }
public Long insertPackage(UserPackage userPackage) { public Integer insertPackage(UserPackage userPackage) {
return mapper.insertPackage(userPackage); return mapper.insertPackage(userPackage);
} }
public void updatePackageStatus(Long packageId, Status status) { public void updatePackageStatus(Integer packageId, Status status) {
mapper.updatePackageStatus(packageId, status.name()); mapper.updatePackageStatus(packageId, status.name());
} }
public void updatePackageLastDownloadedReport(Long id, String fileName) { public void updatePackageLastDownloadedReport(Integer id, String fileName) {
mapper.updatePackageLastDownloadedReport(id, fileName); mapper.updatePackageLastDownloadedReport(id, fileName);
} }
public void updatePackageOnMonitoringSuccess(Long id, LocalDateTime monitoringAt) { public UserPackage findPackage(Integer id) {
mapper.updatePackageOnMonitoringSuccess(id, monitoringAt);
}
public UserPackage findPackage(Long id) {
return mapper.findPackage(id); return mapper.findPackage(id);
} }
public List<UserPackage> findUserPackages(String userId, Status... status) { public List<UserPackage> findUserPackages(String userId, Status status) {
return mapper.findUserPackages(userId.substring(0, 6), Arrays.stream(status).map(Enum::name).toList()); return mapper.findUserPackages(userId.substring(0, 6), status.name());
}
public List<UserPackage> findAllPackagesByUserId(String userId) {
return mapper.findAllPackagesByUserId(userId.substring(0, 6));
} }
public List<UserPackage> findAllPackagesByStatus(Status status) { public List<UserPackage> findAllPackagesByStatus(Status status) {

View file

@ -6,76 +6,40 @@ import javax.xml.stream.XMLStreamReader;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Deque; import java.util.Deque;
import java.util.Iterator; import java.util.Iterator;
import java.util.function.Consumer;
import java.util.function.Function;
public abstract class BaseStaxReader<T> implements StaxReader<T> { public abstract class BaseStaxReader<T> implements StaxReader<T> {
private final Deque<String> stack = new ArrayDeque<>(); private final Deque<String> stack = new ArrayDeque<>();
protected final StringBuilder buffer = new StringBuilder(); protected final StringBuilder buffer = new StringBuilder();
protected abstract T createObject(); protected abstract T createObject();
@Override @Override
public T read(XMLStreamReader reader) throws XMLStreamException { public T read(XMLStreamReader reader) throws XMLStreamException {
return read(reader, null, null, null, null);
}
public T read(XMLStreamReader reader, Consumer<T> objProcessor, Function<T, Boolean> emptyBatchCheckFunction, Integer batchSize, String endBatchElementPath) throws XMLStreamException {
T obj = createObject(); T obj = createObject();
int objCount = 0; while (reader.hasNext()) {
try { boolean breakExecution = false;
while (reader.hasNext()) { int ev = reader.next();
boolean breakExecution = false; switch (ev) {
int ev = reader.next(); case XMLStreamConstants.START_ELEMENT -> {
switch (ev) { buffer.setLength(0);
case XMLStreamConstants.START_ELEMENT -> { startElement(reader.getLocalName());
buffer.setLength(0);
startElement(reader.getLocalName());
innerProcessStartElement(reader, obj);
}
case XMLStreamConstants.CHARACTERS -> {
String text = reader.getText().trim();
if (!text.isEmpty()) buffer.append(text);
}
case XMLStreamConstants.ATTRIBUTE -> {
breakExecution = innerProcess(reader, obj);
}
case XMLStreamConstants.END_ELEMENT -> {
breakExecution = innerProcess(reader, obj);
String lastElementPath = getPath();
endElement();
if (objProcessor != null) {
if (endBatchElementPath.equals(lastElementPath)) {
objCount++;
if (objCount == batchSize) {
objProcessor.accept(obj); // обрабатываем пачку элементов
objCount = 0;
}
}
}
}
default -> {
}
} }
if (breakExecution) break; case XMLStreamConstants.CHARACTERS -> {
} String text = reader.getText().trim();
if (objProcessor != null) { if (!text.isEmpty()) buffer.append(text);
if (emptyBatchCheckFunction == null) {
objProcessor.accept(obj); // Дополнительная обработка пачки если: batchSize меньше количества элементов в xml или дообрабатываем "хвост" меньший чем batchSize
} else if (!emptyBatchCheckFunction.apply(obj)) { // Проверка на пустоту пачки, чтобы не обрабатывать пустой список
objProcessor.accept(obj);
} }
case XMLStreamConstants.END_ELEMENT -> {
breakExecution = innerProcess(reader, obj);
endElement();
}
default -> {}
} }
return obj; if (breakExecution) break;
} catch (Exception e) {
stack.clear();
throw e;
} }
return obj;
} }
protected abstract boolean innerProcess(XMLStreamReader reader, T obj) throws XMLStreamException; protected abstract boolean innerProcess(XMLStreamReader reader, T obj) throws XMLStreamException;
protected abstract void innerProcessStartElement(XMLStreamReader reader, T obj) throws XMLStreamException;
public void startElement(String localName) { public void startElement(String localName) {
localName = substringAfterColon(localName); localName = substringAfterColon(localName);

View file

@ -1,255 +0,0 @@
package ru.nbch.credit_tracker.service.xml.stax;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.io.IOException;
import java.io.Writer;
public class IndentingXMLEventWriter implements XMLEventWriter {
private final XMLEventWriter core;
private String indent = " ";
private final Characters indentEvent = new CharactersImpl() {
public String getData() {
return IndentingXMLEventWriter.this.indent;
}
};
private String newLine;
private final Characters newLineEvent = new CharactersImpl() {
public String getData() {
return IndentingXMLEventWriter.this.newLine;
}
};
private int depth = 0;
private boolean hasText;
private boolean hasEndTag;
public IndentingXMLEventWriter(XMLEventWriter core) {
if (core == null) {
throw new IllegalArgumentException();
} else {
this.core = core;
try {
this.newLine = System.getProperty("line.separator");
} catch (SecurityException var3) {
this.newLine = "\n";
}
}
}
public String getIndent() {
return this.indent;
}
public void setIndent(String indent) {
if (indent == null) {
throw new IllegalArgumentException();
} else {
this.indent = indent;
}
}
public String getNewLine() {
return this.newLine;
}
public void setNewLine(String newLine) {
if (newLine == null) {
throw new IllegalArgumentException();
} else {
this.newLine = newLine;
}
}
public void add(XMLEvent event) throws XMLStreamException {
switch (event.getEventType()) {
case 1:
this.newLine();
this.core.add(event);
this.hasText = false;
this.hasEndTag = false;
++this.depth;
return;
case 2:
--this.depth;
if (!this.hasText && this.hasEndTag) {
this.newLine();
}
this.core.add(event);
this.hasText = false;
this.hasEndTag = true;
return;
case 3:
case 5:
case 11:
if (!this.hasText) {
this.newLine();
}
this.core.add(event);
return;
case 4:
case 6:
case 12:
if (event.asCharacters().isWhiteSpace()) {
return;
}
this.hasText = true;
this.core.add(event);
return;
case 7:
case 9:
case 10:
default:
this.core.add(event);
return;
case 8:
this.core.add(event);
this.flush();
}
}
private void newLine() throws XMLStreamException {
this.core.add(this.newLineEvent);
for (int i = 0; i < this.depth; ++i) {
this.core.add(this.indentEvent);
}
}
public void add(XMLEventReader reader) throws XMLStreamException {
if (reader == null) {
throw new IllegalArgumentException();
} else {
while (reader.hasNext()) {
this.add(reader.nextEvent());
}
}
}
public void close() throws XMLStreamException {
this.core.close();
}
public void flush() throws XMLStreamException {
this.core.flush();
}
public NamespaceContext getNamespaceContext() {
return this.core.getNamespaceContext();
}
public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
this.core.setNamespaceContext(context);
}
public String getPrefix(String uri) throws XMLStreamException {
return this.core.getPrefix(uri);
}
public void setDefaultNamespace(String uri) throws XMLStreamException {
this.core.setDefaultNamespace(uri);
}
public void setPrefix(String prefix, String uri) throws XMLStreamException {
this.core.setPrefix(prefix, uri);
}
private abstract static class CharactersImpl implements Characters {
private CharactersImpl() {
}
public boolean isWhiteSpace() {
return true;
}
public boolean isCData() {
return false;
}
public boolean isIgnorableWhiteSpace() {
return true;
}
public int getEventType() {
return 4;
}
public Location getLocation() {
return null;
}
public boolean isStartElement() {
return false;
}
public boolean isAttribute() {
return false;
}
public boolean isNamespace() {
return false;
}
public boolean isEndElement() {
return false;
}
public boolean isEntityReference() {
return false;
}
public boolean isProcessingInstruction() {
return false;
}
public boolean isCharacters() {
return true;
}
public boolean isStartDocument() {
return false;
}
public boolean isEndDocument() {
return false;
}
public StartElement asStartElement() {
return null;
}
public EndElement asEndElement() {
return null;
}
public Characters asCharacters() {
return this;
}
public QName getSchemaType() {
return null;
}
public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException {
try {
writer.write(this.getData());
} catch (IOException var3) {
throw new XMLStreamException(var3);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more