From 3ed2902219e1411f41937fd2485ad8d046b62726 Mon Sep 17 00:00:00 2001 From: Mikhail Trofimov Date: Thu, 3 Jul 2025 14:06:20 +0000 Subject: [PATCH] Refactoring after review --- .../builder/PersonFactoryBuilder.java | 91 +++++++ .../config/rest/GlobalExceptionHandler.java | 36 ++- .../xml/XmlConfig.java} | 44 +-- .../entities/dto/{HitsData.java => Hit.java} | 2 +- .../{SubjectData.java => PhoneFidMap.java} | 8 +- .../{PackageData.java => UserPackage.java} | 4 +- .../credit_tracker/enums/EnumKeyMessage.java | 41 +++ .../credit_tracker/enums/IEnumKeyCode.java | 102 +++++++ .../credit_tracker/enums/SignalError.java | 17 +- .../credit_tracker/enums/XmlErrorFormat.java | 10 + .../exceptions/SignalClientException.java | 13 + .../exceptions/SignalErrorException.java | 29 -- .../exceptions/SignalException.java | 17 ++ .../exceptions/SignalServerException.java | 12 + .../credit_tracker/facade/SignalFacade.java | 250 +++++++----------- .../mapper/signal/HitsMapper.java | 14 + .../mapper/signal/PhoneFidMapMapper.java | 21 ++ .../mapper/signal/SignalMapper.java | 48 ---- .../mapper/signal/UserPackageMapper.java | 31 +++ .../service/MonitoringService.java | 89 +++---- .../credit_tracker/service/SignalService.java | 193 ++++++-------- .../service/UpdatingFlagsService.java | 24 +- .../service/indic/PhoneService.java | 12 +- .../service/signal/HitsService.java | 21 ++ .../service/signal/PhoneFidMapService.java | 34 +++ .../service/signal/SignalRestService.java | 28 +- .../service/signal/UserPackageService.java | 55 ++++ .../credit_tracker/utils/ValidationUtil.java | 59 ++++- .../nbch/credit_tracker/utils/ZipUtils.java | 28 ++ .../utils/error/ExceptionUtils.java | 18 ++ .../utils/error/SimpleMessageResolver.java | 13 + .../mybatis/mapper/signal/HitsMapper.xml | 16 ++ .../mapper/signal/PhoneFidMapMapper.xml | 63 +++++ .../mybatis/mapper/signal/SignalMapper.xml | 156 ----------- .../mapper/signal/UserPackageMapper.xml | 83 ++++++ .../nbch/credit_tracker/utils/UtilTest.java | 156 +++++++++++ .../monitoring_request/directory_request.zip | Bin 0 -> 154 bytes .../monitoring_request/empty_request.zip | 0 .../monitoring_request/invalid_id_request.zip | Bin 0 -> 415 bytes .../invalid_phone_request.zip | Bin 0 -> 422 bytes .../monitoring_request/invalid_xml.zip | Bin 0 -> 312 bytes .../monitoring_request/many_files_request.zip | Bin 0 -> 1134 bytes .../no_required_tag_request.zip | Bin 0 -> 376 bytes .../no_unique_ids_request.zip | Bin 0 -> 417 bytes .../monitoring_request/txt_request.zip | Bin 0 -> 156 bytes .../monitoring_request/valid_request.zip | Bin 0 -> 390 bytes 46 files changed, 1198 insertions(+), 640 deletions(-) create mode 100644 src/main/java/ru/nbch/credit_tracker/builder/PersonFactoryBuilder.java rename src/main/java/ru/nbch/credit_tracker/{service/xml/jaxb/XmlUtilService.java => config/xml/XmlConfig.java} (52%) rename src/main/java/ru/nbch/credit_tracker/entities/dto/{HitsData.java => Hit.java} (93%) rename src/main/java/ru/nbch/credit_tracker/entities/dto/{SubjectData.java => PhoneFidMap.java} (73%) rename src/main/java/ru/nbch/credit_tracker/entities/dto/{PackageData.java => UserPackage.java} (84%) create mode 100644 src/main/java/ru/nbch/credit_tracker/enums/EnumKeyMessage.java create mode 100644 src/main/java/ru/nbch/credit_tracker/enums/IEnumKeyCode.java create mode 100644 src/main/java/ru/nbch/credit_tracker/enums/XmlErrorFormat.java create mode 100644 src/main/java/ru/nbch/credit_tracker/exceptions/SignalClientException.java delete mode 100644 src/main/java/ru/nbch/credit_tracker/exceptions/SignalErrorException.java create mode 100644 src/main/java/ru/nbch/credit_tracker/exceptions/SignalException.java create mode 100644 src/main/java/ru/nbch/credit_tracker/exceptions/SignalServerException.java create mode 100644 src/main/java/ru/nbch/credit_tracker/mapper/signal/HitsMapper.java create mode 100644 src/main/java/ru/nbch/credit_tracker/mapper/signal/PhoneFidMapMapper.java delete mode 100644 src/main/java/ru/nbch/credit_tracker/mapper/signal/SignalMapper.java create mode 100644 src/main/java/ru/nbch/credit_tracker/mapper/signal/UserPackageMapper.java create mode 100644 src/main/java/ru/nbch/credit_tracker/service/signal/HitsService.java create mode 100644 src/main/java/ru/nbch/credit_tracker/service/signal/PhoneFidMapService.java create mode 100644 src/main/java/ru/nbch/credit_tracker/service/signal/UserPackageService.java create mode 100644 src/main/java/ru/nbch/credit_tracker/utils/ZipUtils.java create mode 100644 src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java create mode 100644 src/main/java/ru/nbch/credit_tracker/utils/error/SimpleMessageResolver.java create mode 100644 src/main/resources/mybatis/mapper/signal/HitsMapper.xml create mode 100644 src/main/resources/mybatis/mapper/signal/PhoneFidMapMapper.xml delete mode 100644 src/main/resources/mybatis/mapper/signal/SignalMapper.xml create mode 100644 src/main/resources/mybatis/mapper/signal/UserPackageMapper.xml create mode 100644 src/test/java/ru/nbch/credit_tracker/utils/UtilTest.java create mode 100644 src/test/resources/monitoring_request/directory_request.zip create mode 100644 src/test/resources/monitoring_request/empty_request.zip create mode 100644 src/test/resources/monitoring_request/invalid_id_request.zip create mode 100644 src/test/resources/monitoring_request/invalid_phone_request.zip create mode 100644 src/test/resources/monitoring_request/invalid_xml.zip create mode 100644 src/test/resources/monitoring_request/many_files_request.zip create mode 100644 src/test/resources/monitoring_request/no_required_tag_request.zip create mode 100644 src/test/resources/monitoring_request/no_unique_ids_request.zip create mode 100644 src/test/resources/monitoring_request/txt_request.zip create mode 100644 src/test/resources/monitoring_request/valid_request.zip diff --git a/src/main/java/ru/nbch/credit_tracker/builder/PersonFactoryBuilder.java b/src/main/java/ru/nbch/credit_tracker/builder/PersonFactoryBuilder.java new file mode 100644 index 0000000..90fe789 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/builder/PersonFactoryBuilder.java @@ -0,0 +1,91 @@ +package ru.nbch.credit_tracker.builder; + +import org.apache.commons.lang3.StringUtils; +import ru.nbch.credit_tracker.entities.signal_package.Person; +import ru.nbch.credit_tracker.service.indic.PersonService; +import ru.nbch.credit_tracker.utils.CTUtil; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.LocalDate; + +public class PersonFactoryBuilder { + private final static DateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy"); + + private final static String DEFAULT_DATE = "01.01.2000"; + private final static String IP = "0"; + private final static String OKSM = "999"; + private final static String CONSENT_PURPOSE = "16"; + private final static String REPORT_USER = "АО «НБКИ»"; + private final static String LIABILITY = "1"; + private final static String CONSENT_PERIOD = "3"; + private final static String REPORT_USER_REG_NUM = "1057746710713"; + private final static String REPORT_USER_TAX_ID = "7703548386"; + private final static String CONSENT_HASH = "hash"; + private final static String CONSENT_DIV_CODE = "000-000"; + private final static String INQ_PURPOSE = "16"; + + + private PersonService.PersonData personData; + private String uid; + + public static PersonFactoryBuilder builder() { + return new PersonFactoryBuilder(); + } + + public PersonFactoryBuilder personData(PersonService.PersonData personData) { + this.personData = personData; + return this; + } + + public PersonFactoryBuilder uid(String uid) { + this.uid = uid; + return this; + } + + public Person build() { + if (personData == null) { + return null; + } + PersonService.NameData nameData = personData.getName(); + PersonService.PassportData passportData = personData.getPassport(); + Person person = new Person(); + person.setS(nameData.getLastName()); + person.setN(nameData.getFirstName()); + person.setM(StringUtils.isNotBlank(nameData.getMiddleName()) ? nameData.getMiddleName() : null); + person.setD(DATE_FORMAT.format(CTUtil.localDatetoDate(nameData.getBirthDate()))); + + person.setPn(getPn(passportData.getSerNum(), passportData.getIdNum())); + person.setPd(passportData.getIssDate() != null ? DATE_FORMAT.format(CTUtil.localDatetoDate(passportData.getIssDate())) : DEFAULT_DATE); + person.setDt(StringUtils.isNotBlank(passportData.getIdType2()) ? passportData.getIdType2() : passportData.getIdType()); + person.setIp(IP); + person.setUid(uid); + person.setOksm(OKSM); + person.setConsentDate(DATE_FORMAT.format(CTUtil.localDatetoDate(LocalDate.now()))); + person.setConsentPurpose(CONSENT_PURPOSE); + person.setReportUser(REPORT_USER); + person.setLiability(LIABILITY); + person.setConsentPeriod(CONSENT_PERIOD); + person.setAgrDate(DATE_FORMAT.format(CTUtil.localDatetoDate(LocalDate.now()))); + person.setReportUserRegNum(REPORT_USER_REG_NUM); + person.setReportUserTaxID(REPORT_USER_TAX_ID); + person.setConsentHash(CONSENT_HASH); + + person.setCs(person.getS()); + person.setConsentN(person.getN()); + person.setConsentM(person.getM()); + person.setConsentBd(person.getD()); + person.setConsentPn(person.getPn()); + person.setConsentPd(person.getPd()); + person.setConsentDivCode(CONSENT_DIV_CODE); + person.setConsentDt(person.getDt()); + person.setInqPurpose(INQ_PURPOSE); + return person; + } + + private String getPn(String serNum, String idNum) { + String normSerNum = CTUtil.normalize(serNum); + String normIdNum = CTUtil.normalize(idNum); + return StringUtils.isNotBlank(normSerNum) ? normSerNum + normIdNum : normIdNum; + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java b/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java index 3ce661b..5f6ee25 100644 --- a/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/GlobalExceptionHandler.java @@ -6,22 +6,44 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; -import ru.nbch.credit_tracker.entities.response.errors.CommonError; -import ru.nbch.credit_tracker.exceptions.SignalErrorException; +import ru.nbch.credit_tracker.entities.response.errors.*; +import ru.nbch.credit_tracker.exceptions.SignalClientException; +import ru.nbch.credit_tracker.exceptions.SignalException; +import ru.nbch.credit_tracker.utils.error.SimpleMessageResolver; import java.nio.charset.Charset; @RestControllerAdvice public class GlobalExceptionHandler { - @ExceptionHandler(value = SignalErrorException.class, produces = MediaType.APPLICATION_XML_VALUE) - public ResponseEntity handleInvalidUser(SignalErrorException ex) { + private final SimpleMessageResolver messageResolver = new SimpleMessageResolver(); + + @ExceptionHandler(value = SignalException.class, produces = MediaType.APPLICATION_XML_VALUE) + public ResponseEntity handleClientException(SignalException ex) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(new MediaType("application", "xml", Charset.forName("windows-1251"))); - if (ex.isUserError()) { - return new ResponseEntity<>(ex.getError(), headers, HttpStatus.BAD_REQUEST); + CommonError commonError = getCommonError(ex); + commonError.setStatus("error"); + commonError.setErrorCode(ex.getErrorMessage().getSubject().getErrorCode()); + commonError.setErrorText(messageResolver.resolve(ex.getErrorMessage())); + + if (ex instanceof SignalClientException) { + return new ResponseEntity<>(commonError, headers, HttpStatus.BAD_REQUEST); } else { - return new ResponseEntity<>(ex.getError(), headers, HttpStatus.INTERNAL_SERVER_ERROR); + return new ResponseEntity<>(commonError, headers, HttpStatus.INTERNAL_SERVER_ERROR); } } + + private static CommonError getCommonError(SignalException ex) { + CommonError commonError; + switch (ex.getErrorFormat()) { + case MonitoringError -> commonError = new MonitoringError(); + case MonitoringActivePackagesError -> commonError = new MonitoringActivePackagesError(); + case MonitoringDownloadError -> commonError = new MonitoringDownloadError(); + case MonitoringReportListError -> commonError = new MonitoringReportListError(); + case MonitoringPackageDeleteError -> commonError = new MonitoringPackageDeleteError(); + default -> throw new IllegalStateException("Unsupported error format: " + ex.getErrorFormat()); + } + return commonError; + } } diff --git a/src/main/java/ru/nbch/credit_tracker/service/xml/jaxb/XmlUtilService.java b/src/main/java/ru/nbch/credit_tracker/config/xml/XmlConfig.java similarity index 52% rename from src/main/java/ru/nbch/credit_tracker/service/xml/jaxb/XmlUtilService.java rename to src/main/java/ru/nbch/credit_tracker/config/xml/XmlConfig.java index d8a1081..263b036 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/xml/jaxb/XmlUtilService.java +++ b/src/main/java/ru/nbch/credit_tracker/config/xml/XmlConfig.java @@ -1,8 +1,8 @@ -package ru.nbch.credit_tracker.service.xml.jaxb; +package ru.nbch.credit_tracker.config.xml; import jakarta.xml.bind.JAXBException; -import org.springframework.stereotype.Service; -import org.xml.sax.SAXException; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest; import ru.nbch.credit_tracker.entities.response.errors.MonitoringError; import ru.nbch.credit_tracker.entities.response.monitoring_signal_response.MonitoringSignalResponse; @@ -10,32 +10,22 @@ import ru.nbch.credit_tracker.entities.response.online_download.OnlineDownloadRe import ru.nbch.credit_tracker.entities.response.online_report.SgnlOnlineReport; import ru.nbch.credit_tracker.entities.response.success.MonitoringResponse; 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.XmlProcessorImplAnyClasses; 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 javax.xml.XMLConstants; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import javax.xml.transform.stax.StAXSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import javax.xml.validation.Validator; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; -import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +@Configuration +public class XmlConfig { -@Service -public class XmlUtilService { - - public IXmlProcessor createJaxbProcessor() throws JAXBException { + @Bean + public IXmlProcessor xmlProcessor() throws JAXBException { return new XmlProcessorImplAnyClasses(Charset.forName("windows-1251"), // unmarshalling classes MonitoringRequest.class, @@ -48,24 +38,10 @@ public class XmlUtilService { MonitoringSignalResponse.class); } + @Bean public StaxXmlProcessor staxXmlProcessor() { List> staxReader = new ArrayList<>(); staxReader.add(new SgnlReportStatusStaxReader()); return new XmlProcessorStaxImpl(staxReader); } - - public void validateXMLByXSD(InputStream xmlStream, String xsdPath) throws IOException, XMLStreamException, SAXException { - SchemaFactory sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); - Schema schema = sf.newSchema(new File(xsdPath)); - - XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); - xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); - xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); - xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); - - Validator validator = schema.newValidator(); - XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(xmlStream); - validator.validate(new StAXSource(xmlStreamReader)); - } - } diff --git a/src/main/java/ru/nbch/credit_tracker/entities/dto/HitsData.java b/src/main/java/ru/nbch/credit_tracker/entities/dto/Hit.java similarity index 93% rename from src/main/java/ru/nbch/credit_tracker/entities/dto/HitsData.java rename to src/main/java/ru/nbch/credit_tracker/entities/dto/Hit.java index 4b94cc2..0b46bb8 100644 --- a/src/main/java/ru/nbch/credit_tracker/entities/dto/HitsData.java +++ b/src/main/java/ru/nbch/credit_tracker/entities/dto/Hit.java @@ -7,7 +7,7 @@ import java.time.LocalDateTime; @Getter @Setter -public class HitsData { +public class Hit { private Integer id; private Integer packageId; private String subjectId; diff --git a/src/main/java/ru/nbch/credit_tracker/entities/dto/SubjectData.java b/src/main/java/ru/nbch/credit_tracker/entities/dto/PhoneFidMap.java similarity index 73% rename from src/main/java/ru/nbch/credit_tracker/entities/dto/SubjectData.java rename to src/main/java/ru/nbch/credit_tracker/entities/dto/PhoneFidMap.java index 95e1cd9..ea7629a 100644 --- a/src/main/java/ru/nbch/credit_tracker/entities/dto/SubjectData.java +++ b/src/main/java/ru/nbch/credit_tracker/entities/dto/PhoneFidMap.java @@ -1,9 +1,6 @@ package ru.nbch.credit_tracker.entities.dto; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; import java.time.LocalDateTime; @@ -11,7 +8,8 @@ import java.time.LocalDateTime; @Setter @AllArgsConstructor @NoArgsConstructor -public class SubjectData { +@Builder +public class PhoneFidMap { private Integer id; private Integer packageId; private String subjectId; diff --git a/src/main/java/ru/nbch/credit_tracker/entities/dto/PackageData.java b/src/main/java/ru/nbch/credit_tracker/entities/dto/UserPackage.java similarity index 84% rename from src/main/java/ru/nbch/credit_tracker/entities/dto/PackageData.java rename to src/main/java/ru/nbch/credit_tracker/entities/dto/UserPackage.java index 57e79ce..aef6bfa 100644 --- a/src/main/java/ru/nbch/credit_tracker/entities/dto/PackageData.java +++ b/src/main/java/ru/nbch/credit_tracker/entities/dto/UserPackage.java @@ -1,5 +1,6 @@ package ru.nbch.credit_tracker.entities.dto; +import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -7,7 +8,8 @@ import java.time.LocalDateTime; @Getter @Setter -public class PackageData { +@Builder +public class UserPackage { private Integer id; private String userId; private String packageName; diff --git a/src/main/java/ru/nbch/credit_tracker/enums/EnumKeyMessage.java b/src/main/java/ru/nbch/credit_tracker/enums/EnumKeyMessage.java new file mode 100644 index 0000000..5c9e30f --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/enums/EnumKeyMessage.java @@ -0,0 +1,41 @@ +package ru.nbch.credit_tracker.enums; + +import java.util.Arrays; +import java.util.Collections; + +public class EnumKeyMessage { + private final IEnumKeyCode subject; + /** + * Параметры для подстановки в текст сообщения. Все Serializable. + * args not null. + */ + private Object[] args; + + public EnumKeyMessage(IEnumKeyCode subject) { + this.subject = subject; + this.args = Collections.emptyList().toArray(new Object[0]); + } + + + public EnumKeyMessage(IEnumKeyCode subject, Object... args) { + this.subject = subject; + this.args = args; + } + + public IEnumKeyCode getSubject() { + return subject; + } + + public Object[] getArgs() { + return args; + } + + public void setArgs(Object[] args) { + this.args = args; + } + + @Override + public String toString() { + return "EnumKeyMessage{subject=" + subject + ", args: " + Arrays.toString(args) + "}"; + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/enums/IEnumKeyCode.java b/src/main/java/ru/nbch/credit_tracker/enums/IEnumKeyCode.java new file mode 100644 index 0000000..ea808ce --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/enums/IEnumKeyCode.java @@ -0,0 +1,102 @@ +package ru.nbch.credit_tracker.enums; + +import java.io.Serializable; +import java.util.Objects; + +public interface IEnumKeyCode extends Serializable { + String getKey(); + String getCode(); + + default boolean equalsByKey(String key) { + return key != null && getKey().equalsIgnoreCase(key); + } + + /** + * Проверяет что среди данного набора Enum, присутствует элемент с данным id + * id может быть null + */ + static & IEnumKeyCode> boolean contains(String id, T... enumSet) { + for (T e : enumSet) { + if (Objects.equals(id, e.getKey())) + return true; + } + return false; + } + static & IEnumKeyCode> boolean containsIgnoreCase(String id, T... enumSet) { + for (T e : enumSet) { + if (e.getKey() != null && e.getKey().equalsIgnoreCase(id)) { + return true; + } + } + return false; + } + + static & IEnumKeyCode> boolean contains(T e, T... enumSet) { + for (T enumEl : enumSet) { + if (enumEl.equals(e)) + return true; + } + return false; + } + + /** + * Проверяет что среди всех Enum данного класса, присутствует элемент с данным id + * id может быть null + */ + static & IEnumKeyCode> boolean contains(String key, Class enumClass) { + for (T e : enumClass.getEnumConstants()) { + if (Objects.equals(key, e.getKey())) + return true; + } + return false; + } + + /** + * Возвращает Enum по id, если в заданном классе такой определен + * id может быть null + * + * @return Enum если нашел, иначе null + */ + static & IEnumKeyCode> T getEnumByKey(Class enumClass, String key) { + for (T e : enumClass.getEnumConstants()) { + if (Objects.equals(key, e.getKey())) + return e; + } + return null; + } + + static & IEnumKeyCode> T getEnumByKeyOrUndefined(Class enumClass, String key) { + T enumByKey = getEnumByKey(enumClass, key); + return enumByKey == null ? getUndefined(enumClass) : enumByKey; + } + + static & IEnumKeyCode> T getUndefined(Class enumClass) { + T enumByKey = getEnumByKey(enumClass, UNDEFINED_VALUE); + if (enumByKey == null) { + throw new IllegalArgumentException("Undefined value not found in enum " + enumClass); + } + return enumByKey; + } + + default boolean theSameAs(Object other) { + if (!(other instanceof IEnumKeyCode otherCasted)) { + return false; + } + return this.getKey().equalsIgnoreCase(otherCasted.getKey()); + } + + default String getErrorCode() { + String key = getKey(); + String[] split = key.split("\\."); + if (split.length < 1) return null; + String s = split[split.length - 1]; + if (!s.matches("\\d+")) return null; + return s; + } + + static String getKeyOrNull(IEnumKeyCode enumVal) { + return enumVal == null ? null : enumVal.getKey(); + } + + String UNDEFINED_VALUE = "_Undefined"; +} diff --git a/src/main/java/ru/nbch/credit_tracker/enums/SignalError.java b/src/main/java/ru/nbch/credit_tracker/enums/SignalError.java index 3a645e6..f3c8c1e 100644 --- a/src/main/java/ru/nbch/credit_tracker/enums/SignalError.java +++ b/src/main/java/ru/nbch/credit_tracker/enums/SignalError.java @@ -1,9 +1,6 @@ package ru.nbch.credit_tracker.enums; -import lombok.Getter; - -@Getter -public enum SignalError { +public enum SignalError implements IEnumKeyCode { ERROR_001("001", "Ошибка распаковки архива"), ERROR_002("002", "Отсутствует обязательный элемент: "), ERROR_003("003", "Элемент ClientId не соответствует формату XXXXXXXXX"), @@ -31,4 +28,16 @@ public enum SignalError { this.code = code; this.message = message; } + + @Override + public String getKey() { + return message; + } + + @Override + public String getCode() { + return code; + } + + } diff --git a/src/main/java/ru/nbch/credit_tracker/enums/XmlErrorFormat.java b/src/main/java/ru/nbch/credit_tracker/enums/XmlErrorFormat.java new file mode 100644 index 0000000..45498ea --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/enums/XmlErrorFormat.java @@ -0,0 +1,10 @@ +package ru.nbch.credit_tracker.enums; + +public enum XmlErrorFormat { + MonitoringActivePackagesError, + MonitoringDownloadError, + MonitoringError, + MonitoringPackageDeleteError, + MonitoringReportListError + +} diff --git a/src/main/java/ru/nbch/credit_tracker/exceptions/SignalClientException.java b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalClientException.java new file mode 100644 index 0000000..ebf18f4 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalClientException.java @@ -0,0 +1,13 @@ +package ru.nbch.credit_tracker.exceptions; + +import lombok.Getter; +import ru.nbch.credit_tracker.enums.EnumKeyMessage; +import ru.nbch.credit_tracker.enums.XmlErrorFormat; + +@Getter +public class SignalClientException extends SignalException { + + public SignalClientException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat) { + super(errorMessage, errorFormat); + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/exceptions/SignalErrorException.java b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalErrorException.java deleted file mode 100644 index d3afa23..0000000 --- a/src/main/java/ru/nbch/credit_tracker/exceptions/SignalErrorException.java +++ /dev/null @@ -1,29 +0,0 @@ -package ru.nbch.credit_tracker.exceptions; - -import lombok.Getter; -import ru.nbch.credit_tracker.entities.response.errors.CommonError; -import ru.nbch.credit_tracker.enums.SignalError; - -@Getter -public class SignalErrorException extends RuntimeException { - - private final boolean isUserError; - private final CommonError error; - - public SignalErrorException(SignalError signalError, String tag, CommonError error, boolean isUserError) { - this.isUserError = isUserError; - this.error = createErrorMessage(error, signalError, tag); - } - - private CommonError createErrorMessage(CommonError errorMessage, SignalError error, String tag) { - errorMessage.setStatus("error"); - errorMessage.setErrorCode(error.getCode()); - if (tag != null) { - errorMessage.setErrorText(error.getMessage() + " " + tag); - } else { - errorMessage.setErrorText(error.getMessage()); - } - return errorMessage; - } - -} diff --git a/src/main/java/ru/nbch/credit_tracker/exceptions/SignalException.java b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalException.java new file mode 100644 index 0000000..38c9a1d --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalException.java @@ -0,0 +1,17 @@ +package ru.nbch.credit_tracker.exceptions; + +import lombok.Getter; +import ru.nbch.credit_tracker.enums.EnumKeyMessage; +import ru.nbch.credit_tracker.enums.XmlErrorFormat; + +@Getter +public class SignalException extends RuntimeException { + private final EnumKeyMessage errorMessage; + private final XmlErrorFormat errorFormat; + + public SignalException(EnumKeyMessage errorMessage, + XmlErrorFormat errorFormat) { + this.errorMessage = errorMessage; + this.errorFormat = errorFormat; + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/exceptions/SignalServerException.java b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalServerException.java new file mode 100644 index 0000000..46dd713 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/exceptions/SignalServerException.java @@ -0,0 +1,12 @@ +package ru.nbch.credit_tracker.exceptions; + +import ru.nbch.credit_tracker.enums.EnumKeyMessage; +import ru.nbch.credit_tracker.enums.XmlErrorFormat; + +public class SignalServerException extends SignalException { + + public SignalServerException(EnumKeyMessage errorMessage, XmlErrorFormat errorFormat) { + super(errorMessage, errorFormat); + } + +} diff --git a/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java b/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java index e1bff2d..bc17fdc 100644 --- a/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java +++ b/src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java @@ -8,35 +8,41 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; +import ru.nbch.credit_tracker.entities.dto.UserPackage; import ru.nbch.credit_tracker.entities.request.active_packages.MonitoringActivePackagesRequest; import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest; -import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject; import ru.nbch.credit_tracker.entities.response.active_packages.MonitoringActivePackagesResponse; -import ru.nbch.credit_tracker.entities.response.errors.*; +import ru.nbch.credit_tracker.entities.response.active_packages.Package; +import ru.nbch.credit_tracker.entities.response.active_packages.Packages; import ru.nbch.credit_tracker.entities.response.success.MonitoringPackageDeleteResponse; import ru.nbch.credit_tracker.entities.response.success.MonitoringReportListResponse; import ru.nbch.credit_tracker.entities.response.success.MonitoringResponse; import ru.nbch.credit_tracker.entities.signal_package.Signals; import ru.nbch.credit_tracker.enums.SignalError; import ru.nbch.credit_tracker.enums.Status; -import ru.nbch.credit_tracker.exceptions.SignalErrorException; +import ru.nbch.credit_tracker.enums.XmlErrorFormat; +import ru.nbch.credit_tracker.exceptions.SignalClientException; 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.signal.SignalRestService; import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor; -import ru.nbch.credit_tracker.service.xml.jaxb.XmlUtilService; import ru.nbch.credit_tracker.utils.CTUtil; import ru.nbch.credit_tracker.utils.ValidationUtil; +import ru.nbch.credit_tracker.utils.ZipUtils; import java.io.File; -import java.util.HashSet; +import java.io.IOException; +import java.time.LocalDateTime; import java.util.List; -import java.util.Set; +import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp; +import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp; + @Slf4j @Service public class SignalFacade { @@ -46,7 +52,7 @@ public class SignalFacade { private final AuthorizationService authorizationService; private final SignalService signalService; private final SignalRestService signalRestService; - private final XmlUtilService xmlUtilService; + private final IXmlProcessor xmlProcessor; private final ExecutorService executor; @@ -55,89 +61,62 @@ public class SignalFacade { AuthorizationService authorizationService, SignalService signalService, SignalRestService signalRestService, - XmlUtilService xmlUtilService, + IXmlProcessor xmlProcessor, @Qualifier("executorService") ExecutorService executor) { this.config = config; this.authorizationService = authorizationService; this.signalService = signalService; this.signalRestService = signalRestService; - this.xmlUtilService = xmlUtilService; + this.xmlProcessor = xmlProcessor; this.executor = executor; } public ResponseEntity setupMonitoring(MultipartFile file) { // первичные валидации - if (file.isEmpty()) { - throw new SignalErrorException(SignalError.ERROR_001, null, new MonitoringError(), true); - } - - if (!isZipFile(file)) { - throw new SignalErrorException(SignalError.ERROR_001, null, new MonitoringError(), true); + if (file.isEmpty() || !isZipFile(file)) { + throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError); } // Валидация Архива на количетсво файлов, размер и расширение - try (ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream())) { - int fileCount = 0; - ZipEntry xmlEntry = null; - - ZipEntry entry = zipInputStream.getNextEntry(); - while (entry != null) { - if (!entry.isDirectory()) { - fileCount++; - if (fileCount > 1) { // Архив должен содержать ровно один XML-файл - throw new SignalErrorException(SignalError.ERROR_001, null, new MonitoringError(), true); - } - - if (!entry.getName().toLowerCase().endsWith(".xml")) { // Файл должен быть с расширением xml - throw new SignalErrorException(SignalError.ERROR_001, null, new MonitoringError(), true); - } - - xmlEntry = entry; - } else { - throw new SignalErrorException(SignalError.ERROR_001, null, new MonitoringError(), true); // Архив должен содержать ровно один XML-файл. Никаких доп директорий - } - zipInputStream.closeEntry(); - entry = zipInputStream.getNextEntry(); - } - - if (fileCount == 0) { // Архив должен содержать ровно один XML-файл - throw new SignalErrorException(SignalError.ERROR_001, null, new MonitoringError(), true); - } - - if (xmlEntry.getSize() > MAX_XML_FILE_SIZE) { // максимально 2 Гб до запаковки - throw new SignalErrorException(SignalError.ERROR_009, null, new MonitoringError(), true); - } - - } catch (Exception e) { - if (e instanceof SignalErrorException) { - throw (SignalErrorException) e; - } - log.error(e.getMessage(), e); - throw new SignalErrorException(SignalError.ERROR_100, null, new MonitoringError(), false); - } - - // Теперь знаем, что в архиве лежит ровно один файл с раширением xml и он весит меньше 2гб. Можно валидировать сам xml - // Пробуем распарсить xml MonitoringRequest monitoringRequest; Integer packageId; - try (ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream())) { + ZipInputStream zipInputStream = null; + try { + zipInputStream = new ZipInputStream(file.getInputStream()); + Optional xmlFileEntry = ZipUtils.extractValidEntry(zipInputStream); + if (xmlFileEntry.isEmpty()) { + throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError); + } + if (xmlFileEntry.get().getSize() > MAX_XML_FILE_SIZE) { + throw clientExcp(SignalError.ERROR_009, XmlErrorFormat.MonitoringError); + } + + zipInputStream.close(); + zipInputStream = new ZipInputStream(file.getInputStream()); zipInputStream.getNextEntry(); - IXmlProcessor processor = xmlUtilService.createJaxbProcessor(); - monitoringRequest = processor.read(zipInputStream, MonitoringRequest.class); - + monitoringRequest = xmlProcessor.read(zipInputStream, MonitoringRequest.class); } catch (Exception e) { - if (e instanceof SignalErrorException) { - throw (SignalErrorException) e; + if (e instanceof SignalClientException) { + throw (SignalClientException) e; } log.error(e.getMessage(), e); - throw new SignalErrorException(SignalError.ERROR_100, null, new MonitoringError(), false); + throw serverExcp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError); + } finally { + if (zipInputStream != null) { + try { + zipInputStream.close(); + } catch (IOException e) { + throw serverExcp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError); + } + } } + // валидация xml try { - validateMonitoringRequest(monitoringRequest); - } catch (SignalErrorException e) { + ValidationUtil.validateMonitoringRequest(monitoringRequest); + } catch (SignalClientException e) { signalService.rejectPackage(monitoringRequest); throw e; } @@ -147,22 +126,22 @@ public class SignalFacade { AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(monitoringRequest.getUserId(), monitoringRequest.getPassword()); if (!authResult.isSuccess()) { signalService.rejectPackage(monitoringRequest); - throw new SignalErrorException(authResult.getError(), null, new MonitoringError(), true); + throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringError); } // проверка на уникальность пакета if (signalService.isPackageNotUnique(monitoringRequest)) { signalService.rejectPackage(monitoringRequest); - throw new SignalErrorException(SignalError.ERROR_007, null, new MonitoringError(), true); + throw clientExcp(SignalError.ERROR_007, XmlErrorFormat.MonitoringError); } packageId = signalService.registerPackage(monitoringRequest); } catch (Exception e) { - if (e instanceof SignalErrorException) { - throw (SignalErrorException) e; + if (e instanceof SignalClientException) { + throw (SignalClientException) e; } log.error(e.getMessage(), e); - throw new SignalErrorException(SignalError.ERROR_100, null, new MonitoringError(), false); + throw serverExcp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError); } // в отдельном потоке запускаем поиск фидов и расчет флагов просрочек @@ -171,58 +150,6 @@ public class SignalFacade { return ResponseEntity.ok().body(new MonitoringResponse()); } - private void validateMonitoringRequest(MonitoringRequest request) throws SignalErrorException { - if (request == null) { - throw new SignalErrorException(SignalError.ERROR_011, null, new MonitoringError(), true); - } - - validateReruqredTags(request); - - validateTagsTypes(request); - } - - private void validateReruqredTags(MonitoringRequest request) throws SignalErrorException { - if (request.getUserId() == null) { - throw new SignalErrorException(SignalError.ERROR_002, "UserId", new MonitoringError(), true); - } - - if (request.getPackageName() == null) { - throw new SignalErrorException(SignalError.ERROR_002, "PackageName", new MonitoringError(), true); - } - - if (request.getPassword() == null) { - throw new SignalErrorException(SignalError.ERROR_002, "Password", new MonitoringError(), true); - } - - if (request.getSubjects() == null) { - throw new SignalErrorException(SignalError.ERROR_002, "Subjects", new MonitoringError(), true); - } - - if (request.getSubjects().getSubject().isEmpty()) { - throw new SignalErrorException(SignalError.ERROR_002, "Subject", new MonitoringError(), true); - } - } - - private void validateTagsTypes(MonitoringRequest request) throws SignalErrorException { - if (!ValidationUtil.validatePackageName(request.getPackageName())) { - throw new SignalErrorException(SignalError.ERROR_008, null, new MonitoringError(), true); - } - - Set uniqueIds = new HashSet<>(); - for (Subject subject : request.getSubjects().getSubject()) { - if (!ValidationUtil.validatePhone(subject.getClientId())) { - throw new SignalErrorException(SignalError.ERROR_003, null, new MonitoringError(), true); - } - if (!ValidationUtil.validateNPId(subject.getId())) { - throw new SignalErrorException(SignalError.ERROR_010, null, new MonitoringError(), true); - } - // проверка на уникальность Id внутри одного пакета - if (!uniqueIds.add(subject.getId())) { - throw new SignalErrorException(SignalError.ERROR_004, subject.getId(), new MonitoringError(), true); - } - } - } - private void registerFidsAndDebts(Integer packageId, String packageName) { executor.execute(() -> { try { @@ -232,14 +159,14 @@ public class SignalFacade { // TODO validate xsd? if (signalRestService.update(signals)) { log.info("Package was successfully registered in signal service. PackageId: {} PackageName: {}", packageId, packageName); - signalService.setPackageStatus(packageId, Status.ON_MONITORING); + signalService.updatePackageStatus(packageId, Status.ON_MONITORING); } else { log.info("Package registration was rejected by signal service. PackageId: {} PackageName: {}", packageId, packageName); - signalService.setPackageStatus(packageId, Status.ERROR); + signalService.updatePackageStatus(packageId, Status.ERROR); } } } catch (Exception e) { - signalService.setPackageStatus(packageId, Status.ERROR); + signalService.updatePackageStatus(packageId, Status.ERROR); log.error("Ошибка при поиске фидов или расчете флагов просрочек. Package_id {}", packageId, e); } }); @@ -247,54 +174,73 @@ public class SignalFacade { private boolean isZipFile(MultipartFile file) { return file.getContentType() != null && - (file.getContentType().equals("application/zip") || file.getContentType().equals("application/x-zip-compressed")) || - file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".zip"); + (file.getContentType().equals("application/zip") || file.getContentType().equals("application/x-zip-compressed")) || + file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".zip"); } public ResponseEntity findActivePackages(MonitoringActivePackagesRequest activePackagesRequest) { try { AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(activePackagesRequest.getUserId(), activePackagesRequest.getPassword()); if (!authResult.isSuccess()) { - throw new SignalErrorException(authResult.getError(), null, new MonitoringActivePackagesError(), true); + throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringActivePackagesError); } - MonitoringActivePackagesResponse response = signalService.findActivePackages(activePackagesRequest.getUserId()); - if (response != null) { + List activePackages = signalService.findActivePackages(activePackagesRequest.getUserId()); + + if (!activePackages.isEmpty()) { + MonitoringActivePackagesResponse response = new MonitoringActivePackagesResponse(); + response.setStatus("OK"); + response.setMembercode(activePackagesRequest.getUserId().substring(0, 6)); + Packages packages = new Packages(); + activePackages.forEach(data -> { + Package pack = new Package(); + pack.setPackageName(data.getPackageName()); + pack.setCreatedAt(data.getCreatedAt() != null ? data.getCreatedAt().toString() : null); + packages.getPackages().add(pack); + }); + response.setPackages(packages); return ResponseEntity.ok(response); } else { - throw new SignalErrorException(SignalError.ERROR_015, null, new MonitoringActivePackagesError(), true); + throw clientExcp(SignalError.ERROR_015, XmlErrorFormat.MonitoringActivePackagesError); } } catch (Exception e) { - if (e instanceof SignalErrorException) { - throw (SignalErrorException) e; + if (e instanceof SignalClientException) { + throw (SignalClientException) e; } log.error(e.getMessage(), e); - throw new SignalErrorException(SignalError.ERROR_013, null, new MonitoringActivePackagesError(), false); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringActivePackagesError); } } public ResponseEntity deletePackage(String username, String packageName) { try { if (!signalService.isPackageExists(username, packageName)) { - throw new SignalErrorException(SignalError.ERROR_016, packageName, new MonitoringPackageDeleteError(), true); + throw clientExcp(SignalError.ERROR_016, XmlErrorFormat.MonitoringPackageDeleteError, packageName); } - MonitoringPackageDeleteResponse response = signalService.deletePackage(username, packageName); + + LocalDateTime deactivatedAt = LocalDateTime.now(); + signalService.deletePackage(username, packageName, deactivatedAt); + + MonitoringPackageDeleteResponse response = new MonitoringPackageDeleteResponse(); + response.setStatus("Deleted"); + response.setPackageName(packageName); + response.setDeactivatedAt(deactivatedAt.toString()); signalRestService.deletePackage(username, packageName); log.info("Package {} deleted", packageName); return ResponseEntity.ok(response); } catch (Exception e) { - if (e instanceof SignalErrorException) { - throw (SignalErrorException) e; + if (e instanceof SignalClientException) { + throw (SignalClientException) e; } log.error(e.getMessage(), e); - throw new SignalErrorException(SignalError.ERROR_017, null, new MonitoringPackageDeleteError(), false); + throw serverExcp(SignalError.ERROR_017, XmlErrorFormat.MonitoringPackageDeleteError); } } public ResponseEntity getReportList(String username, String packageName) { try { if (!signalService.isPackageExists(username, packageName)) { - throw new SignalErrorException(SignalError.ERROR_016, packageName, new MonitoringReportListError(), true); + throw clientExcp(SignalError.ERROR_016, XmlErrorFormat.MonitoringReportListError, packageName); } String memberCode = username.substring(0, 6); @@ -306,7 +252,7 @@ public class SignalFacade { MonitoringReportListResponse.Reports reports = new MonitoringReportListResponse.Reports(); File[] files = folder.listFiles(); if (files == null) { - throw new SignalErrorException(SignalError.ERROR_012, packageName, new MonitoringReportListError(), true); + throw clientExcp(SignalError.ERROR_012, XmlErrorFormat.MonitoringReportListError, packageName); } for (File file : files) { if (file.isFile() && file.getName().startsWith(filePrefix)) { @@ -315,7 +261,7 @@ public class SignalFacade { } if (reports.getReports().isEmpty()) { - throw new SignalErrorException(SignalError.ERROR_012, packageName, new MonitoringReportListError(), true); + throw clientExcp(SignalError.ERROR_012, XmlErrorFormat.MonitoringReportListError, packageName); } else { MonitoringReportListResponse response = new MonitoringReportListResponse(); response.setPackageName(packageName); @@ -324,14 +270,14 @@ public class SignalFacade { } } else { log.error("Пакет {} был найден в бд для memberCode {}, но ни одного архива не было найдено в папке {}", packageName, username, dirPath); - throw new SignalErrorException(SignalError.ERROR_013, packageName, new MonitoringReportListError(), true); + throw clientExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError, packageName); } } catch (Exception e) { - if (e instanceof SignalErrorException) { - throw (SignalErrorException) e; + if (e instanceof SignalClientException) { + throw (SignalClientException) e; } log.error(e.getMessage(), e); - throw new SignalErrorException(SignalError.ERROR_013, null, new MonitoringReportListError(), false); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError); } } @@ -347,15 +293,15 @@ public class SignalFacade { return ResponseEntity.ok().body(new FileUrlResource(file.getPath())); } } else { - throw new SignalErrorException(SignalError.ERROR_014, null, new MonitoringDownloadError(), true); + throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError); } - throw new SignalErrorException(SignalError.ERROR_014, null, new MonitoringDownloadError(), true); + throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError); } catch (Exception e) { - if (e instanceof SignalErrorException) { - throw (SignalErrorException) e; + if (e instanceof SignalClientException) { + throw (SignalClientException) e; } log.error(e.getMessage(), e); - throw new SignalErrorException(SignalError.ERROR_013, null, new MonitoringDownloadError(), false); + throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringDownloadError); } } } diff --git a/src/main/java/ru/nbch/credit_tracker/mapper/signal/HitsMapper.java b/src/main/java/ru/nbch/credit_tracker/mapper/signal/HitsMapper.java new file mode 100644 index 0000000..7333e25 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/mapper/signal/HitsMapper.java @@ -0,0 +1,14 @@ +package ru.nbch.credit_tracker.mapper.signal; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import ru.nbch.credit_tracker.entities.dto.Hit; + +import java.util.List; + +@Mapper +public interface HitsMapper { + + void insertHits(@Param("hits") List hits); + +} diff --git a/src/main/java/ru/nbch/credit_tracker/mapper/signal/PhoneFidMapMapper.java b/src/main/java/ru/nbch/credit_tracker/mapper/signal/PhoneFidMapMapper.java new file mode 100644 index 0000000..5e6051a --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/mapper/signal/PhoneFidMapMapper.java @@ -0,0 +1,21 @@ +package ru.nbch.credit_tracker.mapper.signal; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import ru.nbch.credit_tracker.entities.dto.PhoneFidMap; +import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject; + +import java.util.List; + +@Mapper +public interface PhoneFidMapMapper { + + void registerSubjects(@Param("subjects") List subjects, @Param("packageId") Integer packageId); + + List findPhoneFidMaps(@Param("packageId") Integer packageId); + + List findFullPhoneFidMap(@Param("packageId") Integer packageId); + + void updatePhoneFidMaps(@Param("subjects") List subjects); + +} diff --git a/src/main/java/ru/nbch/credit_tracker/mapper/signal/SignalMapper.java b/src/main/java/ru/nbch/credit_tracker/mapper/signal/SignalMapper.java deleted file mode 100644 index a61ccf8..0000000 --- a/src/main/java/ru/nbch/credit_tracker/mapper/signal/SignalMapper.java +++ /dev/null @@ -1,48 +0,0 @@ -package ru.nbch.credit_tracker.mapper.signal; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import ru.nbch.credit_tracker.entities.dto.HitsData; -import ru.nbch.credit_tracker.entities.dto.PackageData; -import ru.nbch.credit_tracker.entities.dto.SubjectData; -import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest; -import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject; - -import java.time.LocalDateTime; -import java.util.List; - -@Mapper -public interface SignalMapper { - - boolean isPackageNotUnique(@Param("userId") String userId, @Param("packageName") String packageName); - - boolean isPackageExists(@Param("userId") String userId, @Param("packageName") String packageName, @Param("status") String status); - - void deletePackage(@Param("userId") String userId, @Param("packageName") String packageName, @Param("status") String newStatus, @Param("previousStatus") String previousStatus, @Param("deactivatedAt") LocalDateTime deactivatedAt); - - Integer registerPackage(@Param("request") MonitoringRequest request, @Param("creadedAt") LocalDateTime creadedAt, @Param("status") String status); - - void registerSubjects(@Param("subjects") List subjects, @Param("packageId") Integer packageId); - - void insertPackage(@Param("request") MonitoringRequest request, @Param("creadedAt") LocalDateTime creadedAt, @Param("status") String status); - - void registerSubjectsFidAndDebts(@Param("id") Integer id, @Param("fid") Integer fid, @Param("flagDebt5000") Integer flagDebt5000, @Param("flag90") Integer flag90, @Param("calculatedAt") LocalDateTime calculatedAt); - - void setPackageStatus(@Param("packageId") Integer packageId, @Param("status") String status); - - List findSubjectsData(@Param("packageId") Integer packageId); - - List findFullSubjectsData(@Param("packageId") Integer packageId); - - PackageData findPackageData(@Param("id") Integer id); - - List findPackageDataList(@Param("userId") String userId, @Param("status") String status); - - List findPackagesByStatus(@Param("status") String status); - - void setHits(@Param("hits") List hits); - - void updateSubjects(@Param("subjects") List subjects); - - void setPackageLastDownloadedReport(@Param("id") Integer id, @Param("fileName") String fileName); -} diff --git a/src/main/java/ru/nbch/credit_tracker/mapper/signal/UserPackageMapper.java b/src/main/java/ru/nbch/credit_tracker/mapper/signal/UserPackageMapper.java new file mode 100644 index 0000000..cb8ce97 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/mapper/signal/UserPackageMapper.java @@ -0,0 +1,31 @@ +package ru.nbch.credit_tracker.mapper.signal; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import ru.nbch.credit_tracker.entities.dto.UserPackage; + +import java.time.LocalDateTime; +import java.util.List; + +@Mapper +public interface UserPackageMapper { + + boolean isPackageNotUnique(@Param("userId") String userId, @Param("packageName") String packageName); + + boolean isPackageExists(@Param("userId") String userId, @Param("packageName") String packageName, @Param("status") String status); + + void deletePackage(@Param("userId") String userId, @Param("packageName") String packageName, @Param("status") String newStatus, @Param("previousStatus") String previousStatus, @Param("deactivatedAt") LocalDateTime deactivatedAt); + + Integer insertPackage(@Param("userPackage") UserPackage userPackage); + + void updatePackageStatus(@Param("packageId") Integer packageId, @Param("status") String status); + + void updatePackageLastDownloadedReport(@Param("id") Integer id, @Param("fileName") String fileName); + + UserPackage findPackage(@Param("id") Integer id); + + List findUserPackages(@Param("userId") String userId, @Param("status") String status); + + List findAllPackagesByStatus(@Param("status") String status); + +} diff --git a/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java b/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java index d360548..cb1b905 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java @@ -3,9 +3,9 @@ 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.HitsData; -import ru.nbch.credit_tracker.entities.dto.PackageData; -import ru.nbch.credit_tracker.entities.dto.SubjectData; +import ru.nbch.credit_tracker.entities.dto.Hit; +import ru.nbch.credit_tracker.entities.dto.PhoneFidMap; +import ru.nbch.credit_tracker.entities.dto.UserPackage; import ru.nbch.credit_tracker.entities.response.monitoring_signal_response.*; import ru.nbch.credit_tracker.entities.response.online_download.Inquiry; import ru.nbch.credit_tracker.entities.response.online_download.OnlineDownloadReport; @@ -14,7 +14,6 @@ import ru.nbch.credit_tracker.entities.response.online_report.Report; import ru.nbch.credit_tracker.entities.response.online_report.SgnlOnlineReport; import ru.nbch.credit_tracker.service.signal.SignalRestService; import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor; -import ru.nbch.credit_tracker.service.xml.jaxb.XmlUtilService; import ru.nbch.credit_tracker.utils.CTUtil; import java.io.ByteArrayInputStream; @@ -36,16 +35,16 @@ public class MonitoringService { private final SignalRestService signalRestService; private final SignalService signalService; - private final XmlUtilService xmlUtilService; + private final IXmlProcessor xmlProcessor; private final CreditTrackerSettings config; public MonitoringService(SignalRestService signalRestService, SignalService signalService, - XmlUtilService xmlUtilService, + IXmlProcessor xmlProcessor, CreditTrackerSettings config) { this.signalRestService = signalRestService; this.signalService = signalService; - this.xmlUtilService = xmlUtilService; + this.xmlProcessor = xmlProcessor; this.config = config; } @@ -57,13 +56,13 @@ public class MonitoringService { private void monitor() { log.info("Start monitoring"); - List packages = signalService.findPackagesOnMonitoring(); - for (PackageData packageData : packages) { - log.info("Processing package {}", packageData.getPackageName()); - SgnlOnlineReport onlineReports = signalRestService.getReports(packageData.getUserId().substring(0, 6) + "_" + packageData.getPackageName()); + List packages = signalService.findPackagesOnMonitoring(); + for (UserPackage userPackage : packages) { + log.info("Processing package {}", userPackage.getPackageName()); + SgnlOnlineReport onlineReports = signalRestService.getReports(userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName()); if (onlineReports == null) { - log.info("No reports found for package {}", packageData.getPackageName()); + log.info("No reports found for package {}", userPackage.getPackageName()); continue; } @@ -71,7 +70,7 @@ public class MonitoringService { .filter(fileName -> CTUtil.parseDateFromReportFileName(fileName) != null).toList(); // TODO оптимизировать if (fileNames.isEmpty()) { - log.info("No new report found for package {}", packageData.getPackageName()); + log.info("No new report found for package {}", userPackage.getPackageName()); continue; } @@ -79,16 +78,16 @@ public class MonitoringService { .orElseGet(Collections::emptyList) .stream().max(Comparator.comparing(CTUtil::parseDateFromReportFileName)); // отфильтровали только те имена, которые парсятся в дату, так что null тут не придет - LocalDateTime lastDownloadedReportDate = CTUtil.parseDateFromReportFileName(packageData.getLastDownloadedReport()); + LocalDateTime lastDownloadedReportDate = CTUtil.parseDateFromReportFileName(userPackage.getLastDownloadedReport()); - if (packageData.getLastDownloadedReport() != null) { - log.info("Last downloaded report found for package {}. Last Downloaded Report Name: {}", packageData.getPackageName(), packageData.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 (packageData.getLastDownloadedReport() == null && newReport.isPresent()) { + if (userPackage.getLastDownloadedReport() == null && newReport.isPresent()) { report = loadReport(newReport.get()); // по этому пакету еще не было загруженных отчетов, продолжаем работу с полученным } else if (lastDownloadedReportDate != null && newReport.isPresent()) { LocalDateTime newReportDate = CTUtil.parseDateFromReportFileName(newReport.get()); @@ -97,28 +96,28 @@ public class MonitoringService { } } if (report == null) { - log.info("Report was not loaded for package {}", packageData.getPackageName()); + log.info("Report was not loaded for package {}", userPackage.getPackageName()); continue; } - MonitoringSignalResponse response = generateResponse(packageData, report.getPersons().getPersons()); - String fileName = createResponseFile(packageData, response); + MonitoringSignalResponse response = generateResponse(userPackage, report.getPersons().getPersons()); + String fileName = createResponseFile(userPackage, response); if (fileName != null) { log.info("New report fileName: {}", fileName); - updateSignalHits(packageData, response, fileName); - signalService.updateLastDownloadedReport(packageData.getId(), newReport.get()); + updateSignalHits(userPackage, response, fileName); + signalService.updateLastDownloadedReport(userPackage.getId(), newReport.get()); } else { - log.info("Report was not created for package {}", packageData.getPackageName()); + log.info("Report was not created for package {}", userPackage.getPackageName()); } } log.info("Finish monitoring"); } - private MonitoringSignalResponse generateResponse(PackageData packageData, List persons) { + private MonitoringSignalResponse generateResponse(UserPackage userPackage, List persons) { MonitoringSignalResponse response = new MonitoringSignalResponse(); - response.setPackageName(packageData.getPackageName()); // Имя пакета, переданного при установке + response.setPackageName(userPackage.getPackageName()); // Имя пакета, переданного при установке Subjects subjects = new Subjects(); - List subjectDataList = signalService.findFullSubjectsData(packageData.getId()); + List phoneFidMapList = signalService.findFullSubjectsData(userPackage.getId()); for (Person person : persons) { Signals signals = new Signals(); for (Inquiry inquiry : person.getInquiries()) { @@ -135,7 +134,7 @@ public class MonitoringService { // Если есть хотя бы один заполненный сигнал, значит заполняем остальные данные if (!signals.getSignals().isEmpty()) { - subjectDataList.stream().filter(p -> p.getSubjectId().equals(person.getUid())).findFirst().ifPresent(subjectData -> { + phoneFidMapList.stream().filter(p -> p.getSubjectId().equals(person.getUid())).findFirst().ifPresent(subjectData -> { Subject subject = new Subject(); subject.setId(subjectData.getSubjectId()); // Уникальный идентификатор субъекта (равен Id из XML-пакета при установке мониторинга) subject.setClientId(subjectData.getPhone()); @@ -150,18 +149,17 @@ public class MonitoringService { return response; } - private String createResponseFile(PackageData packageData, MonitoringSignalResponse response) { + private String createResponseFile(UserPackage userPackage, MonitoringSignalResponse response) { try { - String fileName = CTUtil.generateResponseReportFileName(packageData.getUserId(), packageData.getPackageName()); - String filePath = config.getLoadDir() + File.separator + packageData.getUserId().substring(0, 6) + File.separator; + String fileName = CTUtil.generateResponseReportFileName(userPackage.getUserId(), userPackage.getPackageName()); + String filePath = config.getLoadDir() + File.separator + userPackage.getUserId().substring(0, 6) + File.separator; File folder = new File(filePath); if (!folder.exists()) { folder.mkdir(); } - IXmlProcessor processor = xmlUtilService.createJaxbProcessor(); - String xmlStr = processor.asString(response, true); + String xmlStr = xmlProcessor.asString(response, true); byte[] xmlBytes = xmlStr.getBytes(Charset.forName("windows-1251")); try (FileOutputStream fos = new FileOutputStream(filePath + fileName + ".zip"); @@ -179,23 +177,23 @@ public class MonitoringService { return null; } - private void updateSignalHits(PackageData packageData, MonitoringSignalResponse response, String reportFileName) { - log.info("Updating signal hits for {}", packageData.getPackageName()); + private void updateSignalHits(UserPackage userPackage, MonitoringSignalResponse response, String reportFileName) { + log.info("Updating signal hits for {}", userPackage.getPackageName()); LocalDateTime responseSentAt = LocalDateTime.now(); - List hits = new ArrayList<>(); + List hits = new ArrayList<>(); response.getSubjects().getSubjects().forEach(subject -> { subject.getSignals().getSignals().forEach(signal -> { - HitsData hitsData = new HitsData(); - hitsData.setPackageId(packageData.getId()); - hitsData.setSubjectId(subject.getId()); - hitsData.setSignalType(1); - hitsData.setResponseSentAt(responseSentAt); - hitsData.setReportFileName(reportFileName); - hits.add(hitsData); + Hit hit = new Hit(); + hit.setPackageId(userPackage.getId()); + hit.setSubjectId(subject.getId()); + hit.setSignalType(1); + hit.setResponseSentAt(responseSentAt); + hit.setReportFileName(reportFileName); + hits.add(hit); }); }); - signalService.setHits(hits); - log.info("Signal hits updated for package {}", packageData.getPackageName()); + signalService.insertHits(hits); + log.info("Signal hits updated for package {}", userPackage.getPackageName()); } private OnlineDownloadReport loadReport(String reportName) { @@ -206,8 +204,7 @@ public class MonitoringService { OnlineDownloadReport report; try (GZIPInputStream zipInputStream = new GZIPInputStream(new ByteArrayInputStream(archive))) { - IXmlProcessor processor = xmlUtilService.createJaxbProcessor(); - report = processor.read(zipInputStream, OnlineDownloadReport.class); + report = xmlProcessor.read(zipInputStream, OnlineDownloadReport.class); } catch (Exception e) { log.error(e.getMessage(), e); diff --git a/src/main/java/ru/nbch/credit_tracker/service/SignalService.java b/src/main/java/ru/nbch/credit_tracker/service/SignalService.java index a8768ca..a4866f6 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/SignalService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/SignalService.java @@ -1,31 +1,25 @@ package ru.nbch.credit_tracker.service; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import ru.nbch.credit_tracker.builder.PersonFactoryBuilder; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; -import ru.nbch.credit_tracker.entities.dto.HitsData; -import ru.nbch.credit_tracker.entities.dto.PackageData; -import ru.nbch.credit_tracker.entities.dto.SubjectData; +import ru.nbch.credit_tracker.entities.dto.Hit; +import ru.nbch.credit_tracker.entities.dto.PhoneFidMap; +import ru.nbch.credit_tracker.entities.dto.UserPackage; import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest; import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject; -import ru.nbch.credit_tracker.entities.response.active_packages.MonitoringActivePackagesResponse; -import ru.nbch.credit_tracker.entities.response.active_packages.Package; -import ru.nbch.credit_tracker.entities.response.active_packages.Packages; -import ru.nbch.credit_tracker.entities.response.success.MonitoringPackageDeleteResponse; import ru.nbch.credit_tracker.entities.signal_package.Auth; import ru.nbch.credit_tracker.entities.signal_package.Person; import ru.nbch.credit_tracker.entities.signal_package.Signals; import ru.nbch.credit_tracker.enums.Status; -import ru.nbch.credit_tracker.mapper.signal.SignalMapper; import ru.nbch.credit_tracker.service.indic.FlagsService; import ru.nbch.credit_tracker.service.indic.PersonService; import ru.nbch.credit_tracker.service.indic.PhoneService; -import ru.nbch.credit_tracker.utils.CTUtil; +import ru.nbch.credit_tracker.service.signal.HitsService; +import ru.nbch.credit_tracker.service.signal.PhoneFidMapService; +import ru.nbch.credit_tracker.service.signal.UserPackageService; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -36,10 +30,10 @@ import java.util.Objects; @Service public class SignalService { - private final static DateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy"); - private final CreditTrackerSettings config; - private final SignalMapper mapper; + private final HitsService hitsService; + private final UserPackageService userPackageService; + private final PhoneFidMapService phoneFidMapService; private final PhoneService phoneService; private final FlagsService flagsService; private final PersonService personService; @@ -47,53 +41,77 @@ public class SignalService { private final int batchSize = 10000; public SignalService(CreditTrackerSettings config, - SignalMapper mapper, + HitsService hitsService, + UserPackageService userPackageService, + PhoneFidMapService phoneFidMapService, PhoneService phoneService, FlagsService flagsService, PersonService personService) { this.config = config; - this.mapper = mapper; + this.hitsService = hitsService; + this.userPackageService = userPackageService; + this.phoneFidMapService = phoneFidMapService; this.phoneService = phoneService; this.flagsService = flagsService; this.personService = personService; } public boolean isPackageNotUnique(MonitoringRequest request) { - String userId = request.getUserId(); - return mapper.isPackageNotUnique(userId.substring(0, 6), request.getPackageName()); + return userPackageService.isPackageNotUnique(request.getUserId(), request.getPackageName()); } public Integer registerPackage(MonitoringRequest request) { - Integer packageId = mapper.registerPackage(request, LocalDateTime.now(), Status.PROCESSING.name()); + UserPackage userPackage = UserPackage.builder() + .userId(request.getUserId()) + .packageName(request.getPackageName()) + .createdAt(LocalDateTime.now()) + .status(Status.PROCESSING.name()) + .build(); + Integer packageId = userPackageService.insertPackage(userPackage); List subjects = request.getSubjects().getSubject(); for (int i = 0; i < subjects.size(); i += batchSize) { int end = Math.min(i + batchSize, subjects.size()); - mapper.registerSubjects(subjects.subList(i, end), packageId); + phoneFidMapService.registerSubjects(subjects.subList(i, end), packageId); // TODO преобразовывать список в List ? } return packageId; } public List registerSubjectsFidAndDebts(Integer packageId) { - List subjects = mapper.findSubjectsData(packageId); + List subjects = phoneFidMapService.findPhoneFidMaps(packageId); return updateFlags(subjects, packageId); } - public List updateFlags(List subjects, Integer packageId) { - List fidsPhoneDataList = phoneService.findFidsPhoneData(subjects, true); + public List updateFlags(List subjects, Integer packageId) { + List fidsPhoneDataList = phoneService.findFidsPhoneData(subjects); LocalDateTime calculatedAt = LocalDateTime.now(); for (int i = 0; i < fidsPhoneDataList.size(); i += batchSize) { int end = Math.min(i + batchSize, fidsPhoneDataList.size()); List currentList = fidsPhoneDataList.subList(i, end); Map flagsDataMap = flagsService.findFlags(currentList.stream().map(PhoneService.FidsPhoneData::getFid).filter(Objects::nonNull).toList()); - List subjectToUpdate = new ArrayList<>(); + List subjectToUpdate = new ArrayList<>(); currentList.forEach(data -> { - SubjectData subject; + PhoneFidMap subject; if (data.getFid() != null) { FlagsService.FlagsData flagsData = flagsDataMap.get(data.getFid()); - subject = new SubjectData(data.getId(), packageId, data.getSubjectId(), data.getPhone(), data.getFid(), flagsData.getFlagDebt5000(), flagsData.getFlag90days(), calculatedAt); + subject = PhoneFidMap.builder() + .id(data.getId()) + .packageId(packageId) + .subjectId(data.getSubjectId()) + .phone(data.getPhone()) + .fid(data.getFid()) + .flagDebt5000(flagsData.getFlagDebt5000()) + .flag90days(flagsData.getFlag90days()) + .calculatedAt(calculatedAt) + .build(); } else { - subject = new SubjectData(data.getId(), packageId, data.getSubjectId(), data.getPhone(), null, null, null, calculatedAt); + subject = PhoneFidMap.builder() + .id(data.getId()) + .packageId(packageId) + .subjectId(data.getSubjectId()) + .phone(data.getPhone()) + .calculatedAt(calculatedAt) + .build(); } subjectToUpdate.add(subject); }); @@ -101,7 +119,7 @@ public class SignalService { int updateBatchSize = batchSize / 8; // 8 параметров на одну запись для обновления. Максимальное количество параметров ~65000 for (int j = 0; j < subjectToUpdate.size(); j += updateBatchSize) { int endIndex = Math.min(j + updateBatchSize, subjectToUpdate.size()); - mapper.updateSubjects(subjectToUpdate.subList(j, endIndex)); + phoneFidMapService.updatePhoneFidMaps(subjectToUpdate.subList(j, endIndex)); } } @@ -109,18 +127,24 @@ public class SignalService { } public void rejectPackage(MonitoringRequest request) { - mapper.insertPackage(request, LocalDateTime.now(), Status.REJECTED.name()); + UserPackage userPackage = UserPackage.builder() + .userId(request.getUserId()) + .packageName(request.getPackageName()) + .createdAt(LocalDateTime.now()) + .status(Status.REJECTED.name()) + .build(); + userPackageService.insertPackage(userPackage); } - public void setPackageStatus(Integer packageId, Status status) { - mapper.setPackageStatus(packageId, status.name()); + public void updatePackageStatus(Integer packageId, Status status) { + userPackageService.updatePackageStatus(packageId, status); } public Signals buildSignals(Integer packageId, List fids) { - PackageData packageData = mapper.findPackageData(packageId); + UserPackage userPackage = userPackageService.findPackage(packageId); Signals signals = new Signals(); signals.setOnline("2"); // Всегда=2 (только онлайн-сигналы) - signals.setId(packageData.getUserId().substring(0, 6) + "_" + packageData.getPackageName()); // _ + signals.setId(userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName()); // _ Auth auth = new Auth(); auth.setUser(config.getSignalsuser()); signals.setAuth(auth); @@ -143,7 +167,10 @@ public class SignalService { fidsPhoneData.forEach(data -> { if (data.getFid() != null) { PersonService.PersonData personData = personFidMap.get(data.getFid()); - Person person = getPerson(personData, data.getSubjectId()); + Person person = PersonFactoryBuilder.builder() + .personData(personData) + .uid(data.getSubjectId()) + .build(); if (person != null) { persons.add(person); } @@ -152,101 +179,31 @@ public class SignalService { return persons; } - private Person getPerson(PersonService.PersonData personData, String id) { - if (personData == null) { - return null; - } - PersonService.NameData nameData = personData.getName(); - PersonService.PassportData passportData = personData.getPassport(); - Person person = new Person(); - person.setS(nameData.getLastName()); - person.setN(nameData.getFirstName()); - person.setM(StringUtils.isNotBlank(nameData.getMiddleName()) ? nameData.getMiddleName() : null); - person.setD(DATE_FORMAT.format(CTUtil.localDatetoDate(nameData.getBirthDate()))); - - person.setPn(getPn(passportData.getSerNum(), passportData.getIdNum())); - person.setPd(passportData.getIssDate() != null ? DATE_FORMAT.format(CTUtil.localDatetoDate(passportData.getIssDate())) : "01.01.2000"); - person.setDt(StringUtils.isNotBlank(passportData.getIdType2()) ? passportData.getIdType2() : passportData.getIdType()); - person.setIp("0"); - person.setUid(id); - person.setOksm("999"); - person.setConsentDate(DATE_FORMAT.format(CTUtil.localDatetoDate(LocalDate.now()))); - person.setConsentPurpose("16"); - person.setReportUser("АО «НБКИ»"); - person.setLiability("1"); - person.setConsentPeriod("3"); - person.setAgrDate(DATE_FORMAT.format(CTUtil.localDatetoDate(LocalDate.now()))); - person.setReportUserRegNum("1057746710713"); - person.setReportUserTaxID("7703548386"); - person.setConsentHash("hash"); - - person.setCs(person.getS()); - person.setConsentN(person.getN()); - person.setConsentM(person.getM()); - person.setConsentBd(person.getD()); - person.setConsentPn(person.getPn()); - person.setConsentPd(person.getPd()); - person.setConsentDivCode("000-000"); - person.setConsentDt(person.getDt()); - person.setInqPurpose("16"); - return person; - } - - private String getPn(String serNum, String idNum) { - String normSerNum = CTUtil.normalize(serNum); - String normIdNum = CTUtil.normalize(idNum); - return StringUtils.isNotBlank(normSerNum) ? normSerNum + normIdNum : normIdNum; - } - - - public MonitoringActivePackagesResponse findActivePackages(String userId) { - String memberCode = userId.substring(0, 6); - MonitoringActivePackagesResponse activePackages = new MonitoringActivePackagesResponse(); - activePackages.setStatus("OK"); - activePackages.setMembercode(memberCode); - Packages packages = new Packages(); - mapper.findPackageDataList(memberCode, Status.ON_MONITORING.name()).forEach(data -> { - Package pack = new Package(); - pack.setPackageName(data.getPackageName()); - pack.setCreatedAt(data.getCreatedAt() != null ? data.getCreatedAt().toString() : null); - packages.getPackages().add(pack); - }); - activePackages.setPackages(packages); - - if (packages.getPackages() == null || packages.getPackages().isEmpty()) { - return null; - } - return activePackages; + public List findActivePackages(String userId) { + return userPackageService.findUserPackages(userId, Status.ON_MONITORING); } public boolean isPackageExists(String username, String packageName) { - return mapper.isPackageExists(username.substring(0, 6), packageName, Status.ON_MONITORING.name()); + return userPackageService.isPackageExists(username, packageName, Status.ON_MONITORING); } - public MonitoringPackageDeleteResponse deletePackage(String username, String packageName) { - LocalDateTime deactivatedAt = LocalDateTime.now(); - mapper.deletePackage(username.substring(0, 6), packageName, Status.DELETED.name(), Status.ON_MONITORING.name(), deactivatedAt); - - MonitoringPackageDeleteResponse deleteResponse = new MonitoringPackageDeleteResponse(); - deleteResponse.setStatus("Deleted"); - deleteResponse.setPackageName(packageName); - deleteResponse.setDeactivatedAt(deactivatedAt.toString()); - return deleteResponse; + public void deletePackage(String username, String packageName, LocalDateTime deactivatedAt) { + userPackageService.deletePackage(username, packageName, Status.DELETED, Status.ON_MONITORING, deactivatedAt); } - public List findPackagesOnMonitoring() { - return mapper.findPackagesByStatus(Status.ON_MONITORING.name()); + public List findPackagesOnMonitoring() { + return userPackageService.findAllPackagesByStatus(Status.ON_MONITORING); } - public List findFullSubjectsData(Integer packageId) { - return mapper.findFullSubjectsData(packageId); + public List findFullSubjectsData(Integer packageId) { + return phoneFidMapService.findFullPhoneFidMap(packageId); } - public void setHits(List hits) { - mapper.setHits(hits); + public void insertHits(List hits) { + hitsService.insertHits(hits); } public void updateLastDownloadedReport(Integer id, String fileName) { - mapper.setPackageLastDownloadedReport(id, fileName); + userPackageService.updatePackageLastDownloadedReport(id, fileName); } } diff --git a/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java b/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java index 05cd5b5..ad2b150 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java @@ -3,8 +3,8 @@ 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.PackageData; -import ru.nbch.credit_tracker.entities.dto.SubjectData; +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; @@ -42,32 +42,32 @@ public class UpdatingFlagsService { private void update() { log.info("Start updating flags"); - List packages = signalService.findPackagesOnMonitoring(); - for (PackageData packageData : packages) { - log.info("Updating flags for Package {}", packageData.getPackageName()); - List subjects = signalService.findFullSubjectsData(packageData.getId()) + List packages = signalService.findPackagesOnMonitoring(); + for (UserPackage userPackage : packages) { + log.info("Updating flags for Package {}", userPackage.getPackageName()); + List subjects = signalService.findFullSubjectsData(userPackage.getId()) .stream().filter(subject -> subject.getCalculatedAt() != null && hasDaysPassed(subject.getCalculatedAt())).toList(); - updateFlags(packageData.getId(), subjects, packageData.getPackageName()); + updateFlags(userPackage.getId(), subjects, userPackage.getPackageName()); } log.info("Finish updating flags"); } - private void updateFlags(Integer packageId, List subjects, String packageName) { + private void updateFlags(Integer packageId, List subjects, String packageName) { try { - signalService.setPackageStatus(packageId, Status.PROCESSING); + signalService.updatePackageStatus(packageId, Status.PROCESSING); List phoneFidsData = signalService.updateFlags(subjects, packageId); if (!phoneFidsData.isEmpty()) { Signals signals = signalService.buildSignals(packageId, phoneFidsData); if (signalRestService.update(signals)) { log.info("Flags were updated successfully. PackageId: {} PackageName: {}. Package status changed to ON_MONITORING", packageId, packageName); - signalService.setPackageStatus(packageId, Status.ON_MONITORING); + signalService.updatePackageStatus(packageId, Status.ON_MONITORING); } else { log.info("Updated package registration was rejected by signal service. PackageId: {} PackageName: {}", packageId, packageName); - signalService.setPackageStatus(packageId, Status.ERROR); + signalService.updatePackageStatus(packageId, Status.ERROR); } } else { log.info("No flags were updated for package id {}. Package status changed to ON_MONITORING", packageId); - signalService.setPackageStatus(packageId, Status.ON_MONITORING); + signalService.updatePackageStatus(packageId, Status.ON_MONITORING); } } catch (Exception e) { log.error("Ошибка при поиске фидов или перерасчете флагов просрочек. Package_id {}", packageId, e); diff --git a/src/main/java/ru/nbch/credit_tracker/service/indic/PhoneService.java b/src/main/java/ru/nbch/credit_tracker/service/indic/PhoneService.java index 0672f84..18c09ae 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/indic/PhoneService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/indic/PhoneService.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import org.springframework.stereotype.Service; -import ru.nbch.credit_tracker.entities.dto.SubjectData; +import ru.nbch.credit_tracker.entities.dto.PhoneFidMap; import ru.nbch.credit_tracker.mapper.indic.PhoneMapper; import java.time.LocalDate; @@ -20,16 +20,12 @@ public class PhoneService { this.mapper = mapper; } - public List findFidsPhoneData(List subjects) { - return findFidsPhoneData(subjects, false); - } - - public List findFidsPhoneData(List subjects, boolean processNullFids) { + public List findFidsPhoneData(List subjects) { List fidsPhoneDataList = new ArrayList<>(); int batchSize = 10000; for (int i = 0; i < subjects.size(); i += batchSize) { int end = Math.min(i + batchSize, subjects.size()); - List currentSubjects = subjects.subList(i, end); + List currentSubjects = subjects.subList(i, end); List phones = currentSubjects.stream().map(subject -> "9" + subject.getPhone()).toList(); List fidsData = mapper.findFids(phones); @@ -40,7 +36,7 @@ public class PhoneService { Integer fid = fidsMap.get(phone); if (fid != null) { fidsPhoneDataList.add(new FidsPhoneData(subject.getId(), fid, subject.getPhone(), subject.getSubjectId())); - } else if (processNullFids) { + } else { fidsPhoneDataList.add(new FidsPhoneData(subject.getId(), null, subject.getPhone(), subject.getSubjectId())); } }); diff --git a/src/main/java/ru/nbch/credit_tracker/service/signal/HitsService.java b/src/main/java/ru/nbch/credit_tracker/service/signal/HitsService.java new file mode 100644 index 0000000..5d319d3 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/service/signal/HitsService.java @@ -0,0 +1,21 @@ +package ru.nbch.credit_tracker.service.signal; + +import org.springframework.stereotype.Service; +import ru.nbch.credit_tracker.entities.dto.Hit; +import ru.nbch.credit_tracker.mapper.signal.HitsMapper; + +import java.util.List; + +@Service +public class HitsService { + + private final HitsMapper mapper; + + public HitsService(HitsMapper mapper) { + this.mapper = mapper; + } + + public void insertHits(List hits) { + mapper.insertHits(hits); + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/service/signal/PhoneFidMapService.java b/src/main/java/ru/nbch/credit_tracker/service/signal/PhoneFidMapService.java new file mode 100644 index 0000000..97fc8c0 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/service/signal/PhoneFidMapService.java @@ -0,0 +1,34 @@ +package ru.nbch.credit_tracker.service.signal; + +import org.springframework.stereotype.Service; +import ru.nbch.credit_tracker.entities.dto.PhoneFidMap; +import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject; +import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper; + +import java.util.List; + +@Service +public class PhoneFidMapService { + + private final PhoneFidMapMapper mapper; + + public PhoneFidMapService(PhoneFidMapMapper mapper) { + this.mapper = mapper; + } + + public void registerSubjects(List subjects, Integer packageId) { + mapper.registerSubjects(subjects, packageId); + } + + public List findPhoneFidMaps(Integer packageId) { + return mapper.findPhoneFidMaps(packageId); + } + + public List findFullPhoneFidMap(Integer packageId) { + return mapper.findFullPhoneFidMap(packageId); + } + + public void updatePhoneFidMaps(List subjects) { + mapper.updatePhoneFidMaps(subjects); + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/service/signal/SignalRestService.java b/src/main/java/ru/nbch/credit_tracker/service/signal/SignalRestService.java index 33a0cb8..b53ee2b 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/signal/SignalRestService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/signal/SignalRestService.java @@ -15,7 +15,6 @@ import ru.nbch.credit_tracker.entities.response.external_errors.SgnlReport; import ru.nbch.credit_tracker.entities.response.online_report.SgnlOnlineReport; 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.XmlUtilService; import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor; import java.io.ByteArrayOutputStream; @@ -35,14 +34,17 @@ public class SignalRestService { private static String DOWNLOAD_REPORT_URI = "onlinedownload"; private final RestTemplate restTemplate; - private final XmlUtilService xmlUtilService; + private final IXmlProcessor xmlProcessor; + private final StaxXmlProcessor staxProcessor; private final String authToken; public SignalRestService(@Qualifier(value = "restTemplate") RestTemplate restTemplate, - XmlUtilService xmlUtilService, + IXmlProcessor xmlProcessor, + StaxXmlProcessor staxProcessor, CreditTrackerSettings config) throws Exception { this.restTemplate = restTemplate; - this.xmlUtilService = xmlUtilService; + this.xmlProcessor = xmlProcessor; + this.staxProcessor = staxProcessor; this.authToken = buildToken(config.getSignalsToken(), config.getSignalsuser()); } @@ -64,8 +66,7 @@ public class SignalRestService { // good response return true; } else if (response.getStatusCode().value() == 200 && response.getBody() != null) { - StaxXmlProcessor staxXmlProcessor = xmlUtilService.staxXmlProcessor(); - SgnlReport error = staxXmlProcessor.read(response.getBody(), SgnlReport.class); + SgnlReport error = staxProcessor.read(response.getBody(), SgnlReport.class); if (error.getError().getDescription() != null) { log.error("Ошибка при постановке пакета на мониторинг в официальный сервис сигналов: {}", error.getError().getDescription()); } else { @@ -92,8 +93,7 @@ public class SignalRestService { ); String answer = response.getBody(); - StaxXmlProcessor staxXmlProcessor = xmlUtilService.staxXmlProcessor(); - SgnlReport error = staxXmlProcessor.read(answer, SgnlReport.class); + SgnlReport error = staxProcessor.read(answer, SgnlReport.class); if (error.getError().getDescription() != null) { log.error("Ошибка при удалении пакета из сервиса НБКИ. packCode={}. Описание: {}", packCode, error.getError().getDescription()); } @@ -116,15 +116,13 @@ public class SignalRestService { String answer = response.getBody(); - StaxXmlProcessor staxXmlProcessor = xmlUtilService.staxXmlProcessor(); - SgnlReport error = staxXmlProcessor.read(answer, SgnlReport.class); + SgnlReport error = staxProcessor.read(answer, SgnlReport.class); if (error.getError().getDescription() != null) { log.error("Ошибка при получении пакета из сервиса НБКИ. packCode={}. Описание: {}", packCode, error.getError().getDescription()); return null; } try { - IXmlProcessor processor = xmlUtilService.createJaxbProcessor(); - return processor.read(answer, SgnlOnlineReport.class); + return xmlProcessor.read(answer, SgnlOnlineReport.class); } catch (Exception e) { log.error("Ошибка при получении пакета из сервиса НБКИ. Код ошибки: {} packCode={}", response.getStatusCode().value(), packCode); return null; @@ -148,8 +146,7 @@ public class SignalRestService { byte[] answer = response.getBody(); if (isXmlError(response.getBody())) { - StaxXmlProcessor staxXmlProcessor = xmlUtilService.staxXmlProcessor(); - SgnlReport error = staxXmlProcessor.read(answer, SgnlReport.class); + SgnlReport error = staxProcessor.read(answer, SgnlReport.class); if (error.getError().getDescription() != null) { log.error("Ошибка при скачивание отчета. fNameReport={}. Описание: {}", reportName, error.getError().getDescription()); return null; @@ -175,8 +172,7 @@ public class SignalRestService { } private Resource compressFile(Signals signals) throws Exception { - IXmlProcessor processor = xmlUtilService.createJaxbProcessor(); - String requestData = processor.asString(signals, false); + String requestData = xmlProcessor.asString(signals, false); ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); try (GZIPOutputStream gzipStream = new GZIPOutputStream(byteStream)) { diff --git a/src/main/java/ru/nbch/credit_tracker/service/signal/UserPackageService.java b/src/main/java/ru/nbch/credit_tracker/service/signal/UserPackageService.java new file mode 100644 index 0000000..33c169e --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/service/signal/UserPackageService.java @@ -0,0 +1,55 @@ +package ru.nbch.credit_tracker.service.signal; + +import org.springframework.stereotype.Service; +import ru.nbch.credit_tracker.entities.dto.UserPackage; +import ru.nbch.credit_tracker.enums.Status; +import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper; + +import java.time.LocalDateTime; +import java.util.List; + +@Service +public class UserPackageService { + + private final UserPackageMapper mapper; + + public UserPackageService(UserPackageMapper mapper) { + this.mapper = mapper; + } + + public boolean isPackageNotUnique(String userId, String packageName) { + return mapper.isPackageNotUnique(userId.substring(0, 6), packageName); + } + + public boolean isPackageExists(String userId, String packageName, Status status) { + return mapper.isPackageExists(userId.substring(0, 6), packageName, status.name()); + } + + 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); + } + + public Integer insertPackage(UserPackage userPackage) { + return mapper.insertPackage(userPackage); + } + + public void updatePackageStatus(Integer packageId, Status status) { + mapper.updatePackageStatus(packageId, status.name()); + } + + public void updatePackageLastDownloadedReport(Integer id, String fileName) { + mapper.updatePackageLastDownloadedReport(id, fileName); + } + + public UserPackage findPackage(Integer id) { + return mapper.findPackage(id); + } + + public List findUserPackages(String userId, Status status) { + return mapper.findUserPackages(userId.substring(0, 6), status.name()); + } + + public List findAllPackagesByStatus(Status status) { + return mapper.findAllPackagesByStatus(status.name()); + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java b/src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java index e37458a..3695db8 100644 --- a/src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java +++ b/src/main/java/ru/nbch/credit_tracker/utils/ValidationUtil.java @@ -1,29 +1,82 @@ package ru.nbch.credit_tracker.utils; +import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest; +import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject; +import ru.nbch.credit_tracker.enums.SignalError; +import ru.nbch.credit_tracker.enums.XmlErrorFormat; +import ru.nbch.credit_tracker.exceptions.SignalClientException; + +import java.util.HashSet; +import java.util.Set; import java.util.regex.Pattern; +import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp; + public class ValidationUtil { private static String phoneRegex = "^\\d{9}$"; private static String packageNameRegex = "^[A-Z0-9_]{1,22}$"; private static String npIdRegex = "^\\S{1,36}$"; + public static void validateMonitoringRequest(MonitoringRequest request) throws SignalClientException { + if (request == null) { + throw clientExcp(SignalError.ERROR_011, XmlErrorFormat.MonitoringError); + } - public static boolean validatePhone(String input) { + if (request.getUserId() == null) { + throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "UserId"); + } + + if (request.getPackageName() == null) { + throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "PackageName"); + } + + if (request.getPassword() == null) { + throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Password"); + } + + if (request.getSubjects() == null) { + throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Subjects"); + } + + if (request.getSubjects().getSubject().isEmpty()) { + throw clientExcp(SignalError.ERROR_002, XmlErrorFormat.MonitoringError, "Subject"); + } + + if (!validatePackageName(request.getPackageName())) { + throw clientExcp(SignalError.ERROR_008, XmlErrorFormat.MonitoringError, "Subject"); + } + + Set uniqueIds = new HashSet<>(); + for (Subject subject : request.getSubjects().getSubject()) { + if (!validatePhone(subject.getClientId())) { + throw clientExcp(SignalError.ERROR_003, XmlErrorFormat.MonitoringError); + } + if (!validateNPId(subject.getId())) { + throw clientExcp(SignalError.ERROR_010, XmlErrorFormat.MonitoringError); + } + // проверка на уникальность Id внутри одного пакета + if (!uniqueIds.add(subject.getId())) { + throw clientExcp(SignalError.ERROR_004, XmlErrorFormat.MonitoringError, subject.getId()); + } + } + } + + private static boolean validatePhone(String input) { if(input == null) { return false; } return Pattern.matches(phoneRegex, input); } - public static boolean validatePackageName(String input) { + private static boolean validatePackageName(String input) { if(input == null) { return false; } return Pattern.matches(packageNameRegex, input); } - public static boolean validateNPId(String input) { + private static boolean validateNPId(String input) { if(input == null) { return false; } diff --git a/src/main/java/ru/nbch/credit_tracker/utils/ZipUtils.java b/src/main/java/ru/nbch/credit_tracker/utils/ZipUtils.java new file mode 100644 index 0000000..4d1438e --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/utils/ZipUtils.java @@ -0,0 +1,28 @@ +package ru.nbch.credit_tracker.utils; + +import java.io.IOException; +import java.util.Optional; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ZipUtils { + public static Optional extractValidEntry(ZipInputStream inputStream) throws IOException { + Optional zipEntry = Optional.empty(); + ZipEntry entry; + while ((entry = inputStream.getNextEntry()) != null) { + if (!entry.isDirectory()) { + if (zipEntry.isPresent()) { + //если мы уже нашли валидный xml файл, то обработка всего файла недоступна, возвращаем пустой entry + return Optional.empty(); + } + if (entry.getName().toLowerCase().endsWith(".xml")) { // Файл должен быть с расширением xml + zipEntry = Optional.of(entry); + } + } + inputStream.closeEntry(); + } + return zipEntry; + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java b/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java new file mode 100644 index 0000000..a15457c --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/utils/error/ExceptionUtils.java @@ -0,0 +1,18 @@ +package ru.nbch.credit_tracker.utils.error; + +import ru.nbch.credit_tracker.enums.EnumKeyMessage; +import ru.nbch.credit_tracker.enums.IEnumKeyCode; +import ru.nbch.credit_tracker.enums.XmlErrorFormat; +import ru.nbch.credit_tracker.exceptions.SignalClientException; +import ru.nbch.credit_tracker.exceptions.SignalServerException; + +public class ExceptionUtils { + + public static SignalClientException clientExcp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Object... args) { + return new SignalClientException(new EnumKeyMessage(enumKeyCode, args), xmlErrorFormat); + } + + public static SignalServerException serverExcp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Object... args) { + return new SignalServerException(new EnumKeyMessage(enumKeyCode, args), xmlErrorFormat); + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/utils/error/SimpleMessageResolver.java b/src/main/java/ru/nbch/credit_tracker/utils/error/SimpleMessageResolver.java new file mode 100644 index 0000000..d856415 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/utils/error/SimpleMessageResolver.java @@ -0,0 +1,13 @@ +package ru.nbch.credit_tracker.utils.error; + +import ru.nbch.credit_tracker.enums.EnumKeyMessage; + +import java.util.Arrays; + + +public class SimpleMessageResolver { + public String resolve(EnumKeyMessage errorMessage) { + if (errorMessage == null) return "null"; + return String.format("%s %s", errorMessage.getSubject().getKey(), Arrays.toString(errorMessage.getArgs())); + } +} diff --git a/src/main/resources/mybatis/mapper/signal/HitsMapper.xml b/src/main/resources/mybatis/mapper/signal/HitsMapper.xml new file mode 100644 index 0000000..2a64fdb --- /dev/null +++ b/src/main/resources/mybatis/mapper/signal/HitsMapper.xml @@ -0,0 +1,16 @@ + + + + + + + INSERT INTO signals_hits (package_id, subject_id, signal_type, response_sent_at, report_file_name) + values + + (#{hit.packageId}, #{hit.subjectId}, #{hit.signalType}, #{hit.responseSentAt}, #{hit.reportFileName}) + + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/mapper/signal/PhoneFidMapMapper.xml b/src/main/resources/mybatis/mapper/signal/PhoneFidMapMapper.xml new file mode 100644 index 0000000..74aa773 --- /dev/null +++ b/src/main/resources/mybatis/mapper/signal/PhoneFidMapMapper.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + INSERT INTO signals_phone_fid_map (subject_id, phone, fid, package_id) + values + + (#{subject.id}, #{subject.clientId}, NULL, #{packageId}) + + + + + + + UPDATE signals_phone_fid_map + SET + package_id = #{subject.packageId}, + subject_id = #{subject.subjectId}, + phone = #{subject.phone}, + fid = #{subject.fid}, + flag_debt5000 = #{subject.flagDebt5000}, + flag_90_12 = #{subject.flag90days}, + calculated_at = #{subject.calculatedAt} + WHERE id = #{subject.id} + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/mapper/signal/SignalMapper.xml b/src/main/resources/mybatis/mapper/signal/SignalMapper.xml deleted file mode 100644 index cfd25c2..0000000 --- a/src/main/resources/mybatis/mapper/signal/SignalMapper.xml +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UPDATE signals_user_packages - SET status = #{status}, deactivated_at = #{deactivatedAt} - WHERE membercode IS NOT NULL AND LEFT(membercode, 6) = #{userId} AND package_name = #{packageName} AND status = - #{previousStatus} - - - - - - INSERT INTO signals_user_packages (membercode, package_name, created_at, status) - values (#{request.userId}, #{request.packageName}, #{creadedAt}, #{status}) - - - - INSERT INTO signals_phone_fid_map (subject_id, phone, fid, package_id) - values - - (#{subject.id}, #{subject.clientId}, NULL, #{packageId}) - - - - - INSERT INTO signals_hits (package_id, subject_id, signal_type, response_sent_at, report_file_name) - values - - (#{hit.packageId}, #{hit.subjectId}, #{hit.signalType}, #{hit.responseSentAt}, #{hit.reportFileName}) - - - - - - UPDATE signals_phone_fid_map - SET - package_id = #{subject.packageId}, - subject_id = #{subject.subjectId}, - phone = #{subject.phone}, - fid = #{subject.fid}, - flag_debt5000 = #{subject.flagDebt5000}, - flag_90_12 = #{subject.flag90days}, - calculated_at = #{subject.calculatedAt} - WHERE id = #{subject.id} - - - - - UPDATE signals_phone_fid_map - SET fid = #{fid}, flag_debt5000 = #{flagDebt5000}, flag_90_12 = #{flag90}, calculated_at = #{calculatedAt} - WHERE id = #{id} - - - - UPDATE signals_user_packages - SET status = #{status} - WHERE id = #{packageId} - - - - UPDATE signals_user_packages - SET last_downloaded_report = #{fileName} - WHERE id = #{id} - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/mybatis/mapper/signal/UserPackageMapper.xml b/src/main/resources/mybatis/mapper/signal/UserPackageMapper.xml new file mode 100644 index 0000000..7a0cdc8 --- /dev/null +++ b/src/main/resources/mybatis/mapper/signal/UserPackageMapper.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + UPDATE signals_user_packages + SET status = #{status}, deactivated_at = #{deactivatedAt} + WHERE membercode IS NOT NULL AND LEFT(membercode, 6) = #{userId} AND package_name = #{packageName} AND status = + #{previousStatus} + + + + + + UPDATE signals_user_packages + SET status = #{status} + WHERE id = #{packageId} + + + + UPDATE signals_user_packages + SET last_downloaded_report = #{fileName} + WHERE id = #{id} + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/ru/nbch/credit_tracker/utils/UtilTest.java b/src/test/java/ru/nbch/credit_tracker/utils/UtilTest.java new file mode 100644 index 0000000..c7dc696 --- /dev/null +++ b/src/test/java/ru/nbch/credit_tracker/utils/UtilTest.java @@ -0,0 +1,156 @@ +package ru.nbch.credit_tracker.utils; + +import jakarta.xml.bind.JAXBException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest; +import ru.nbch.credit_tracker.enums.SignalError; +import ru.nbch.credit_tracker.exceptions.SignalClientException; +import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor; +import ru.nbch.credit_tracker.service.xml.jaxb.XmlProcessorImplAnyClasses; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Collections; +import java.util.Optional; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +@SpringBootTest(classes = {UtilTest.TestConfig.class}) +public class UtilTest { + + private final IXmlProcessor xmlProcessor; + + @Autowired + public UtilTest(IXmlProcessor xmlProcessor) { + this.xmlProcessor = xmlProcessor; + } + + @Configuration + public static class TestConfig { + @Bean + public IXmlProcessor xmlProcessor() throws JAXBException { + return new XmlProcessorImplAnyClasses(Charset.forName("windows-1251"), + MonitoringRequest.class); + } + } + + private static Stream entryTestCases() { + return Stream.of( + Arguments.of( + "/monitoring_request/valid_request.zip", + true + ), + Arguments.of( + "/monitoring_request/directory_request.zip", + false + ) + , + Arguments.of( + "/monitoring_request/empty_request.zip", + false + ) + , + Arguments.of( + "/monitoring_request/many_files_request.zip", + false + ) + , + Arguments.of( + "/monitoring_request/txt_request.zip", + false + ) + ); + } + + @ParameterizedTest(name = "[{index}] PATH: [ {0} ] EXPECTED: [ {1} ]") + @MethodSource("entryTestCases") + void testExtractEntryFromZip(String path, boolean expected) { + ZipInputStream zipInputStream; + Optional xmlFileEntry; + try { + zipInputStream = new ZipInputStream(getClass().getResourceAsStream(path)); + xmlFileEntry = ZipUtils.extractValidEntry(zipInputStream); + Assertions.assertEquals(expected, xmlFileEntry.isPresent()); + zipInputStream.close(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static Stream validationTestCases() { + return Stream.of( + Arguments.of( + "/monitoring_request/valid_request.zip", + null, + null + ), + Arguments.of( + "/monitoring_request/invalid_xml.zip", + SignalError.ERROR_011, + Collections.emptyList().toArray(new Object[0]) + ) + , + Arguments.of( + "/monitoring_request/no_required_tag_request.zip", + SignalError.ERROR_002, + new Object[]{"Password"} + ), + Arguments.of( + "/monitoring_request/invalid_phone_request.zip", + SignalError.ERROR_003, + Collections.emptyList().toArray(new Object[0]) + ), + Arguments.of( + "/monitoring_request/invalid_id_request.zip", + SignalError.ERROR_010, + Collections.emptyList().toArray(new Object[0]) + ), + Arguments.of( + "/monitoring_request/no_unique_ids_request.zip", + SignalError.ERROR_004, + new Object[]{"abc125"} + ) + ); + } + + @ParameterizedTest(name = "[{index}] PATH: [ {0} ] SIGNALERROR: [ {1} ] ARGS [ {2} ]") + @MethodSource("validationTestCases") + void testMonitoringRequestValidation(String path, SignalError signalError, Object[] args) { + ZipInputStream zipInputStream = null; + MonitoringRequest monitoringRequest; + try { + zipInputStream = new ZipInputStream(getClass().getResourceAsStream(path)); + zipInputStream.getNextEntry(); + monitoringRequest = xmlProcessor.read(zipInputStream, MonitoringRequest.class); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (zipInputStream != null) { + try { + zipInputStream.close(); + } catch (IOException e) { + throw new RuntimeException(); + } + } + } + + SignalClientException ex = null; + try { + ValidationUtil.validateMonitoringRequest(monitoringRequest); + } catch (SignalClientException e) { + ex = e; + } + if (ex != null) { + Assertions.assertEquals(signalError, ex.getErrorMessage().getSubject()); + Assertions.assertArrayEquals(args, ex.getErrorMessage().getArgs()); + } + } +} diff --git a/src/test/resources/monitoring_request/directory_request.zip b/src/test/resources/monitoring_request/directory_request.zip new file mode 100644 index 0000000000000000000000000000000000000000..7ad23ba857b6fea2c7e0e355e5acf2faeba850c3 GIT binary patch literal 154 zcmWIWW@Zs#0D*~dkD|Z~D8U7!Q!Jfm_2z^`(3Scot h1__3s&ZW!rUf*VfDuPo1-mGjO4kHl80BH@d3;?cJ6W9O% literal 0 HcmV?d00001 diff --git a/src/test/resources/monitoring_request/empty_request.zip b/src/test/resources/monitoring_request/empty_request.zip new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/monitoring_request/invalid_id_request.zip b/src/test/resources/monitoring_request/invalid_id_request.zip new file mode 100644 index 0000000000000000000000000000000000000000..0de7ae4ebac795fd1eb48b1a8fe2ade2ef3ea4fd GIT binary patch literal 415 zcmWIWW@Zs#U|`^2=*)N&b-?SY$y*@Lh>3wg3`l3@l_ln6ro;nLQEFjnYH^8PMQ+aA ziPrvy4MbYgKWQ&AXqMkNTWROI1>8KY9ql2@w0zfTIcIm@Q2kSr=d?)2lilWq-Se3G zx|L7Qe-x;9e%iaayCwFr3S0D!OE>;1t?bo}eY;*_x=!RPkF|464~9zE9lp+4b0JV> zwK@M)=argEb2cB8b9eoB#;pF--u1DeuNt&PUZ%_!o&Qr#?z8fXufM;&`&L@IKeebY z)%jA`zBy&`0W9}B9L-i;-ElqjvdF>6{B?Y6IS$R~nv0vdXDaQzUg*I->)5m1O@)R> zpRN?CcxZg5+jE6XdywVynI4hf^k3x2R9)U$te$)1! literal 0 HcmV?d00001 diff --git a/src/test/resources/monitoring_request/invalid_phone_request.zip b/src/test/resources/monitoring_request/invalid_phone_request.zip new file mode 100644 index 0000000000000000000000000000000000000000..f32304894634f65193fa43caa088df52d62d060f GIT binary patch literal 422 zcmWIWW@Zs#U|`^2xSa7Q%Hc7G$vYs=jER9k5=dv}l_ln6ro8-*vu*oByZWmruF1)t@)* zh&Hx7x=Arpdw&0HevPL5BMQ=2v+ii$7wK8v^7QEPOUuSa%xk(qx$0uuh-4B&Qxw&9+vXt^kVq{Z$>72 z23*0U0t_e+Pymy70*wo*gpomlLAvtve~Z_*8KHXMRDd@t8;HXQgxNq^6|4dPJdd7P literal 0 HcmV?d00001 diff --git a/src/test/resources/monitoring_request/invalid_xml.zip b/src/test/resources/monitoring_request/invalid_xml.zip new file mode 100644 index 0000000000000000000000000000000000000000..25fc1766e7819b937f36b42df2951c1c5b15895f GIT binary patch literal 312 zcmWIWW@Zs#U|`^2&`Wz1Wqq-5)9u9^k>#Z+GW?Z*6C&`BiFjWd5p> zTeCcwzFTxo)m(EW&E8Whcgfm23>?iVT1xx2xK&5DeR7?9?o_4VQN#M;RWTlohHYP^ zt~1NT9@!?=yZUR^&-=7k==9ld9}`Vy=Qs9R?8<#Lb^Y_ZyS4VL ze%Qs!%9s9hHS?N7%0Dz3AK5iSOqrng*?& z=ALz<*zu^<#H`Do^nz4>CH>=kdL+BOPa;dzcMF`_tUEZXQXWs>^SS1uB~2p zwy5@3rrx|-u@yV&6)vb4BZCCPdCU5l=C5xvLKVTO S0B=?{5Qh;6V}LXpSOoxU^@e)@ literal 0 HcmV?d00001 diff --git a/src/test/resources/monitoring_request/no_unique_ids_request.zip b/src/test/resources/monitoring_request/no_unique_ids_request.zip new file mode 100644 index 0000000000000000000000000000000000000000..ee9204970b1392e35382fd18f4dcf21fff2a790a GIT binary patch literal 417 zcmWIWW@Zs#U|`^2u*rB7^{u~t=}REbn2CWw5=iIe$Cu`17M7;QXQmX#7o`GO#U*+b zxjAbmTKgY15NS>Sq`m0P1NWRDmFuDU>T3 zJ*W8Z&!uX+&szO!KP8=hoOAbLPo8ZBOE<1A43duCb?d&7UZl~*iL)%Tn^qgtwC~sb zv0$-9SiIb-=|RC>H*5NA`?_S#nAM-&yFNDbRfD$3%ar+|`+su9edc{}^ZTQhAB%tO zNhoSbb-ol6oh`?qIbCycQ+Ks%)q3WMeIdIccUxWSQ>^=j-R@ZV^0etzGnF|67223#Se0t_P% rPymy7!ix*4gpomlA-<+2+~W0ZMyMV*72wUv2I4RRVK$If0IL81cv6~v literal 0 HcmV?d00001 diff --git a/src/test/resources/monitoring_request/txt_request.zip b/src/test/resources/monitoring_request/txt_request.zip new file mode 100644 index 0000000000000000000000000000000000000000..b635e012ec8c0577403f5cda9c34160f958b9bd4 GIT binary patch literal 156 zcmWIWW@h1H0D;Q5M^Rt~l;8%^MX80Qsl_FFB^4zB-i%E447il4Ks6~qX(WwY3=ly^ h1__2<>kr*}uWvI#Rl%tMZ&o%ChY<*4fwU%A1^^OF6zc#0 literal 0 HcmV?d00001 diff --git a/src/test/resources/monitoring_request/valid_request.zip b/src/test/resources/monitoring_request/valid_request.zip new file mode 100644 index 0000000000000000000000000000000000000000..e1ac937be152015ee36765e2f09b281a87fb1d38 GIT binary patch literal 390 zcmWIWW@Zs#U|`^2cvg2WimCS||0^KRn2CXb8%P(W7M7+Km*`dG=FFYwn14t?qV4?a z^%+&=9|AYbQb_x}h<$o$apycA-6I<`k2Jlm`}ZPimG>>#Z+GW?Z*6C&`BiFjWd5p> zTeCcwzFTxo)m(EW&E8Whcgfm23>?iVT1xx2xK&5DeR7?9?o_4VQN#M;RWTlohHYP^ zt~1NT9@!?=yZUR^&-=7k==9ld9}`Vy=Qs9R?8<#Lb^Y_ZyS4VL ze%Qs!%9s9hH