some refactoring and new Facade classes

This commit is contained in:
etreschenkov 2025-10-07 10:44:27 +03:00
parent f4b49c06ed
commit 194828d0b7
17 changed files with 654 additions and 1 deletions

View file

@ -0,0 +1,90 @@
package ru.nbch.credit_tracker.component;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
import ru.nbch.credit_tracker.enums.SignalError;
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
import ru.nbch.credit_tracker.exceptions.SignalException;
import ru.nbch.credit_tracker.model.MonitoringValidationError;
import ru.nbch.credit_tracker.model.ValidationResult;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
import ru.nbch.credit_tracker.utils.ValidationUtil;
import ru.nbch.credit_tracker.utils.ZipUtils;
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp;
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp;
@Component
@Slf4j
public class MonitoringRequestValidator {
private final CreditTrackerSettings config;
private final StaxXmlProcessor staxXmlProcessor;
public MonitoringRequestValidator(CreditTrackerSettings config,
StaxXmlProcessor staxXmlProcessor) {
this.config = config;
this.staxXmlProcessor = staxXmlProcessor;
}
public void validateZipContent(MultipartFile file) {
log.trace("Validating zip content");
if (file.isEmpty() || !ZipUtils.isZipFile(file)) {
throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
}
// Валидация Архива на количетсво файлов, размер и расширение
try (ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream())) {
Optional<ZipEntry> xmlFileEntry = ZipUtils.extractValidEntry(zipInputStream);
if (xmlFileEntry.isEmpty()) {
throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
}
long maxXmlFileSize = config.getMaxXmlFileSize() * 1024 * 1024;
if (xmlFileEntry.get().getSize() > maxXmlFileSize) {
throw clientExcp(SignalError.ERROR_009, XmlErrorFormat.MonitoringError);
}
} catch (IOException e) {
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
}
log.trace("Validated zip content ok!");
}
public ValidationResult readAndValidateMonitoringRequest(String filePath) {
log.debug("Validating monitoring request...");
ValidationResult validationResult = new ValidationResult();
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) {
staxXmlProcessor.read(in, MonitoringRequest.class,
request -> {
try {
ValidationUtil.validateMonitoringRequest(request);
if (request.getPackageName() != null && validationResult.getPackageName() == null) {
validationResult.setPackageName(request.getPackageName());
}
if (request.getUserId() != null && validationResult.getUserId() == null) {
validationResult.setUserId(request.getUserId());
}
if (request.getPassword() != null && validationResult.getPassword() == null) {
validationResult.setPassword(request.getPassword());
}
request.getSubjects().getSubject().clear();
} catch (SignalException e) {
validationResult.addError(new MonitoringValidationError(-1, "", e));
}
},
request -> request.getSubjects().getSubject().isEmpty(),
40000, "/MonitoringRequest/Subjects/Subject");
} catch (IOException e) {
throw new RuntimeException("Error while parsing and validating monitoring request", e);
}
log.debug("Validating monitoring request {}!", validationResult.getValidationErrors().isEmpty() ? "ok" : "fail");
return validationResult;
}
}

View file

@ -0,0 +1,15 @@
package ru.nbch.credit_tracker.config;
import java.util.ArrayDeque;
import java.util.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public Queue<Integer> registeredPackages() {
return new ArrayDeque<>();
}
}

View file

@ -0,0 +1,24 @@
package ru.nbch.credit_tracker.config.task;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.nbch.credit_tracker.model.PackageSavePayload;
import ru.nbch.credit_tracker.service.task.PackageSaver;
import ru.nbch.credit_tracker.service.task.TaskConsumer;
@Configuration
public class ConsumerConfig {
@Bean
public BlockingQueue<PackageSavePayload> savingRequest() {
return new LinkedBlockingQueue<>();
}
@Bean
public TaskConsumer<PackageSavePayload> saverTask(PackageSaver packageSaver,
BlockingQueue<PackageSavePayload> savingRequest) {
return new TaskConsumer<>(packageSaver, savingRequest, Executors.newFixedThreadPool(5));
}
}

View file

