Merge branch 'feature/RED-10106' into 'master'

Resolve RED-10106 "Feature/"

Closes RED-10106

See merge request redactmanager/persistence-service!765
This commit is contained in:
Maverick Studer 2024-10-18 15:12:58 +02:00
commit 9203993d6e
10 changed files with 345 additions and 333 deletions

View File

@ -45,10 +45,10 @@ dependencies {
implementation("com.knecon.fforesight:llm-service-api:1.17.0") implementation("com.knecon.fforesight:llm-service-api:1.17.0")
api("com.knecon.fforesight:jobs-commons:0.10.0") api("com.knecon.fforesight:jobs-commons:0.10.0")
api("com.iqser.red.commons:storage-commons:2.50.0") api("com.iqser.red.commons:storage-commons:2.50.0")
api("com.knecon.fforesight:tenant-commons:0.30.0") { api("com.knecon.fforesight:tenant-commons:0.31.0") {
exclude(group = "com.iqser.red.commons", module = "storage-commons") exclude(group = "com.iqser.red.commons", module = "storage-commons")
} }
api("com.knecon.fforesight:database-tenant-commons:0.24.0") { api("com.knecon.fforesight:database-tenant-commons:0.28.0") {
exclude(group = "com.knecon.fforesight", module = "tenant-commons") exclude(group = "com.knecon.fforesight", module = "tenant-commons")
} }
api("com.knecon.fforesight:keycloak-commons:0.30.0") { api("com.knecon.fforesight:keycloak-commons:0.30.0") {

View File

@ -0,0 +1,198 @@
package com.iqser.red.service.persistence.management.v1.processor.configuration;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.ANALYSIS_FLAG_CALCULATION_REQUEST_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.ANALYSIS_FLAG_CALCULATION_REQUEST_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.AZURE_ENTITY_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.AZURE_ENTITY_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.AZURE_ENTITY_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.CHUNKING_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.CHUNKING_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.CHUNKING_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.CV_ANALYSIS_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.CV_ANALYSIS_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.CV_ANALYSIS_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.DOWNLOAD_COMPRESSION_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.DOWNLOAD_COMPRESSION_REQUEST_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.DOWNLOAD_COMPRESSION_REQUEST_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.DOWNLOAD_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.DOWNLOAD_REQUEST_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.DOWNLOAD_REQUEST_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.ENTITY_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.ENTITY_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.ENTITY_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.EXPORT_DOWNLOAD_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.EXPORT_DOWNLOAD_REQUEST_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.EXPORT_DOWNLOAD_REQUEST_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.IMAGE_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.IMAGE_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.IMAGE_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.LLM_NER_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.LLM_NER_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.LLM_NER_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.OCR_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.OCR_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.OCR_STATUS_UPDATE_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.OCR_STATUS_UPDATE_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.OCR_STATUS_UPDATE_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.PDFTRON_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.PDFTRON_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.PDFTRON_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.REDACTION_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.REDACTION_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.REDACTION_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.REPORT_RESPONSE_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.REPORT_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.REPORT_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.SEARCH_BULK_LOCAL_TERM_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.SEARCH_BULK_LOCAL_TERM_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.SEARCH_BULK_LOCAL_TERM_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.VISUAL_LAYOUT_PARSING_DLQ;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.VISUAL_LAYOUT_PARSING_RESPONSE_EXCHANGE;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.VISUAL_LAYOUT_PARSING_RESPONSE_QUEUE_PREFIX;
import static com.iqser.red.service.persistence.management.v1.processor.dataexchange.ExportDownloadMessageReceiver.EXPORT_DOWNLOAD_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.download.DownloadCompressionMessageReceiver.DOWNLOAD_COMPRESSION_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.download.DownloadMessageReceiver.DOWNLOAD_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.download.DownloadReportMessageReceiver.REPORT_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.download.RedactionResultMessageReceiver.PDFTRON_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.AnalysisFlagsCalculationMessageReceiver.ANALYSIS_FLAG_CALCULATION_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.AzureNerMessageReceiver.AZURE_ENTITY_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.ChunkingMessageReceiver.CHUNKING_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.CvAnalysisMessageReceiver.CV_ANALYSIS_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.ImageMessageReceiver.IMAGE_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.LayoutParsingFinishedMessageReceiver.LAYOUT_PARSING_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.NerMessageReceiver.ENTITY_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.NerMessageReceiver.LLM_ENTITY_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.OCRProcessingMessageReceiver.OCR_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.OCRProcessingMessageReceiver.OCR_STATUS_UPDATE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.RedactionAnalysisResponseReceiver.REDACTION_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.SearchTermOccurrencesResponseReceiver.SEARCH_BULK_LOCAL_TERM_RESPONSE_LISTENER;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.VisualLayoutParsingMessageReceiver.VISUAL_LAYOUT_PARSING_RESPONSE_LISTENER_ID;
import java.util.Map;
import java.util.Set;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames;
import com.knecon.fforesight.tenantcommons.model.TenantQueueConfiguration;
import com.knecon.fforesight.tenantcommons.model.TenantQueueProvider;
@Configuration
public class QueueProviderConfiguration {
@Bean
public TenantQueueProvider tenantQueueProvider() {
var queues = Set.of(TenantQueueConfiguration.builder()
.listenerId(DOWNLOAD_LISTENER_ID)
.exchangeName(DOWNLOAD_REQUEST_EXCHANGE)
.queuePrefix(DOWNLOAD_REQUEST_QUEUE_PREFIX)
.dlqName(DOWNLOAD_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(DOWNLOAD_COMPRESSION_LISTENER_ID)
.exchangeName(DOWNLOAD_COMPRESSION_REQUEST_EXCHANGE)
.queuePrefix(DOWNLOAD_COMPRESSION_REQUEST_QUEUE_PREFIX)
.dlqName(DOWNLOAD_COMPRESSION_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(EXPORT_DOWNLOAD_LISTENER_ID)
.exchangeName(EXPORT_DOWNLOAD_REQUEST_EXCHANGE)
.queuePrefix(EXPORT_DOWNLOAD_REQUEST_QUEUE_PREFIX)
.dlqName(EXPORT_DOWNLOAD_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(ANALYSIS_FLAG_CALCULATION_LISTENER_ID)
.exchangeName(ANALYSIS_FLAG_CALCULATION_REQUEST_EXCHANGE)
.queuePrefix(ANALYSIS_FLAG_CALCULATION_REQUEST_QUEUE_PREFIX)
.build(),
TenantQueueConfiguration.builder()
.listenerId(REDACTION_RESPONSE_LISTENER_ID)
.exchangeName(REDACTION_RESPONSE_EXCHANGE)
.queuePrefix(REDACTION_RESPONSE_QUEUE_PREFIX)
.dlqName(REDACTION_DLQ)
.arguments(Map.of("x-max-priority", 2))
.build(),
TenantQueueConfiguration.builder()
.listenerId(SEARCH_BULK_LOCAL_TERM_RESPONSE_LISTENER)
.exchangeName(SEARCH_BULK_LOCAL_TERM_RESPONSE_EXCHANGE)
.queuePrefix(SEARCH_BULK_LOCAL_TERM_RESPONSE_QUEUE_PREFIX)
.dlqName(SEARCH_BULK_LOCAL_TERM_DLQ)
.arguments(Map.of("x-max-priority", 2))
.build(),
TenantQueueConfiguration.builder()
.listenerId(PDFTRON_RESPONSE_LISTENER_ID)
.exchangeName(PDFTRON_RESPONSE_EXCHANGE)
.queuePrefix(PDFTRON_RESPONSE_QUEUE_PREFIX)
.dlqName(PDFTRON_DLQ)
.arguments(Map.of("x-max-priority", 2))
.build(),
TenantQueueConfiguration.builder()
.listenerId(REPORT_RESPONSE_LISTENER_ID)
.exchangeName(REPORT_RESPONSE_EXCHANGE)
.queuePrefix(REPORT_RESPONSE_QUEUE_PREFIX)
.dlqName(REPORT_RESPONSE_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(OCR_RESPONSE_LISTENER_ID)
.exchangeName(OCR_RESPONSE_EXCHANGE)
.queuePrefix(OCR_RESPONSE_QUEUE_PREFIX)
.build(),
TenantQueueConfiguration.builder()
.listenerId(OCR_STATUS_UPDATE_LISTENER_ID)
.exchangeName(OCR_STATUS_UPDATE_RESPONSE_EXCHANGE)
.queuePrefix(OCR_STATUS_UPDATE_RESPONSE_QUEUE_PREFIX)
.dlqName(OCR_STATUS_UPDATE_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(IMAGE_RESPONSE_LISTENER_ID)
.exchangeName(IMAGE_RESPONSE_EXCHANGE)
.queuePrefix(IMAGE_RESPONSE_QUEUE_PREFIX)
.dlqName(IMAGE_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(ENTITY_RESPONSE_LISTENER_ID)
.exchangeName(ENTITY_RESPONSE_EXCHANGE)
.queuePrefix(ENTITY_RESPONSE_QUEUE_PREFIX)
.dlqName(ENTITY_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(AZURE_ENTITY_RESPONSE_LISTENER_ID)
.exchangeName(AZURE_ENTITY_RESPONSE_EXCHANGE)
.queuePrefix(AZURE_ENTITY_RESPONSE_QUEUE_PREFIX)
.dlqName(AZURE_ENTITY_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(CHUNKING_RESPONSE_LISTENER_ID)
.exchangeName(CHUNKING_RESPONSE_EXCHANGE)
.queuePrefix(CHUNKING_RESPONSE_QUEUE_PREFIX)
.dlqName(CHUNKING_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(LLM_ENTITY_RESPONSE_LISTENER_ID)
.exchangeName(LLM_NER_RESPONSE_EXCHANGE)
.queuePrefix(LLM_NER_RESPONSE_QUEUE_PREFIX)
.dlqName(LLM_NER_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(CV_ANALYSIS_RESPONSE_LISTENER_ID)
.exchangeName(CV_ANALYSIS_RESPONSE_EXCHANGE)
.queuePrefix(CV_ANALYSIS_RESPONSE_QUEUE_PREFIX)
.dlqName(CV_ANALYSIS_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(VISUAL_LAYOUT_PARSING_RESPONSE_LISTENER_ID)
.exchangeName(VISUAL_LAYOUT_PARSING_RESPONSE_EXCHANGE)
.queuePrefix(VISUAL_LAYOUT_PARSING_RESPONSE_QUEUE_PREFIX)
.dlqName(VISUAL_LAYOUT_PARSING_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(LAYOUT_PARSING_RESPONSE_LISTENER_ID)
.exchangeName(LayoutParsingQueueNames.LAYOUT_PARSING_RESPONSE_EXCHANGE)
.queuePrefix(LayoutParsingQueueNames.LAYOUT_PARSING_RESPONSE_QUEUE_PREFIX)
.build());
return new TenantQueueProvider(queues);
}
}

View File

@ -1,10 +0,0 @@
package com.iqser.red.service.persistence.management.v1.processor.configuration;
import org.springframework.context.annotation.Configuration;
import com.knecon.fforesight.tenantcommons.queue.TenantMessagingConfiguration;
@Configuration
public class TenantMessagingConfigurationImpl extends TenantMessagingConfiguration {
}

View File

@ -37,10 +37,10 @@ import com.iqser.red.storage.commons.exception.StorageException;
import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist; import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist;
import com.iqser.red.storage.commons.service.StorageService; import com.iqser.red.storage.commons.service.StorageService;
import com.knecon.fforesight.databasetenantcommons.providers.TenantSyncService; import com.knecon.fforesight.databasetenantcommons.providers.TenantSyncService;
import com.knecon.fforesight.databasetenantcommons.providers.events.TenantSyncEvent;
import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames; import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames;
import com.knecon.fforesight.tenantcommons.TenantContext; import com.knecon.fforesight.tenantcommons.TenantContext;
import com.knecon.fforesight.tenantcommons.TenantProvider; import com.knecon.fforesight.tenantcommons.TenantProvider;
import com.knecon.fforesight.tenantcommons.model.TenantSyncEvent;
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest; import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
import lombok.AccessLevel; import lombok.AccessLevel;

View File

@ -1,188 +0,0 @@
package com.iqser.red.service.persistence.management.v1.processor.service.queue;
import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.*;
import static com.iqser.red.service.persistence.management.v1.processor.dataexchange.ExportDownloadMessageReceiver.EXPORT_DOWNLOAD_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.download.DownloadCompressionMessageReceiver.DOWNLOAD_COMPRESSION_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.download.DownloadMessageReceiver.DOWNLOAD_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.download.DownloadReportMessageReceiver.REPORT_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.download.RedactionResultMessageReceiver.PDFTRON_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.AnalysisFlagsCalculationMessageReceiver.ANALYSIS_FLAG_CALCULATION_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.AzureNerMessageReceiver.AZURE_ENTITY_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.ChunkingMessageReceiver.CHUNKING_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.CvAnalysisMessageReceiver.CV_ANALYSIS_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.ImageMessageReceiver.IMAGE_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.LayoutParsingFinishedMessageReceiver.LAYOUT_PARSING_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.NerMessageReceiver.ENTITY_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.NerMessageReceiver.LLM_ENTITY_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.OCRProcessingMessageReceiver.OCR_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.OCRProcessingMessageReceiver.OCR_STATUS_UPDATE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.RedactionAnalysisResponseReceiver.REDACTION_RESPONSE_LISTENER_ID;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.SearchTermOccurrencesResponseReceiver.SEARCH_BULK_LOCAL_TERM_RESPONSE_LISTENER;
import static com.iqser.red.service.persistence.management.v1.processor.service.queue.VisualLayoutParsingMessageReceiver.VISUAL_LAYOUT_PARSING_RESPONSE_LISTENER_ID;
import java.util.Map;
import java.util.Set;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames;
import com.knecon.fforesight.tenantcommons.TenantProvider;
import com.knecon.fforesight.tenantcommons.model.TenantCreatedEvent;
import com.knecon.fforesight.tenantcommons.model.TenantQueueConfiguration;
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
import com.knecon.fforesight.tenantcommons.queue.RabbitQueueFromExchangeService;
import com.knecon.fforesight.tenantcommons.queue.TenantExchangeMessageReceiver;
@Service
public class TenantExchangeMessageReceiverImpl extends TenantExchangeMessageReceiver {
public TenantExchangeMessageReceiverImpl(RabbitQueueFromExchangeService rabbitQueueService, TenantProvider tenantProvider) {
super(rabbitQueueService, tenantProvider);
}
@Override
protected Set<TenantQueueConfiguration> getTenantQueueConfigs() {
return Set.of(TenantQueueConfiguration.builder()
.listenerId(DOWNLOAD_LISTENER_ID)
.exchangeName(DOWNLOAD_REQUEST_EXCHANGE)
.queuePrefix(DOWNLOAD_REQUEST_QUEUE_PREFIX)
.dlqName(DOWNLOAD_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(DOWNLOAD_COMPRESSION_LISTENER_ID)
.exchangeName(DOWNLOAD_COMPRESSION_REQUEST_EXCHANGE)
.queuePrefix(DOWNLOAD_COMPRESSION_REQUEST_QUEUE_PREFIX)
.dlqName(DOWNLOAD_COMPRESSION_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(EXPORT_DOWNLOAD_LISTENER_ID)
.exchangeName(EXPORT_DOWNLOAD_REQUEST_EXCHANGE)
.queuePrefix(EXPORT_DOWNLOAD_REQUEST_QUEUE_PREFIX)
.dlqName(EXPORT_DOWNLOAD_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(ANALYSIS_FLAG_CALCULATION_LISTENER_ID)
.exchangeName(ANALYSIS_FLAG_CALCULATION_REQUEST_EXCHANGE)
.queuePrefix(ANALYSIS_FLAG_CALCULATION_REQUEST_QUEUE_PREFIX)
.build(),
TenantQueueConfiguration.builder()
.listenerId(REDACTION_RESPONSE_LISTENER_ID)
.exchangeName(REDACTION_RESPONSE_EXCHANGE)
.queuePrefix(REDACTION_RESPONSE_QUEUE_PREFIX)
.dlqName(REDACTION_DLQ)
.arguments(Map.of("x-max-priority", 2))
.build(),
TenantQueueConfiguration.builder()
.listenerId(SEARCH_BULK_LOCAL_TERM_RESPONSE_LISTENER)
.exchangeName(SEARCH_BULK_LOCAL_TERM_RESPONSE_EXCHANGE)
.queuePrefix(SEARCH_BULK_LOCAL_TERM_RESPONSE_QUEUE_PREFIX)
.dlqName(SEARCH_BULK_LOCAL_TERM_DLQ)
.arguments(Map.of("x-max-priority", 2))
.build(),
TenantQueueConfiguration.builder()
.listenerId(PDFTRON_RESPONSE_LISTENER_ID)
.exchangeName(PDFTRON_RESPONSE_EXCHANGE)
.queuePrefix(PDFTRON_RESPONSE_QUEUE_PREFIX)
.dlqName(PDFTRON_DLQ)
.arguments(Map.of("x-max-priority", 2))
.build(),
TenantQueueConfiguration.builder()
.listenerId(REPORT_RESPONSE_LISTENER_ID)
.exchangeName(REPORT_RESPONSE_EXCHANGE)
.queuePrefix(REPORT_RESPONSE_QUEUE_PREFIX)
.dlqName(REPORT_RESPONSE_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(OCR_RESPONSE_LISTENER_ID)
.exchangeName(OCR_RESPONSE_EXCHANGE)
.queuePrefix(OCR_RESPONSE_QUEUE_PREFIX)
.build(),
TenantQueueConfiguration.builder()
.listenerId(OCR_STATUS_UPDATE_LISTENER_ID)
.exchangeName(OCR_STATUS_UPDATE_RESPONSE_EXCHANGE)
.queuePrefix(OCR_STATUS_UPDATE_RESPONSE_QUEUE_PREFIX)
.dlqName(OCR_STATUS_UPDATE_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(IMAGE_RESPONSE_LISTENER_ID)
.exchangeName(IMAGE_RESPONSE_EXCHANGE)
.queuePrefix(IMAGE_RESPONSE_QUEUE_PREFIX)
.dlqName(IMAGE_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(ENTITY_RESPONSE_LISTENER_ID)
.exchangeName(ENTITY_RESPONSE_EXCHANGE)
.queuePrefix(ENTITY_RESPONSE_QUEUE_PREFIX)
.dlqName(ENTITY_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(AZURE_ENTITY_RESPONSE_LISTENER_ID)
.exchangeName(AZURE_ENTITY_RESPONSE_EXCHANGE)
.queuePrefix(AZURE_ENTITY_RESPONSE_QUEUE_PREFIX)
.dlqName(AZURE_ENTITY_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(CHUNKING_RESPONSE_LISTENER_ID)
.exchangeName(CHUNKING_RESPONSE_EXCHANGE)
.queuePrefix(CHUNKING_RESPONSE_QUEUE_PREFIX)
.dlqName(CHUNKING_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(LLM_ENTITY_RESPONSE_LISTENER_ID)
.exchangeName(LLM_NER_RESPONSE_EXCHANGE)
.queuePrefix(LLM_NER_RESPONSE_QUEUE_PREFIX)
.dlqName(LLM_NER_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(CV_ANALYSIS_RESPONSE_LISTENER_ID)
.exchangeName(CV_ANALYSIS_RESPONSE_EXCHANGE)
.queuePrefix(CV_ANALYSIS_RESPONSE_QUEUE_PREFIX)
.dlqName(CV_ANALYSIS_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(VISUAL_LAYOUT_PARSING_RESPONSE_LISTENER_ID)
.exchangeName(VISUAL_LAYOUT_PARSING_RESPONSE_EXCHANGE)
.queuePrefix(VISUAL_LAYOUT_PARSING_RESPONSE_QUEUE_PREFIX)
.dlqName(VISUAL_LAYOUT_PARSING_DLQ)
.build(),
TenantQueueConfiguration.builder()
.listenerId(LAYOUT_PARSING_RESPONSE_LISTENER_ID)
.exchangeName(LayoutParsingQueueNames.LAYOUT_PARSING_RESPONSE_EXCHANGE)
.queuePrefix(LayoutParsingQueueNames.LAYOUT_PARSING_RESPONSE_QUEUE_PREFIX)
.build());
}
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady() {
System.out.println("application ready invoked");
super.initializeQueues();
}
@RabbitHandler
@RabbitListener(queues = "#{tenantMessagingConfigurationImpl.getTenantCreatedQueueName()}")
public void reactToTenantCreation(TenantCreatedEvent tenantCreatedEvent) {
super.reactToTenantCreation(tenantCreatedEvent);
}
@RabbitHandler
@RabbitListener(queues = "#{tenantMessagingConfigurationImpl.getTenantDeletedQueueName()}")
public void reactToTenantDeletion(TenantResponse tenantResponse) {
super.reactToTenantDeletion(tenantResponse);
}
}

View File

@ -5,7 +5,7 @@
<include file="/mongo/changelog/tenant/1-initial-database.changelog.xml"/> <include file="/mongo/changelog/tenant/1-initial-database.changelog.xml"/>
<include file="/mongo/changelog/tenant/2-create-indices-for-entries.xml"/> <include file="/mongo/changelog/tenant/2-create-indices-for-entries.xml"/>
<include file="/mongo/changelog/tenant/3-add-page-paragraph-idx.xml"/> <include file="/mongo/changelog/tenant/3-add-page-paragraph-idx.xml"/>
<!--<include file="/mongo/changelog/tenant/4-create-component-entities.xml"/>--> <include file="/mongo/changelog/tenant/4-create-component-entities.xml"/>
<include file="/mongo/changelog/tenant/5-add-duplicate-text-ranges.xml"/> <include file="/mongo/changelog/tenant/5-add-duplicate-text-ranges.xml"/>
<include file="/mongo/changelog/tenant/6-rename-component-collections.xml"/> <include file="/mongo/changelog/tenant/6-rename-component-collections.xml"/>
<!-- THIS FILE IS NOT RUN IN THE CURRENT CONFIGURATION, PLEASE ADD CHANGES TO redaction-service --> <!-- THIS FILE IS NOT RUN IN THE CURRENT CONFIGURATION, PLEASE ADD CHANGES TO redaction-service -->

View File

@ -26,7 +26,6 @@ lifecycle:
spring: spring:
main: main:
allow-bean-definition-overriding: true
allow-circular-references: true allow-circular-references: true
jpa: jpa:
open-in-view: true open-in-view: true

View File

@ -3,6 +3,8 @@ package com.iqser.red.service.peristence.v1.server.integration.utils;
import static com.iqser.red.service.peristence.v1.server.integration.utils.MongoDBTestContainer.MONGO_DATABASE; import static com.iqser.red.service.peristence.v1.server.integration.utils.MongoDBTestContainer.MONGO_DATABASE;
import static com.iqser.red.service.peristence.v1.server.integration.utils.MongoDBTestContainer.MONGO_PASSWORD; import static com.iqser.red.service.peristence.v1.server.integration.utils.MongoDBTestContainer.MONGO_PASSWORD;
import static com.iqser.red.service.peristence.v1.server.integration.utils.MongoDBTestContainer.MONGO_USERNAME; import static com.iqser.red.service.peristence.v1.server.integration.utils.MongoDBTestContainer.MONGO_USERNAME;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.util.ArrayList; import java.util.ArrayList;
@ -13,17 +15,9 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.assertj.core.util.Lists;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonString;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.quartz.Scheduler;
import org.springframework.amqp.rabbit.core.RabbitAdmin; import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.MessageListenerContainer;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry; import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -108,8 +102,8 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService; import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.ApplicationConfig; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.ApplicationConfig;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.ComponentLogEntryDocumentRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.ComponentLogDocumentRepository; import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.ComponentLogDocumentRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.ComponentLogEntryDocumentRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.EntityLogDocumentRepository; import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.EntityLogDocumentRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.EntityLogEntryDocumentRepository; import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.EntityLogEntryDocumentRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.ComponentLogMongoService; import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.ComponentLogMongoService;
@ -117,12 +111,10 @@ import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.Ent
import com.iqser.red.service.redaction.v1.model.DroolsValidation; import com.iqser.red.service.redaction.v1.model.DroolsValidation;
import com.iqser.red.storage.commons.service.StorageService; import com.iqser.red.storage.commons.service.StorageService;
import com.iqser.red.storage.commons.utils.FileSystemBackedStorageService; import com.iqser.red.storage.commons.utils.FileSystemBackedStorageService;
import com.knecon.fforesight.databasetenantcommons.providers.TenantCreatedListener; import com.knecon.fforesight.databasetenantcommons.providers.TenantCreatedDatabaseEventHandler;
import com.knecon.fforesight.databasetenantcommons.providers.events.TenantCreatedEvent;
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
import com.knecon.fforesight.keycloakcommons.security.TenantAuthenticationManagerResolver; import com.knecon.fforesight.keycloakcommons.security.TenantAuthenticationManagerResolver;
import com.knecon.fforesight.mongo.database.commons.liquibase.MongoTenantCreatedEvent; import com.knecon.fforesight.mongo.database.commons.liquibase.TenantCreatedMongoEventHandler;
import com.knecon.fforesight.mongo.database.commons.liquibase.MongoTenantCreatedListener;
import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService; import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService;
import com.knecon.fforesight.tenantcommons.TenantContext; import com.knecon.fforesight.tenantcommons.TenantContext;
import com.knecon.fforesight.tenantcommons.TenantsClient; import com.knecon.fforesight.tenantcommons.TenantsClient;
@ -131,21 +123,31 @@ import com.knecon.fforesight.tenantcommons.model.DatabaseConnection;
import com.knecon.fforesight.tenantcommons.model.MongoDBConnection; import com.knecon.fforesight.tenantcommons.model.MongoDBConnection;
import com.knecon.fforesight.tenantcommons.model.S3StorageConnection; import com.knecon.fforesight.tenantcommons.model.S3StorageConnection;
import com.knecon.fforesight.tenantcommons.model.SearchConnection; import com.knecon.fforesight.tenantcommons.model.SearchConnection;
import com.knecon.fforesight.tenantcommons.model.TenantCreatedEvent;
import com.knecon.fforesight.tenantcommons.model.TenantResponse; import com.knecon.fforesight.tenantcommons.model.TenantResponse;
import com.mongodb.MongoCommandException; import com.mongodb.MongoCommandException;
import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients; import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase; import com.mongodb.client.MongoDatabase;
import io.micrometer.prometheus.PrometheusMeterRegistry; import io.micrometer.prometheus.PrometheusMeterRegistry;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonString;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.quartz.Scheduler;
@Slf4j @Slf4j
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@EnableFeignClients(basePackageClasses = FileClient.class) @EnableFeignClients(basePackageClasses = FileClient.class)
@Import(AbstractPersistenceServerServiceTest.TestConfiguration.class) @Import(AbstractPersistenceServerServiceTest.TestConfiguration.class)
@ContextConfiguration(initializers = {AbstractPersistenceServerServiceTest.Initializer.class}) @ContextConfiguration(initializers = {AbstractPersistenceServerServiceTest.Initializer.class})
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = "spring-hibernate-query-utils.n-plus-one-queries-detection.error-level=INFO") @SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
properties = "spring-hibernate-query-utils.n-plus-one-queries-detection.error-level=INFO")
public abstract class AbstractPersistenceServerServiceTest { public abstract class AbstractPersistenceServerServiceTest {
public static final String TENANT_1 = "redaction"; public static final String TENANT_1 = "redaction";
@ -245,8 +247,6 @@ public abstract class AbstractPersistenceServerServiceTest {
protected PrometheusMeterRegistry prometheusMeterRegistry; protected PrometheusMeterRegistry prometheusMeterRegistry;
@MockBean @MockBean
private RabbitAdmin rabbitAdmin; private RabbitAdmin rabbitAdmin;
@MockBean
private RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry;
@Autowired @Autowired
private DossierStatusRepository dossierStatusRepository; private DossierStatusRepository dossierStatusRepository;
@Autowired @Autowired
@ -262,9 +262,9 @@ public abstract class AbstractPersistenceServerServiceTest {
@Autowired @Autowired
protected EncryptionDecryptionService encryptionDecryptionService; protected EncryptionDecryptionService encryptionDecryptionService;
@Autowired @Autowired
protected TenantCreatedListener tenantCreatedListener; protected TenantCreatedDatabaseEventHandler tenantCreatedDatabaseEventHandler;
@Autowired @Autowired
protected MongoTenantCreatedListener mongoTenantCreatedListener; protected TenantCreatedMongoEventHandler tenantCreatedMongoEventHandler;
@Autowired @Autowired
protected MongoTestConfig mongoTestConfig; protected MongoTestConfig mongoTestConfig;
@MockBean @MockBean
@ -359,9 +359,10 @@ public abstract class AbstractPersistenceServerServiceTest {
when(usersClient.getAllUsers(true)).thenReturn(allUsers); when(usersClient.getAllUsers(true)).thenReturn(allUsers);
// doNothing().when(pdfTronRedactionClient).testDigitalCurrentSignature(Mockito.any()); // doNothing().when(pdfTronRedactionClient).testDigitalCurrentSignature(Mockito.any());
when(rabbitAdmin.getQueueInfo(Mockito.any())).thenReturn(null); when(rabbitAdmin.getQueueInfo(any())).thenReturn(null);
when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(new EntityLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0));
when(entityLogService.getEntityLog(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyBoolean())).thenReturn(new EntityLog(1, when(entityLogService.getEntityLog(any(), any())).thenReturn(new EntityLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0));
when(entityLogService.getEntityLog(any(), any(), any(), Mockito.anyBoolean())).thenReturn(new EntityLog(1,
1, 1,
Lists.newArrayList(), Lists.newArrayList(),
null, null,
@ -369,7 +370,7 @@ public abstract class AbstractPersistenceServerServiceTest {
0, 0,
0, 0,
0)); 0));
when(redactionClient.testRules(Mockito.any())).thenReturn(DroolsValidation.builder() when(redactionClient.testRules(any())).thenReturn(DroolsValidation.builder()
.syntaxErrorMessages(Collections.emptyList()) .syntaxErrorMessages(Collections.emptyList())
.deprecatedWarnings(Collections.emptyList()) .deprecatedWarnings(Collections.emptyList())
.build()); .build());
@ -474,10 +475,10 @@ public abstract class AbstractPersistenceServerServiceTest {
when(tenantsClient.getTenants()).thenReturn(List.of(redactionTenant, redactionTenant2)); when(tenantsClient.getTenants()).thenReturn(List.of(redactionTenant, redactionTenant2));
try { try {
tenantCreatedListener.createTenant(new TenantCreatedEvent(TENANT_1)); tenantCreatedDatabaseEventHandler.handle(new TenantCreatedEvent(TENANT_1));
tenantCreatedListener.createTenant(new TenantCreatedEvent(TENANT_2)); tenantCreatedDatabaseEventHandler.handle(new TenantCreatedEvent(TENANT_2));
mongoTenantCreatedListener.createTenant(new MongoTenantCreatedEvent(TENANT_1)); tenantCreatedMongoEventHandler.handle(new TenantCreatedEvent(TENANT_1));
mongoTenantCreatedListener.createTenant(new MongoTenantCreatedEvent(TENANT_2)); tenantCreatedMongoEventHandler.handle(new TenantCreatedEvent(TENANT_2));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -641,6 +642,15 @@ public abstract class AbstractPersistenceServerServiceTest {
@ComponentScan("com.iqser.red.service.persistence") @ComponentScan("com.iqser.red.service.persistence")
public static class TestConfiguration { public static class TestConfiguration {
@Bean
public RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry() {
var mock = mock(RabbitListenerEndpointRegistry.class);
when(mock.getListenerContainer(any())).thenReturn(mock(MessageListenerContainer.class));
return mock;
}
@Bean @Bean
public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) { public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {

View File

@ -131,3 +131,5 @@ fforesight:
name: 'users-exchange' name: 'users-exchange'
keycloak: keycloak:
enabled: false enabled: false
logging.level.liquibase: DEBUG

View File

@ -9,9 +9,10 @@ dependencies {
api(project(":persistence-service-shared-api-v1")) api(project(":persistence-service-shared-api-v1"))
api("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2") api("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2")
api("com.google.guava:guava:31.1-jre") api("com.google.guava:guava:31.1-jre")
api("com.knecon.fforesight:mongo-database-commons:0.13.0+RED9348.0") { api("com.knecon.fforesight:mongo-database-commons:0.16.0") {
exclude(group = "com.iqser.red.commons", module = "storage-commons") exclude(group = "com.knecon.fforesight", module = "tenant-commons")
} }
api("com.knecon.fforesight:tenant-commons:0.31.0")
api("org.springframework.boot:spring-boot-starter-data-mongodb:${springBootStarterVersion}") api("org.springframework.boot:spring-boot-starter-data-mongodb:${springBootStarterVersion}")
api("org.springframework.boot:spring-boot-starter-validation:3.1.3") api("org.springframework.boot:spring-boot-starter-validation:3.1.3")
testImplementation("com.iqser.red.commons:test-commons:2.1.0") testImplementation("com.iqser.red.commons:test-commons:2.1.0")