@ -0,0 +1,30 @@
package ru.nbch.credit_tracker.controller;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse;
import ru.nbch.credit_tracker.facade.SignalFacadeV2;
@RestController
@RequestMapping("/api/v2/signal")
public class SignalControllerV2 {
private final SignalFacadeV2 signalFacadeV2;
public SignalControllerV2(SignalFacadeV2 signalFacadeV2) {
this.signalFacadeV2 = signalFacadeV2;
}
@PostMapping(value = "/set", produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<MonitoringSetupResponse> setupMonitoring(@RequestParam("file") MultipartFile file) {
signalFacadeV2.setupMonitoringRequest(file);
return ResponseEntity.ok().body(new MonitoringSetupResponse());
}
}

View file

@ -0,0 +1,108 @@
package ru.nbch.credit_tracker.facade;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import javax.xml.stream.XMLStreamException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import ru.nbch.credit_tracker.component.MonitoringRequestValidator;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.enums.SignalError;
import ru.nbch.credit_tracker.enums.Status;
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
import ru.nbch.credit_tracker.exceptions.SignalClientException;
import ru.nbch.credit_tracker.model.MonitoringValidationError;
import ru.nbch.credit_tracker.model.PackageSavePayload;
import ru.nbch.credit_tracker.model.ValidationResult;
import ru.nbch.credit_tracker.service.SignalService;
import ru.nbch.credit_tracker.service.scoring.AuthorizationService;
import ru.nbch.credit_tracker.utils.CTUtil;
import ru.nbch.credit_tracker.utils.ZipUtils;
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp;
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp;
@Service
@Slf4j
public class SignalFacadeV2 {
private final MonitoringRequestValidator monitoringRequestValidator;
private final CreditTrackerSettings config;
private final SignalService signalService;
private final AuthorizationService authorizationService;
private final BlockingQueue<PackageSavePayload> savingRequest;
public SignalFacadeV2(MonitoringRequestValidator monitoringRequestValidator,
CreditTrackerSettings config,
SignalService signalService,
AuthorizationService authorizationService,
BlockingQueue<PackageSavePayload> savingRequest) {
this.monitoringRequestValidator = monitoringRequestValidator;
this.config = config;
this.signalService = signalService;
this.authorizationService = authorizationService;
this.savingRequest = savingRequest;
}
public void setupMonitoringRequest(MultipartFile file) {
log.debug("Start processing monitoring request");
monitoringRequestValidator.validateZipContent(file);
log.trace("Saving monitoring request to tmp file...");
String filePath;
try {
String folderPath = config.getLoadDir() + File.separator + "tmp_folder" + File.separator;
filePath = ZipUtils.writeTmpFile(folderPath, file);
} catch (IOException e) {
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
}
log.debug("File saved to {}", filePath);
ValidationResult validationResult = null;
try {
validationResult = monitoringRequestValidator.readAndValidateMonitoringRequest(filePath);
if (!validationResult.getValidationErrors().isEmpty()) {
MonitoringValidationError firstError = validationResult.getValidationErrors().get(0);
signalService.rejectPackage(validationResult.getUserId(), validationResult.getPackageName());
FileUtils.delete(new File(filePath));
throw firstError.getSignalException();
}
} catch (RuntimeException e) {
if (e.getCause() instanceof XMLStreamException) {
throw clientExcp(SignalError.ERROR_011, XmlErrorFormat.MonitoringError);
}
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
} catch (IOException e) {
log.warn("Error deleting tmp file", e);
}
String packageName = validationResult.getPackageName();
String userId = validationResult.getUserId();
String password = validationResult.getPassword();
try {
// проверка авторизации
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(userId, password);
if (!authResult.isSuccess()) {
signalService.rejectPackage(userId, packageName);
throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringError);
}
// проверка на уникальность пакета
if (signalService.isPackageNotUnique(userId, packageName)) {
signalService.rejectPackage(userId, packageName);
throw clientExcp(SignalError.ERROR_007, XmlErrorFormat.MonitoringError);
}
Integer packageId = signalService.registerPackage(userId, packageName);
log.info("Package registered. PackageId {}. Status: {}", packageId, Status.PROCESSING.name());
savingRequest.add(new PackageSavePayload(packageId, filePath));
} catch (Exception e) {
CTUtil.removeFile(filePath);
if (e instanceof SignalClientException) {
throw (SignalClientException) e;
}
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
}
}
}

View file

@ -0,0 +1,30 @@
package ru.nbch.credit_tracker.model;
import ru.nbch.credit_tracker.exceptions.SignalException;
public class MonitoringValidationError {
private final int line;
private final String message;
private final SignalException signalException;
public MonitoringValidationError(int line,
String message,
SignalException signalException) {
this.line = line;
this.message = message;
this.signalException = signalException;
}
public int getLine() {
return line;
}
public String getMessage() {
return message;
}
public SignalException getSignalException() {
return signalException;
}
}

View file

@ -0,0 +1,21 @@
package ru.nbch.credit_tracker.model;
import ru.nbch.credit_tracker.service.task.TaskPayload;
public class PackageSavePayload implements TaskPayload {
private final Integer packageId;
private final String filePath;
public PackageSavePayload(Integer packageId, String filePath) {
this.packageId = packageId;
this.filePath = filePath;
}
public Integer getPackageId() {
return packageId;
}
public String getFilePath() {
return filePath;
}
}

View file

@ -0,0 +1,51 @@
package ru.nbch.credit_tracker.model;
import java.util.ArrayList;
import java.util.List;
public class ValidationResult {
private String packageName;
private String userId;
private String password;
private List<MonitoringValidationError> validationErrors = new ArrayList<>();
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public void setUserId(String userId) {
this.userId = userId;
}
public void setValidationErrors(List<MonitoringValidationError> validationErrors) {
this.validationErrors = validationErrors;
}
public ValidationResult() {
}
public String getPackageName() {
return packageName;
}
public String getUserId() {
return userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<MonitoringValidationError> getValidationErrors() {
return validationErrors;
}
public void addError(MonitoringValidationError error) {
this.validationErrors.add(error);
}
}

View file

@ -73,6 +73,10 @@ public class SignalService {
return userPackageService.isPackageNotUnique(request.getUserId(), request.getPackageName()); return userPackageService.isPackageNotUnique(request.getUserId(), request.getPackageName());
} }
public boolean isPackageNotUnique(String userId, String packageName) {
return userPackageService.isPackageNotUnique(userId, packageName);
}
public Integer registerPackage(MonitoringRequest request) { public Integer registerPackage(MonitoringRequest request) {
UserPackage userPackage = UserPackage.builder() UserPackage userPackage = UserPackage.builder()
.userId(request.getUserId()) .userId(request.getUserId())
@ -83,6 +87,16 @@ public class SignalService {
return userPackageService.insertPackage(userPackage); return userPackageService.insertPackage(userPackage);
} }
public Integer registerPackage(String userId, String packageName) {
UserPackage userPackage = UserPackage.builder()
.userId(userId)
.packageName(packageName)
.createdAt(LocalDateTime.now())
.status(Status.PROCESSING.name())
.build();
return userPackageService.insertPackage(userPackage);
}
public void registerSubjects(String filePath, Integer packageId) { public void registerSubjects(String filePath, Integer packageId) {
log.info("Start registering subjects. PackageId: {}", packageId); log.info("Start registering subjects. PackageId: {}", packageId);
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) { try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) {
@ -153,6 +167,7 @@ public class SignalService {
if (fidsMapByBatch.size() + phonesByFidToProcessing.size() <= batchSize) { if (fidsMapByBatch.size() + phonesByFidToProcessing.size() <= batchSize) {
phonesByFidToProcessing.putAll(fidsMapByBatch); phonesByFidToProcessing.putAll(fidsMapByBatch);
} else { } else {
//todo execute find name and id -> forming xml
boolean fidsFound = updateFlags(phonesByFidToProcessing, packageId); boolean fidsFound = updateFlags(phonesByFidToProcessing, packageId);
if (noFidsFound) { if (noFidsFound) {
noFidsFound = !fidsFound; noFidsFound = !fidsFound;
@ -221,6 +236,16 @@ public class SignalService {
userPackageService.insertPackage(userPackage); userPackageService.insertPackage(userPackage);
} }
public void rejectPackage(String userId, String packageName) {
UserPackage userPackage = UserPackage.builder()
.userId(userId)
.packageName(packageName)
.createdAt(LocalDateTime.now())
.status(Status.REJECTED.name())
.build();
userPackageService.insertPackage(userPackage);
}
public void updatePackageStatus(Integer packageId, Status status) { public void updatePackageStatus(Integer packageId, Status status) {
userPackageService.updatePackageStatus(packageId, status); userPackageService.updatePackageStatus(packageId, status);
} }

View file

@ -0,0 +1,5 @@
package ru.nbch.credit_tracker.service.task;
public interface Dispatcher<X> {
void handle(X taskPayload);
}

View file

@ -0,0 +1,54 @@
package ru.nbch.credit_tracker.service.task;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Queue;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
import ru.nbch.credit_tracker.model.PackageSavePayload;
import ru.nbch.credit_tracker.service.signal.PhoneFidMapService;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
@Service
@Slf4j
public class PackageSaver implements Dispatcher<PackageSavePayload> {
private final StaxXmlProcessor xmlProcessor;
private final PhoneFidMapService phoneFidMapService;
private final Queue<Integer> registeredPackage;
private final static int BATCH_SIZE = 10_000;
public PackageSaver(StaxXmlProcessor xmlProcessor,
PhoneFidMapService phoneFidMapService,
Queue<Integer> registeredPackage) {
this.xmlProcessor = xmlProcessor;
this.phoneFidMapService = phoneFidMapService;
this.registeredPackage = registeredPackage;
}
@Override
public void handle(PackageSavePayload taskPayload) {
Integer packageId = taskPayload.getPackageId();
Path pkgPath = Paths.get(taskPayload.getFilePath());
log.info("Start registering subjects. PackageId: {}", taskPayload.getPackageId());
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(pkgPath), 8 * 1024 * 1024)) {
xmlProcessor.read(in, MonitoringRequest.class,
request -> {
if (!request.getSubjects().getSubject().isEmpty()) {
phoneFidMapService.registerSubjects(request.getSubjects().getSubject(), packageId);
log.trace("Registered subject's batch. Total count: {}. PackageId: {}", request.getSubjects().getSubject().size(), packageId);
request.getSubjects().getSubject().clear();
}
},
request -> request.getSubjects().getSubject().isEmpty()
,
BATCH_SIZE, "/MonitoringRequest/Subjects/Subject");
} catch (IOException e) {
throw new RuntimeException("Error while parsing monitoring request", e);
}
log.info("Subjects were registered. PackageId: {}", packageId);
registeredPackage.add(packageId);
}
}

View file

@ -0,0 +1,48 @@
package ru.nbch.credit_tracker.service.task;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import org.springframework.context.SmartLifecycle;
public class TaskConsumer<X extends TaskPayload> implements SmartLifecycle {
private final Dispatcher<X> dispatcher;
private final BlockingQueue<X> taskQueue;
private final ExecutorService worker;
private volatile boolean running;
public TaskConsumer(Dispatcher<X> dispatcher,
BlockingQueue<X> taskQueue,
ExecutorService worker) {
this.dispatcher = dispatcher;
this.taskQueue = taskQueue;
this.worker = worker;
}
@Override
public void start() {
running = true;
worker.submit(() -> {
while (running && !Thread.currentThread().isInterrupted()) {
try {
X job = taskQueue.take();
dispatcher.handle(job);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
}
}
});
}
@Override
public void stop() {
running = false;
worker.shutdownNow();
}
@Override
public boolean isRunning() {
return running;
}
}

View file

@ -0,0 +1,4 @@
package ru.nbch.credit_tracker.service.task;
public interface TaskPayload {
}

View file

@ -104,7 +104,11 @@ public class XmlProcessorStaxImpl implements StaxXmlProcessor {
} }
@Override @Override
public <Z> Z read(InputStream inputStream, Class<Z> clazz, Consumer<Z> objProcessor, Function<Z, Boolean> emptyBatchCheckFunction, Integer batchSize, String endBatchElementPath) { public <Z> Z read(InputStream inputStream,
Class<Z> clazz, Consumer<Z> objProcessor,
Function<Z, Boolean> emptyBatchCheckFunction,
Integer batchSize,
String endBatchElementPath) {
try { try {
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream);
Supplier<StaxReader<?>> staxReaderSupplier = staxReaders.get(clazz); Supplier<StaxReader<?>> staxReaderSupplier = staxReaders.get(clazz);

View file

@ -1,10 +1,15 @@
package ru.nbch.credit_tracker.utils; package ru.nbch.credit_tracker.utils;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
@Slf4j @Slf4j
public class ZipUtils { public class ZipUtils {
@ -25,4 +30,27 @@ public class ZipUtils {
} }
return zipEntry; return zipEntry;
} }
public static 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");
}
public static String writeTmpFile(String path, MultipartFile file) throws IOException {
CTUtil.createFolder(path);
String filePath = path + UUID.randomUUID() + "monitoring_request.xml";
try (OutputStream out = Files.newOutputStream(Path.of(filePath))) {
ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream());
zipInputStream.getNextEntry();
byte[] buffer = new byte[8 * 1024 * 1024];
int bytesRead;
while ((bytesRead = zipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
return filePath;
}
}
} }

View file

@ -46,6 +46,47 @@ public class PhoneService2Test {
Assertions.assertEquals("1115", res.get(127).getPhone()); Assertions.assertEquals("1115", res.get(127).getPhone());
} }
@Test
public void defineFidByPhoneTest2() {
PhoneService2 phoneService = new PhoneService2(phoneRepository);
fidsDataWithEqualSinceDt.sort(byDbOrder);
when(phoneRepository.findFids(any())).thenReturn(fidsDataWithEqualSinceDt2);
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
Assertions.assertEquals(3, res.size());
Assertions.assertEquals("1112", res.get(125).getPhone());
Assertions.assertEquals("1114", res.get(126).getPhone());
Assertions.assertEquals("1115", res.get(127).getPhone());
}
@Test
public void defineFidByPhoneTest3() {
PhoneService2 phoneService = new PhoneService2(phoneRepository);
fidsDataWithEqualSinceDt.sort(byDbOrder);
when(phoneRepository.findFids(any())).thenReturn(fidsDataWithEqualSinceDt3);
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
Assertions.assertEquals(2, res.size());
Assertions.assertEquals("1114", res.get(126).getPhone());
Assertions.assertEquals("1115", res.get(127).getPhone());
}
private final List<PhoneRepository.FidsData> fidsDataWithEqualSinceDt = new ArrayList<>( private final List<PhoneRepository.FidsData> fidsDataWithEqualSinceDt = new ArrayList<>(
List.of( List.of(
new PhoneRepository.FidsData(123, "91111", LocalDate.of(2025, 9, 10)), new PhoneRepository.FidsData(123, "91111", LocalDate.of(2025, 9, 10)),
@ -57,6 +98,23 @@ public class PhoneService2Test {
) )
); );
private final List<PhoneRepository.FidsData> fidsDataWithEqualSinceDt2 = new ArrayList<>(
List.of(
new PhoneRepository.FidsData(125, "91112", LocalDate.of(2024, 10, 10)),
new PhoneRepository.FidsData(126, "91114", LocalDate.of(2024, 10, 11)),
new PhoneRepository.FidsData(127, "91115", LocalDate.of(2025, 9, 11)),
new PhoneRepository.FidsData(128, "91115", LocalDate.of(2025, 9, 10))
)
);
private final List<PhoneRepository.FidsData> fidsDataWithEqualSinceDt3 = new ArrayList<>(
List.of(
new PhoneRepository.FidsData(126, "91114", LocalDate.of(2024, 10, 11)),
new PhoneRepository.FidsData(127, "91115", LocalDate.of(2025, 9, 11)),
new PhoneRepository.FidsData(128, "91115", LocalDate.of(2025, 9, 10))
)
);
Comparator<PhoneRepository.FidsData> byDbOrder = Comparator<PhoneRepository.FidsData> byDbOrder =
Comparator.comparing(PhoneRepository.FidsData::getPhone, Comparator.nullsFirst(Comparator.naturalOrder())) // pn.number ASC Comparator.comparing(PhoneRepository.FidsData::getPhone, Comparator.nullsFirst(Comparator.naturalOrder())) // pn.number ASC
.thenComparing(PhoneRepository.FidsData::getFileSinceDate, Comparator.nullsLast(Comparator.reverseOrder())) // file_since_dt DESC .thenComparing(PhoneRepository.FidsData::getFileSinceDate, Comparator.nullsLast(Comparator.reverseOrder())) // file_since_dt DESC

View file

@ -46,6 +46,47 @@ public class PhoneServiceTest {
Assertions.assertEquals("1115", res.get(127).getPhone()); Assertions.assertEquals("1115", res.get(127).getPhone());
} }
@Test
public void defineFidByPhoneTest2() {
PhoneService phoneService = new PhoneService(phoneRepository);
fidsDataWithEqualSinceDt.sort(byDbOrder);
when(phoneRepository.findFidsLong(any())).thenReturn(fidsDataWithEqualSinceDt2);
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
Assertions.assertEquals(3, res.size());
Assertions.assertEquals("1112", res.get(125).getPhone());
Assertions.assertEquals("1114", res.get(126).getPhone());
Assertions.assertEquals("1115", res.get(127).getPhone());
}
@Test
public void defineFidByPhoneTest3() {
PhoneService phoneService = new PhoneService(phoneRepository);
fidsDataWithEqualSinceDt.sort(byDbOrder);
when(phoneRepository.findFidsLong(any())).thenReturn(fidsDataWithEqualSinceDt3);
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
Assertions.assertEquals(2, res.size());
Assertions.assertEquals("1114", res.get(126).getPhone());
Assertions.assertEquals("1115", res.get(127).getPhone());
}
private final List<PhoneRepository.FidsDataLong> fidsDataWithEqualSinceDt = new ArrayList<>( private final List<PhoneRepository.FidsDataLong> fidsDataWithEqualSinceDt = new ArrayList<>(
List.of( List.of(
new PhoneRepository.FidsDataLong(123, 91111L, LocalDate.of(2025, 9, 10)), new PhoneRepository.FidsDataLong(123, 91111L, LocalDate.of(2025, 9, 10)),
@ -57,6 +98,23 @@ public class PhoneServiceTest {
) )
); );
private final List<PhoneRepository.FidsDataLong> fidsDataWithEqualSinceDt2 = new ArrayList<>(
List.of(
new PhoneRepository.FidsDataLong(125, 91112L, LocalDate.of(2024, 10, 10)),
new PhoneRepository.FidsDataLong(126, 91114L, LocalDate.of(2024, 10, 11)),
new PhoneRepository.FidsDataLong(127, 91115L, LocalDate.of(2025, 9, 11)),
new PhoneRepository.FidsDataLong(128, 91115L, LocalDate.of(2025, 9, 10))
)
);
private final List<PhoneRepository.FidsDataLong> fidsDataWithEqualSinceDt3 = new ArrayList<>(
List.of(
new PhoneRepository.FidsDataLong(126, 91114L, LocalDate.of(2024, 10, 11)),
new PhoneRepository.FidsDataLong(127, 91115L, LocalDate.of(2025, 9, 11)),
new PhoneRepository.FidsDataLong(128, 91115L, LocalDate.of(2025, 9, 10))
)
);
Comparator<PhoneRepository.FidsDataLong> byDbOrder = Comparator<PhoneRepository.FidsDataLong> byDbOrder =
Comparator.comparing(PhoneRepository.FidsDataLong::getPhone, Comparator.nullsFirst(Comparator.naturalOrder())) // pn.number ASC Comparator.comparing(PhoneRepository.FidsDataLong::getPhone, Comparator.nullsFirst(Comparator.naturalOrder())) // pn.number ASC
.thenComparing(PhoneRepository.FidsDataLong::getFileSinceDate, Comparator.nullsLast(Comparator.reverseOrder())) // file_since_dt DESC .thenComparing(PhoneRepository.FidsDataLong::getFileSinceDate, Comparator.nullsLast(Comparator.reverseOrder())) // file_since_dt DESC