diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/pom.xml b/redaction-report-service-v1/redaction-report-service-server-v1/pom.xml index 2b2ab4f..4522db3 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/pom.xml +++ b/redaction-report-service-v1/redaction-report-service-server-v1/pom.xml @@ -12,7 +12,16 @@ redaction-report-service-server-v1 + + 0.6.0 + + + + com.knecon.fforesight + tenant-commons + ${tennat-commons.version} + com.iqser.red.service redaction-report-service-api-v1 diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/Application.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/Application.java index c67d794..a108c4d 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/Application.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/Application.java @@ -2,6 +2,7 @@ package com.iqser.red.service.redaction.report.v1.server; import org.springframework.boot.SpringApplication; import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -12,18 +13,17 @@ import org.springframework.scheduling.annotation.EnableAsync; import com.iqser.red.service.redaction.report.v1.server.client.DossierClient; import com.iqser.red.service.redaction.report.v1.server.configuration.MessagingConfiguration; -import com.iqser.red.service.redaction.report.v1.server.multitenancy.AsyncConfig; -import com.iqser.red.service.redaction.report.v1.server.multitenancy.MultiTenancyMessagingConfiguration; -import com.iqser.red.service.redaction.report.v1.server.multitenancy.MultiTenancyWebConfiguration; import com.iqser.red.service.redaction.report.v1.server.settings.ReportTemplateSettings; import com.iqser.red.storage.commons.StorageAutoConfiguration; +import com.knecon.fforesight.tenantcommons.MultiTenancyAutoConfiguration; import io.micrometer.core.aop.TimedAspect; import io.micrometer.core.instrument.MeterRegistry; @EnableAsync +@ImportAutoConfiguration({MultiTenancyAutoConfiguration.class}) @SpringBootApplication(exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class}) -@Import({MultiTenancyWebConfiguration.class, AsyncConfig.class, MessagingConfiguration.class, MultiTenancyMessagingConfiguration.class, StorageAutoConfiguration.class}) +@Import({MessagingConfiguration.class, StorageAutoConfiguration.class}) @EnableFeignClients(basePackageClasses = {DossierClient.class}) @EnableConfigurationProperties(ReportTemplateSettings.class) public class Application { diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/TenantsClient.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/TenantsClient.java deleted file mode 100644 index af2d6b0..0000000 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/TenantsClient.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.iqser.red.service.redaction.report.v1.server.client; - -import org.springframework.cloud.openfeign.FeignClient; - -import com.iqser.red.service.persistence.service.v1.api.internal.resources.TenantsResource; - -@FeignClient(name = "TenantsResource", url = "${persistence-service.url}") -public interface TenantsClient extends TenantsResource { - -} diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/ControllerAdvice.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/ControllerAdvice.java index d350ae3..6b18489 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/ControllerAdvice.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/ControllerAdvice.java @@ -1,15 +1,17 @@ package com.iqser.red.service.redaction.report.v1.server.controller; -import com.amazonaws.services.kms.model.NotFoundException; -import com.iqser.red.commons.spring.ErrorMessage; -import lombok.extern.slf4j.Slf4j; +import java.time.OffsetDateTime; + import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; -import java.time.OffsetDateTime; +import com.amazonaws.services.kms.model.NotFoundException; +import com.iqser.red.commons.spring.ErrorMessage; + +import lombok.extern.slf4j.Slf4j; @Slf4j @RestControllerAdvice @@ -17,6 +19,7 @@ public class ControllerAdvice { /* error handling */ + @ResponseBody @ResponseStatus(value = HttpStatus.NOT_FOUND) @ExceptionHandler(value = NotFoundException.class) @@ -25,4 +28,5 @@ public class ControllerAdvice { log.error(e.getMessage(), e); return new ErrorMessage(OffsetDateTime.now(), e.getMessage()); } + } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/RSSController.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/RSSController.java index f130001..defcae3 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/RSSController.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/RSSController.java @@ -1,7 +1,6 @@ package com.iqser.red.service.redaction.report.v1.server.controller; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -32,11 +31,11 @@ public class RSSController implements RSSResource { var detailed = rSSService.getRSS(dossierId, fileId); List fileResponses = new ArrayList<>(); - for (DetailedRSSFileResponse detailedRSSFileResponse : detailed.getFiles()){ + for (DetailedRSSFileResponse detailedRSSFileResponse : detailed.getFiles()) { String fileName = detailedRSSFileResponse.getFilename(); Map result = new LinkedHashMap<>(); - for(Map.Entry detailedRss : detailedRSSFileResponse.getResult().entrySet()){ - if(detailedRss.getValue().getValue() != null){ + for (Map.Entry detailedRss : detailedRSSFileResponse.getResult().entrySet()) { + if (detailedRss.getValue().getValue() != null) { result.put(detailedRss.getKey(), detailedRss.getValue().getValue()); } else { result.put(detailedRss.getKey(), detailedRss.getValue().getOriginalValue()); @@ -50,7 +49,7 @@ public class RSSController implements RSSResource { } - public DetailedRSSResponse getDetailedRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId){ + public DetailedRSSResponse getDetailedRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId) { return rSSService.getRSS(dossierId, fileId); } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/AsyncConfig.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/AsyncConfig.java deleted file mode 100644 index e111103..0000000 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/AsyncConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.iqser.red.service.redaction.report.v1.server.multitenancy; - -import java.util.concurrent.Executor; - -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.AsyncConfigurerSupport; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; - -@Configuration -public class AsyncConfig extends AsyncConfigurerSupport { - - @Override - public Executor getAsyncExecutor() { - - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - - executor.setCorePoolSize(7); - executor.setMaxPoolSize(42); - executor.setQueueCapacity(11); - executor.setThreadNamePrefix("TenantAwareTaskExecutor-"); - executor.setTaskDecorator(new TenantAwareTaskDecorator()); - executor.initialize(); - - return executor; - } - -} \ No newline at end of file diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/EncryptionDecryptionService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/EncryptionDecryptionService.java deleted file mode 100644 index 57e6c02..0000000 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/EncryptionDecryptionService.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.iqser.red.service.redaction.report.v1.server.multitenancy; - -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.security.SecureRandom; -import java.security.spec.KeySpec; -import java.util.Base64; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import jakarta.annotation.PostConstruct; -import lombok.SneakyThrows; - -@Service -public class EncryptionDecryptionService { - - @Value("${redaction-report-service.crypto.key:redaction}") - private String key; - - private SecretKey secretKey; - private byte[] iv; - - - @SneakyThrows - @PostConstruct - protected void postConstruct() { - - SecureRandom secureRandom = new SecureRandom(); - iv = new byte[12]; - secureRandom.nextBytes(iv); - secretKey = generateSecretKey(key, iv); - } - - - @SneakyThrows - public String encrypt(String strToEncrypt) { - - return Base64.getEncoder().encodeToString(encrypt(strToEncrypt.getBytes())); - } - - - @SneakyThrows - public String decrypt(String strToDecrypt) { - - byte[] bytes = Base64.getDecoder().decode(strToDecrypt); - return new String(decrypt(bytes), StandardCharsets.UTF_8); - } - - - @SneakyThrows - public byte[] encrypt(byte[] data) { - - Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); - GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); - cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec); - byte[] encryptedData = cipher.doFinal(data); - ByteBuffer byteBuffer = ByteBuffer.allocate(4 + iv.length + encryptedData.length); - byteBuffer.putInt(iv.length); - byteBuffer.put(iv); - byteBuffer.put(encryptedData); - return byteBuffer.array(); - } - - - @SneakyThrows - public byte[] decrypt(byte[] encryptedData) { - - ByteBuffer byteBuffer = ByteBuffer.wrap(encryptedData); - int noonceSize = byteBuffer.getInt(); - if (noonceSize < 12 || noonceSize >= 16) { - throw new IllegalArgumentException("Nonce size is incorrect. Make sure that the incoming data is an AES encrypted file."); - } - byte[] iv = new byte[noonceSize]; - byteBuffer.get(iv); - - SecretKey secretKey = generateSecretKey(key, iv); - - byte[] cipherBytes = new byte[byteBuffer.remaining()]; - byteBuffer.get(cipherBytes); - - Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); - GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); - cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec); - return cipher.doFinal(cipherBytes); - } - - - @SneakyThrows - public SecretKey generateSecretKey(String password, byte[] iv) { - - KeySpec spec = new PBEKeySpec(password.toCharArray(), iv, 65536, 128); // AES-128 - SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); - byte[] key = secretKeyFactory.generateSecret(spec).getEncoded(); - return new SecretKeySpec(key, "AES"); - } - -} diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/ForwardTenantInterceptor.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/ForwardTenantInterceptor.java deleted file mode 100644 index d92d43a..0000000 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/ForwardTenantInterceptor.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.iqser.red.service.redaction.report.v1.server.multitenancy; - -import org.springframework.stereotype.Component; - -import feign.RequestInterceptor; -import feign.RequestTemplate; - -@Component -public class ForwardTenantInterceptor implements RequestInterceptor { - - public static final String TENANT_HEADER_NAME = "X-TENANT-ID"; - - @Override - public void apply(RequestTemplate template) { - template.header(TENANT_HEADER_NAME, TenantContext.getTenantId()); - } -} \ No newline at end of file diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/MultiTenancyMessagingConfiguration.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/MultiTenancyMessagingConfiguration.java deleted file mode 100644 index 8520df3..0000000 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/MultiTenancyMessagingConfiguration.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.iqser.red.service.redaction.report.v1.server.multitenancy; - -import static com.iqser.red.service.redaction.report.v1.server.multitenancy.ForwardTenantInterceptor.TENANT_HEADER_NAME; - -import org.springframework.amqp.rabbit.config.AbstractRabbitListenerContainerFactory; -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class MultiTenancyMessagingConfiguration { - - @Bean - public static BeanPostProcessor multitenancyBeanPostProcessor() { - - return new BeanPostProcessor() { - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - - if (bean instanceof RabbitTemplate) { - - ((RabbitTemplate) bean).setBeforePublishPostProcessors(m -> { - m.getMessageProperties().setHeader(TENANT_HEADER_NAME, TenantContext.getTenantId()); - return m; - }); - - } else if (bean instanceof AbstractRabbitListenerContainerFactory) { - - ((AbstractRabbitListenerContainerFactory) bean).setAfterReceivePostProcessors(m -> { - String tenant = m.getMessageProperties().getHeader(TENANT_HEADER_NAME); - - if (tenant != null) { - TenantContext.setTenantId(tenant); - } else { - throw new RuntimeException("No Tenant is set queue message"); - } - return m; - }); - } - return bean; - } - }; - } - -} diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/MultiTenancyWebConfiguration.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/MultiTenancyWebConfiguration.java deleted file mode 100644 index 4798891..0000000 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/MultiTenancyWebConfiguration.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.iqser.red.service.redaction.report.v1.server.multitenancy; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; - -import com.iqser.red.commons.spring.DefaultWebMvcConfiguration; - -@Configuration -public class MultiTenancyWebConfiguration extends DefaultWebMvcConfiguration { - - private final TenantInterceptor tenantInterceptor; - - - @Autowired - public MultiTenancyWebConfiguration(TenantInterceptor tenantInterceptor) { - - this.tenantInterceptor = tenantInterceptor; - } - - - @Override - public void addInterceptors(InterceptorRegistry registry) { - - registry.addWebRequestInterceptor(tenantInterceptor); - } - -} \ No newline at end of file diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/StorageConnectionProviderImpl.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/StorageConnectionProviderImpl.java deleted file mode 100644 index 5fcb449..0000000 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/StorageConnectionProviderImpl.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.iqser.red.service.redaction.report.v1.server.multitenancy; - -import org.springframework.stereotype.Service; - -import com.iqser.red.service.redaction.report.v1.server.client.TenantsClient; -import com.iqser.red.storage.commons.model.AzureStorageConnection; -import com.iqser.red.storage.commons.model.S3StorageConnection; -import com.iqser.red.storage.commons.service.StorageConnectionProvider; - -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class StorageConnectionProviderImpl implements StorageConnectionProvider { - - private final TenantsClient tenantsClient; - private final EncryptionDecryptionService encryptionDecryptionService; - - - @Override - public AzureStorageConnection getAzureStorageConnection(String tenantId) { - - var tenant = tenantsClient.getTenant(tenantId); - return AzureStorageConnection.builder() - .connectionString(encryptionDecryptionService.decrypt(tenant.getAzureStorageConnection().getConnectionString())) - .containerName(tenant.getAzureStorageConnection().getContainerName()) - .build(); - } - - - @Override - public S3StorageConnection getS3StorageConnection(String tenantId) { - - var tenant = tenantsClient.getTenant(tenantId); - return S3StorageConnection.builder() - .key(tenant.getS3StorageConnection().getKey()) - .secret(encryptionDecryptionService.decrypt(tenant.getS3StorageConnection().getSecret())) - .signerType(tenant.getS3StorageConnection().getSignerType()) - .bucketName(tenant.getS3StorageConnection().getBucketName()) - .region(tenant.getS3StorageConnection().getRegion()) - .endpoint(tenant.getS3StorageConnection().getEndpoint()) - .build(); - } - -} diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/TenantAwareTaskDecorator.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/TenantAwareTaskDecorator.java deleted file mode 100644 index 5258b61..0000000 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/TenantAwareTaskDecorator.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.iqser.red.service.redaction.report.v1.server.multitenancy; - -import org.springframework.core.task.TaskDecorator; -import org.springframework.lang.NonNull; - -public class TenantAwareTaskDecorator implements TaskDecorator { - - @Override - @NonNull - public Runnable decorate(@NonNull Runnable runnable) { - - String tenantId = TenantContext.getTenantId(); - return () -> { - try { - TenantContext.setTenantId(tenantId); - runnable.run(); - } finally { - TenantContext.setTenantId(null); - } - }; - } - -} \ No newline at end of file diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/TenantContext.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/TenantContext.java deleted file mode 100644 index 9f35451..0000000 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/TenantContext.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.iqser.red.service.redaction.report.v1.server.multitenancy; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public final class TenantContext { - - private static InheritableThreadLocal currentTenant = new InheritableThreadLocal<>(); - - - public static void setTenantId(String tenantId) { - - log.debug("Setting tenantId to " + tenantId); - currentTenant.set(tenantId); - } - - - public static String getTenantId() { - - return currentTenant.get(); - } - - - public static void clear() { - - currentTenant.remove(); - } - -} \ No newline at end of file diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/TenantInterceptor.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/TenantInterceptor.java deleted file mode 100644 index 1870cc0..0000000 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/multitenancy/TenantInterceptor.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.iqser.red.service.redaction.report.v1.server.multitenancy; - -import org.springframework.stereotype.Component; -import org.springframework.ui.ModelMap; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.context.request.WebRequestInterceptor; - -@Component -public class TenantInterceptor implements WebRequestInterceptor { - - public static final String TENANT_HEADER_NAME = "X-TENANT-ID"; - - - @Override - public void preHandle(WebRequest request) { - - if (request.getHeader(TENANT_HEADER_NAME) != null) { - TenantContext.setTenantId(request.getHeader(TENANT_HEADER_NAME)); - } - } - - - @Override - public void postHandle(WebRequest request, ModelMap model) { - - TenantContext.clear(); - } - - - @Override - public void afterCompletion(WebRequest request, Exception ex) { - - } - -} \ No newline at end of file diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ExcelReportGenerationService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ExcelReportGenerationService.java index 38d39b9..c978cff 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ExcelReportGenerationService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ExcelReportGenerationService.java @@ -78,10 +78,7 @@ import lombok.extern.slf4j.Slf4j; @RequiredArgsConstructor public class ExcelReportGenerationService { - private final RSSPoc2Service rSSPoc2Service; - private static final Set prefixRedactionPlaceholders = Set.of(DOSSIER_ATTRIBUTE_PLACEHOLDER_BASE, FILE_ATTRIBUTE_PLACEHOLDER_BASE); - private static final Set redactionPlaceholders = Set.of(FILE_NAME_PLACEHOLDER, PAGE_PLACEHOLDER, PARAGRAPH_PLACEHOLDER, @@ -97,6 +94,7 @@ public class ExcelReportGenerationService { REDACTION_ENTITY_DISPLAY_NAME_PLACEHOLDER, SCM_FUNCTION_PLACEHOLDER, SKIPPED_PLACEHOLDER); + private final RSSPoc2Service rSSPoc2Service; @Timed("redactmanager_generateExcelReport") @@ -218,6 +216,60 @@ public class ExcelReportGenerationService { } + private void addRedactionEntryRows(Sheet sheet, List reportEntries, String filename, ExcelModel excelModel, PlaceholderModel placeholderModel) { + + long start = System.currentTimeMillis(); + AtomicInteger rowIndex = new AtomicInteger(excelModel.getRedactionPlaceholderRow()); + + Map> placeholderCellPos = excelModel.getPlaceholderCellPos(); + reportEntries.forEach(entry -> { + + sheet.createRow(rowIndex.get()); + excelModel.getWrittenRows().add(rowIndex.get()); + for (Map.Entry> entry1 : placeholderCellPos.entrySet()) { + Cell cell = sheet.getRow(rowIndex.get()).createCell(entry1.getKey()); + cell.setCellValue(entry1.getValue().apply(new PlaceholderInput(filename, entry, placeholderModel, null))); + } + rowIndex.getAndIncrement(); + }); + + excelModel.setRedactionPlaceholderRow(rowIndex.getAndIncrement()); + + log.debug("Adding rows took: {}", System.currentTimeMillis() - start); + } + + + private void addSCMEntryRows(Sheet sheet, FileModel fileModel, ExcelModel excelModel) { + + var scm = rSSPoc2Service.getRSS(fileModel.getDossierId(), fileModel.getId()); + var scmResultMap = scm.getFiles().get(0).getResult(); + + AtomicInteger rowIndex = new AtomicInteger(excelModel.getRedactionPlaceholderRow()); + + var oecd = rSSPoc2Service.getOecdNumber(fileModel); + + for (Map.Entry entry : scmResultMap.entrySet()) { + + sheet.createRow(rowIndex.get()); + excelModel.getWrittenRows().add(rowIndex.get()); + + Cell keyCell = sheet.getRow(rowIndex.get()).createCell(0); + keyCell.setCellValue(oecd + "-" + entry.getKey().replaceAll("_", " ")); + + Cell valueCell = sheet.getRow(rowIndex.get()).createCell(1); + valueCell.setCellValue(entry.getValue().getValue() != null ? entry.getValue().getValue() : entry.getValue().getOriginalValue()); + + rowIndex.getAndIncrement(); + } + + sheet.createRow(rowIndex.get()); + excelModel.getWrittenRows().add(rowIndex.get()); + + excelModel.setRedactionPlaceholderRow(rowIndex.getAndIncrement()); + + } + + private void replacePlaceholders(Cell cell, PlaceholderModel placeholderModel, String dossierName, String filename) { for (String placeholder : placeholderModel.getPlaceholders()) { @@ -229,6 +281,112 @@ public class ExcelReportGenerationService { } + private void replacePlaceholdersForImagePlaceholder(SXSSFWorkbook workbook, Sheet sheet, Cell cell, PlaceholderModel placeholderModel) throws IOException { + + for (ImagePlaceholder imagePlaceholder : placeholderModel.getImagePlaceholders()) { + + if (cell.getStringCellValue().contains(imagePlaceholder.getPlaceholder())) { + try (ByteArrayInputStream is = new ByteArrayInputStream(imagePlaceholder.getImage())) { + + double factor = calculateScale(is, + PixelUtil.widthUnits2Pixel((short) sheet.getColumnWidth(cell.getColumnIndex())), + PixelUtil.heightUnits2Pixel(cell.getRow().getHeight())); + is.reset(); + + int pictureIdx = workbook.addPicture(is.readAllBytes(), SXSSFWorkbook.PICTURE_TYPE_JPEG); + is.reset(); + + //Returns an object that handles instantiating concrete classes + CreationHelper helper = workbook.getCreationHelper(); + //Create an anchor that is attached to the worksheet + ClientAnchor anchor = helper.createClientAnchor(); + anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE); + + anchor.setCol1(cell.getColumnIndex()); + anchor.setRow1(cell.getRowIndex()); + + //Creates the top-level drawing patriarch. + Drawing drawing = sheet.createDrawingPatriarch(); + + Picture picture = drawing.createPicture(anchor, pictureIdx); + picture.resize(factor); + + cell.setCellValue(""); + + } + } + } + } + + + private String getPlaceholderValue(String placeholder, String dossierName, String filename, PlaceholderModel placeholderModel) { + + if (placeholder.equals(FORMAT_DATE_ISO_PLACEHOLDER)) { + return OffsetDateTime.now().format(FORMAT_DATE_ISO); + } + if (placeholder.equals(FORMAT_DATE_GER_PLACEHOLDER)) { + return OffsetDateTime.now().format(FORMAT_DATE_GER); + } + if (placeholder.equals(FORMAT_DATE_ENG_PLACEHOLDER)) { + return OffsetDateTime.now().format(FORMAT_DATE_ENG); + } + if (placeholder.equals(FORMAT_TIME_ISO_PLACEHOLDER)) { + return OffsetDateTime.now().format(FORMAT_TIME_ISO); + } + if (placeholder.equals(DOSSIER_NAME_PLACEHOLDER)) { + return dossierName; + } + if (placeholder.equals(FILE_NAME_PLACEHOLDER)) { + return filename; + } + if (placeholderModel.getFileAttributeValueByPlaceholder().containsKey(placeholder)) { + return placeholderModel.getFileAttributeValueByPlaceholder().get(placeholder); + } + + if (placeholderModel.getDossierAttributesValueByPlaceholder().containsKey(placeholder)) { + return placeholderModel.getDossierAttributesValueByPlaceholder().get(placeholder); + } + + if (placeholderModel.getRssComponentPlaceholder() != null && placeholderModel.getRssComponentPlaceholder().containsKey(placeholder)) { + return placeholderModel.getRssComponentPlaceholder().get(placeholder); + } + + return null; + } + + + private void replacePlaceholdersForCell(Cell cell, String search, String replace) { + + if (cell.getStringCellValue().contains(search)) { + String safeToUseInReplaceAllString = Pattern.quote(search); + String escapedReplace = Matcher.quoteReplacement(replace); + String str = cell.getStringCellValue().replaceAll(safeToUseInReplaceAllString, escapedReplace); + cell.setCellValue(str); + } + } + + + private double calculateScale(ByteArrayInputStream imageByteArrayInputStream, float cellWidth, float cellHeight) throws IOException { + + BufferedImage img = ImageIO.read(imageByteArrayInputStream); + + double imageWidth = img.getWidth(); + double imageHeight = img.getHeight(); + + double widthFactor = cellWidth / imageWidth; + double heightFactor = cellHeight / imageHeight; + + if (imageWidth < cellWidth && imageHeight < cellHeight) { + return 1; + } else if (cellWidth > cellHeight) { + return heightFactor; + } else { + return widthFactor; + } + + } + + @Timed("redactmanager_calculateExcelModel") public ExcelModel calculateExcelModel(Sheet sheet) { @@ -306,60 +464,6 @@ public class ExcelReportGenerationService { } - private void addSCMEntryRows(Sheet sheet, FileModel fileModel, ExcelModel excelModel) { - - var scm = rSSPoc2Service.getRSS(fileModel.getDossierId(), fileModel.getId()); - var scmResultMap = scm.getFiles().get(0).getResult(); - - AtomicInteger rowIndex = new AtomicInteger(excelModel.getRedactionPlaceholderRow()); - - var oecd = rSSPoc2Service.getOecdNumber(fileModel); - - for (Map.Entry entry : scmResultMap.entrySet()) { - - sheet.createRow(rowIndex.get()); - excelModel.getWrittenRows().add(rowIndex.get()); - - Cell keyCell = sheet.getRow(rowIndex.get()).createCell(0); - keyCell.setCellValue(oecd + "-" + entry.getKey().replaceAll("_", " ")); - - Cell valueCell = sheet.getRow(rowIndex.get()).createCell(1); - valueCell.setCellValue(entry.getValue().getValue() != null ? entry.getValue().getValue() : entry.getValue().getOriginalValue()); - - rowIndex.getAndIncrement(); - } - - sheet.createRow(rowIndex.get()); - excelModel.getWrittenRows().add(rowIndex.get()); - - excelModel.setRedactionPlaceholderRow(rowIndex.getAndIncrement()); - - } - - - private void addRedactionEntryRows(Sheet sheet, List reportEntries, String filename, ExcelModel excelModel, PlaceholderModel placeholderModel) { - - long start = System.currentTimeMillis(); - AtomicInteger rowIndex = new AtomicInteger(excelModel.getRedactionPlaceholderRow()); - - Map> placeholderCellPos = excelModel.getPlaceholderCellPos(); - reportEntries.forEach(entry -> { - - sheet.createRow(rowIndex.get()); - excelModel.getWrittenRows().add(rowIndex.get()); - for (Map.Entry> entry1 : placeholderCellPos.entrySet()) { - Cell cell = sheet.getRow(rowIndex.get()).createCell(entry1.getKey()); - cell.setCellValue(entry1.getValue().apply(new PlaceholderInput(filename, entry, placeholderModel, null))); - } - rowIndex.getAndIncrement(); - }); - - excelModel.setRedactionPlaceholderRow(rowIndex.getAndIncrement()); - - log.debug("Adding rows took: {}", System.currentTimeMillis() - start); - } - - private boolean isRedactionPlaceholder(String text) { return prefixRedactionPlaceholders.stream().anyMatch(text::startsWith) || redactionPlaceholders.stream().anyMatch(text::contains); @@ -383,10 +487,9 @@ public class ExcelReportGenerationService { case JUSTIFICATION_PARAGRAPH_PLACEHOLDER, JUSTIFICATION_LEGAL_BASIS_PLACEHOLDER -> input -> input.getEntry().getJustificationParagraph(); case JUSTIFICATION_REASON_PLACEHOLDER, JUSTIFICATION_TEXT_PLACEHOLDER -> input -> input.getEntry().getJustificationReason(); case EXCERPT_PLACEHOLDER -> input -> input.getEntry().getExcerpt(); - case REDACTION_VALUE_PLACEHOLDER -> input -> input.getEntry().getValue() != null ? input.getEntry() - .getValue() - .replaceAll("\n", " ") - .replaceAll(" {2,}", " ") : input.getEntry().getEntityDisplayName(); + case REDACTION_VALUE_PLACEHOLDER -> + input -> input.getEntry().getValue() != null ? input.getEntry().getValue().replaceAll("\n", " ").replaceAll(" {2,}", " ") : input.getEntry() + .getEntityDisplayName(); case REDACTION_ENTITY_DISPLAY_NAME_PLACEHOLDER -> input -> input.getEntry().getEntityDisplayName(); case SKIPPED_PLACEHOLDER -> input -> input.getEntry().isSkipped() ? "true" : "false"; default -> input -> ""; @@ -395,112 +498,6 @@ public class ExcelReportGenerationService { } - private void replacePlaceholdersForCell(Cell cell, String search, String replace) { - - if (cell.getStringCellValue().contains(search)) { - String safeToUseInReplaceAllString = Pattern.quote(search); - String escapedReplace = Matcher.quoteReplacement(replace); - String str = cell.getStringCellValue().replaceAll(safeToUseInReplaceAllString, escapedReplace); - cell.setCellValue(str); - } - } - - - private void replacePlaceholdersForImagePlaceholder(SXSSFWorkbook workbook, Sheet sheet, Cell cell, PlaceholderModel placeholderModel) throws IOException { - - for (ImagePlaceholder imagePlaceholder : placeholderModel.getImagePlaceholders()) { - - if (cell.getStringCellValue().contains(imagePlaceholder.getPlaceholder())) { - try (ByteArrayInputStream is = new ByteArrayInputStream(imagePlaceholder.getImage())) { - - double factor = calculateScale(is, - PixelUtil.widthUnits2Pixel((short) sheet.getColumnWidth(cell.getColumnIndex())), - PixelUtil.heightUnits2Pixel(cell.getRow().getHeight())); - is.reset(); - - int pictureIdx = workbook.addPicture(is.readAllBytes(), SXSSFWorkbook.PICTURE_TYPE_JPEG); - is.reset(); - - //Returns an object that handles instantiating concrete classes - CreationHelper helper = workbook.getCreationHelper(); - //Create an anchor that is attached to the worksheet - ClientAnchor anchor = helper.createClientAnchor(); - anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE); - - anchor.setCol1(cell.getColumnIndex()); - anchor.setRow1(cell.getRowIndex()); - - //Creates the top-level drawing patriarch. - Drawing drawing = sheet.createDrawingPatriarch(); - - Picture picture = drawing.createPicture(anchor, pictureIdx); - picture.resize(factor); - - cell.setCellValue(""); - - } - } - } - } - - - private double calculateScale(ByteArrayInputStream imageByteArrayInputStream, float cellWidth, float cellHeight) throws IOException { - - BufferedImage img = ImageIO.read(imageByteArrayInputStream); - - double imageWidth = img.getWidth(); - double imageHeight = img.getHeight(); - - double widthFactor = cellWidth / imageWidth; - double heightFactor = cellHeight / imageHeight; - - if (imageWidth < cellWidth && imageHeight < cellHeight) { - return 1; - } else if (cellWidth > cellHeight) { - return heightFactor; - } else { - return widthFactor; - } - - } - - - private String getPlaceholderValue(String placeholder, String dossierName, String filename, PlaceholderModel placeholderModel) { - - if (placeholder.equals(FORMAT_DATE_ISO_PLACEHOLDER)) { - return OffsetDateTime.now().format(FORMAT_DATE_ISO); - } - if (placeholder.equals(FORMAT_DATE_GER_PLACEHOLDER)) { - return OffsetDateTime.now().format(FORMAT_DATE_GER); - } - if (placeholder.equals(FORMAT_DATE_ENG_PLACEHOLDER)) { - return OffsetDateTime.now().format(FORMAT_DATE_ENG); - } - if (placeholder.equals(FORMAT_TIME_ISO_PLACEHOLDER)) { - return OffsetDateTime.now().format(FORMAT_TIME_ISO); - } - if (placeholder.equals(DOSSIER_NAME_PLACEHOLDER)) { - return dossierName; - } - if (placeholder.equals(FILE_NAME_PLACEHOLDER)) { - return filename; - } - if (placeholderModel.getFileAttributeValueByPlaceholder().containsKey(placeholder)) { - return placeholderModel.getFileAttributeValueByPlaceholder().get(placeholder); - } - - if (placeholderModel.getDossierAttributesValueByPlaceholder().containsKey(placeholder)) { - return placeholderModel.getDossierAttributesValueByPlaceholder().get(placeholder); - } - - if (placeholderModel.getRssComponentPlaceholder() != null && placeholderModel.getRssComponentPlaceholder().containsKey(placeholder)) { - return placeholderModel.getRssComponentPlaceholder().get(placeholder); - } - - return null; - } - - @SneakyThrows public byte[] toByteArray(SXSSFWorkbook workbook) { diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/GeneratePlaceholderService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/GeneratePlaceholderService.java index 8850ef2..3dfd01b 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/GeneratePlaceholderService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/GeneratePlaceholderService.java @@ -90,6 +90,30 @@ public class GeneratePlaceholderService { } + private Map getFileAttributePlaceholders(String dossierTemplateId) { + + Map fileAttributePlaceholders = new HashMap<>(); + + var fileAttributesConfig = fileAttributesClient.getFileAttributeConfigs(dossierTemplateId); + fileAttributesConfig.forEach(fileAttributeConfig -> fileAttributePlaceholders.put(fileAttributeConfig.getPlaceholder(), fileAttributeConfig.getId())); + return fileAttributePlaceholders; + } + + + public Set getDefaultPlaceholders() { + + return new HashSet<>(Set.of(FILE_NAME_PLACEHOLDER, + FORMAT_DATE_ISO_PLACEHOLDER, + FORMAT_DATE_GER_PLACEHOLDER, + FORMAT_DATE_ENG_PLACEHOLDER, + FORMAT_TIME_ISO_PLACEHOLDER, + DOSSIER_NAME_PLACEHOLDER, + IUCLID_FUNCTION_PLACEHOLDER, + SEEDS_FUNCTION_REDACTION_GROUPED_BY_JUSTIFICATION_PAGES_PLACEHOLDER, + SEEDS_FUNCTION_JUSTIFICATION_PLACEHOLDER)); + } + + public void resolveFileAttributeValues(FileModel fileModel, PlaceholderModel placeholderModel) { Map fileAttributeValueByPlaceholder = new HashMap<>(); @@ -115,28 +139,4 @@ public class GeneratePlaceholderService { placeholderModel.getPlaceholders().addAll(rssPlaceholders.keySet()); } - - public Set getDefaultPlaceholders() { - - return new HashSet<>(Set.of(FILE_NAME_PLACEHOLDER, - FORMAT_DATE_ISO_PLACEHOLDER, - FORMAT_DATE_GER_PLACEHOLDER, - FORMAT_DATE_ENG_PLACEHOLDER, - FORMAT_TIME_ISO_PLACEHOLDER, - DOSSIER_NAME_PLACEHOLDER, - IUCLID_FUNCTION_PLACEHOLDER, - SEEDS_FUNCTION_REDACTION_GROUPED_BY_JUSTIFICATION_PAGES_PLACEHOLDER, - SEEDS_FUNCTION_JUSTIFICATION_PLACEHOLDER)); - } - - - private Map getFileAttributePlaceholders(String dossierTemplateId) { - - Map fileAttributePlaceholders = new HashMap<>(); - - var fileAttributesConfig = fileAttributesClient.getFileAttributeConfigs(dossierTemplateId); - fileAttributesConfig.forEach(fileAttributeConfig -> fileAttributePlaceholders.put(fileAttributeConfig.getPlaceholder(), fileAttributeConfig.getId())); - return fileAttributePlaceholders; - } - } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/PlaceholderService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/PlaceholderService.java index 4ec1356..eeae7c6 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/PlaceholderService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/PlaceholderService.java @@ -71,7 +71,6 @@ public class PlaceholderService { public static final String SEEDS_FUNCTION_REDACTION_GROUPED_BY_JUSTIFICATION_PAGES_PLACEHOLDER = "{{function.seeds.redactionGroupedByJustification.pages}}"; public static final String SEEDS_FUNCTION_JUSTIFICATION_PLACEHOLDER = "{{function.seeds.justification}}"; - public static final Set GENERAL_PLACEHOLDERS = Set.of(FILE_NAME_PLACEHOLDER, PAGE_PLACEHOLDER, PARAGRAPH_PLACEHOLDER, @@ -105,22 +104,15 @@ public class PlaceholderService { } - public List getReportTemplatesByPlaceholder(String dossierTemplateId, String placeholder) { + private Set getAllPlaceholders(String dossierTemplateId) { - List reportTemplates = reportTemplateClient.getAvailableReportTemplates(dossierTemplateId); - if (reportTemplates == null || reportTemplates.isEmpty()) { - throw new NotFoundException("For dossierTemplateId '" + dossierTemplateId + "' no report templates exist."); - } - List result = new ArrayList<>(); + Set allPlaceholders = new HashSet<>(GENERAL_PLACEHOLDERS); - for (ReportTemplate reportTemplate : reportTemplates) { - Set placeholders = findGivenPlaceholdersOfTemplate(reportTemplate, new HashSet<>(Collections.singleton(placeholder))); - if (!placeholders.isEmpty()) { - result.add(reportTemplate); - } - } + dossierAttributesConfigClient.getDossierAttributes(dossierTemplateId).forEach(dossierAttributeConfig -> allPlaceholders.add(dossierAttributeConfig.getPlaceholder())); - return result; + fileAttributesClient.getFileAttributeConfigs(dossierTemplateId).forEach(fileAttributeConfig -> allPlaceholders.add(fileAttributeConfig.getPlaceholder())); + + return allPlaceholders; } @@ -216,18 +208,6 @@ public class PlaceholderService { } - private Set getAllPlaceholders(String dossierTemplateId) { - - Set allPlaceholders = new HashSet<>(GENERAL_PLACEHOLDERS); - - dossierAttributesConfigClient.getDossierAttributes(dossierTemplateId).forEach(dossierAttributeConfig -> allPlaceholders.add(dossierAttributeConfig.getPlaceholder())); - - fileAttributesClient.getFileAttributeConfigs(dossierTemplateId).forEach(fileAttributeConfig -> allPlaceholders.add(fileAttributeConfig.getPlaceholder())); - - return allPlaceholders; - } - - private void contains(Set allPlaceholders, Set resultPlaceholders, String placeholder) { for (String searchPlaceholder : allPlaceholders) { @@ -238,4 +218,23 @@ public class PlaceholderService { allPlaceholders.removeAll(resultPlaceholders); } + + public List getReportTemplatesByPlaceholder(String dossierTemplateId, String placeholder) { + + List reportTemplates = reportTemplateClient.getAvailableReportTemplates(dossierTemplateId); + if (reportTemplates == null || reportTemplates.isEmpty()) { + throw new NotFoundException("For dossierTemplateId '" + dossierTemplateId + "' no report templates exist."); + } + List result = new ArrayList<>(); + + for (ReportTemplate reportTemplate : reportTemplates) { + Set placeholders = findGivenPlaceholdersOfTemplate(reportTemplate, new HashSet<>(Collections.singleton(placeholder))); + if (!placeholders.isEmpty()) { + result.add(reportTemplate); + } + } + + return result; + } + } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RSSPoc2Service.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RSSPoc2Service.java index a7aef0c..7ab1b50 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RSSPoc2Service.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RSSPoc2Service.java @@ -90,8 +90,8 @@ public class RSSPoc2Service { private final Map guidelineMapping = new HashMap<>(); private final FileAttributesConfigClient fileAttributesClient; - private List formats = new ArrayList<>(); - private DateFormat resultDateFormat = new SimpleDateFormat("dd/MM/yyyy"); + private final List formats = new ArrayList<>(); + private final DateFormat resultDateFormat = new SimpleDateFormat("dd/MM/yyyy"); @PostConstruct @@ -336,22 +336,386 @@ public class RSSPoc2Service { } - @SneakyThrows - private void setOverrideValues(String dossierId, String fileId, Map result) { + public String getOecdNumber(FileModel file) { - if (!reportStorageService.objectExists(dossierId, fileId, FileType.COMPONENTS)) { - return; + var fileAttributesConfig = fileAttributesClient.getFileAttributeConfigs(file.getDossierTemplateId()); + var oecdFileAttributeConf = fileAttributesConfig.stream().filter(f -> f.getLabel().equals("OECD Number")).map(f -> f.getId()).findFirst(); + if (oecdFileAttributeConf.isPresent()) { + return file.getFileAttributes().get(oecdFileAttributeConf.get()); + } + return null; + } + + + private void sortRedactionLog(RedactionLog redactionLog) { + + redactionLog.getRedactionLogEntry().sort((entry1, entry2) -> { + if (entry1.getPositions().get(0).getPage() == entry2.getPositions().get(0).getPage()) { + if (entry1.getPositions().get(0).getTopLeft().getY() == entry2.getPositions().get(0).getTopLeft().getY()) { + return entry1.getPositions().get(0).getTopLeft().getX() <= entry2.getPositions().get(0).getTopLeft().getX() ? -1 : 1; + } else { + return entry1.getPositions().get(0).getTopLeft().getY() <= entry2.getPositions().get(0).getTopLeft().getY() ? 1 : -1; + } + } + return entry1.getPositions().get(0).getPage() < entry2.getPositions().get(0).getPage() ? -1 : 1; + }); + + } + + + private SCMComponent getFirstEntryOrElse(RedactionLog redactionLog, String type, String elseValue) { + + String transformation = String.format("First found value of type '%s' or else '%s'", type, elseValue); + + var firstEntryOptional = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).findFirst(); + + if (firstEntryOptional.isPresent()) { + + var firstEntry = firstEntryOptional.get(); + return SCMComponent.builder().originalValue(firstEntry.getValue()).scmAnnotations(List.of(toScmAnnotations(firstEntry))).transformation(transformation).build(); } - var overrideBytes = reportStorageService.getStoredObjectBytes(dossierId, fileId, FileType.COMPONENTS); - ComponentsOverrides componentsOverrides = objectMapper.readValue(overrideBytes, ComponentsOverrides.class); + return SCMComponent.builder().originalValue(elseValue).transformation(transformation).build(); + } - for (Map.Entry entry : result.entrySet()) { - if (componentsOverrides.getComponentOverrides().containsKey(entry.getKey())) { - String overrideValue = componentsOverrides.getComponentOverrides().get(entry.getKey()); - entry.getValue().setValue(overrideValue); + + private SCMComponent getPerformingLaboratory(RedactionLog redactionLog) { + + String transformation = "Value of laboratory_name, combined with laboratory_country if distance is small"; + + var laboratoryEntry = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("laboratory_name")).findFirst(); + if (!laboratoryEntry.isPresent()) { + return SCMComponent.builder().originalValue("").transformation(transformation).build(); + } + + var laboratoryCountry = redactionLog.getRedactionLogEntry() + .stream() + .filter(r -> r.getType().equals("laboratory_country") && Math.abs(laboratoryEntry.get().getPositions().get(0).getTopLeft().getY() - r.getPositions() + .get(0) + .getTopLeft() + .getY()) < 80) + .collect(Collectors.toList()); + + RedactionLogEntry countryWithSmallestDistance = null; + for (var entry : laboratoryCountry) { + + if (countryWithSmallestDistance == null) { + countryWithSmallestDistance = entry; + } else if (Math.abs(laboratoryEntry.get().getPositions().get(0).getTopLeft().getY() - entry.getPositions().get(0).getTopLeft().getY()) < Math.abs(laboratoryEntry.get() + .getPositions() + .get(0) + .getTopLeft() + .getY() - countryWithSmallestDistance.getPositions().get(0).getTopLeft().getY())) { + countryWithSmallestDistance = entry; + } + + } + + List scmAnnotations = new ArrayList<>(); + scmAnnotations.add(toScmAnnotations(laboratoryEntry.get())); + + StringBuilder sb = new StringBuilder(); + if (laboratoryEntry.isPresent()) { + sb.append(laboratoryEntry.get().getValue()); + } + if (countryWithSmallestDistance != null) { + sb.append(", ").append(countryWithSmallestDistance.getValue()); + scmAnnotations.add(toScmAnnotations(countryWithSmallestDistance)); + } + + return SCMComponent.builder().originalValue(sb.toString().trim()).scmAnnotations(scmAnnotations).transformation(transformation).build(); + } + + + private SCMComponent getConvertedDates(RedactionLog redactionLog, String type) { + + List redactionLogEntries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).collect(Collectors.toList()); + + String value = redactionLogEntries.stream().map(RedactionLogEntry::getValue).map(this::convertDate).collect(Collectors.joining(", ")); + + return SCMComponent.builder() + .originalValue(value) + .scmAnnotations(redactionLogEntries.stream().map(this::toScmAnnotations).collect(Collectors.toList())) + .transformation(String.format("Convert values of type '%s' to dd/MM/yyyy joined with ', '", type)) + .build(); + } + + + private SCMComponent ifPresentAddOrElse(RedactionLog redactionLog, String type, String presentValue, String elseValue) { + + String transformation = String.format("If type %s is present than '%s' else '%s'", type, presentValue, elseValue); + + var firstEntryOptional = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).findFirst(); + + if (firstEntryOptional.isPresent()) { + + var firstEntry = firstEntryOptional.get(); + return SCMComponent.builder().originalValue(presentValue).scmAnnotations(List.of(toScmAnnotations(firstEntry))).transformation(transformation).build(); + } + + return SCMComponent.builder().originalValue(elseValue).transformation(transformation).build(); + } + + + private SCMComponent getJoinedUniqueValues(RedactionLog redactionLog, String type, String seperator) { + + String transformation = String.format("Combine unique values of '%s' with seperator '%s'", type, seperator); + + var uniqueEntries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).collect(Collectors.toSet()); + + String value = uniqueEntries.stream().map(RedactionLogEntry::getValue).collect(Collectors.toSet()).stream().collect(Collectors.joining(seperator)).trim(); + + return SCMComponent.builder() + .originalValue(value) + .scmAnnotations(uniqueEntries.stream().map(this::toScmAnnotations).collect(Collectors.toList())) + .transformation(transformation) + .build(); + } + + + private SCMComponent getTestGuideline1(RedactionLog redactionLog) { + + String transformation = "If 'oecd_guideline_number' and 'oecd_guideline_year' are present than mapped by provided mapping table else value of 'oecd_guideline' if present or else ''"; + + var guidelineNumber = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("oecd_guideline_number")).findFirst(); + var guidelineYear = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("oecd_guideline_year")).findFirst(); + + if (guidelineNumber.isPresent() && guidelineYear.isPresent()) { + var guidelinePair = Pair.of(guidelineNumber.get().getValue(), guidelineYear.get().getValue()); + if (guidelineMapping.containsKey(guidelinePair)) { + String value = guidelineMapping.get(guidelinePair); + return SCMComponent.builder() + .originalValue(value) + .scmAnnotations(List.of(toScmAnnotations(guidelineNumber.get()), toScmAnnotations(guidelineYear.get()))) + .transformation(transformation) + .build(); } } + + var guideline = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("oecd_guideline")).findFirst(); + + if (guideline.isPresent()) { + return SCMComponent.builder() + .originalValue(guideline.get().getValue()) + .scmAnnotations(List.of(toScmAnnotations(guideline.get()))) + .transformation(transformation) + .build(); + } + + return SCMComponent.builder().originalValue("").transformation(transformation).build(); + } + + + private SCMComponent getTestGuideline2(RedactionLog redactionLog) { + + String transformation = "Combine values of 'epa_guideline' and 'ec_guideline' with seperator ', '"; + + List guidelines = new ArrayList<>(); + guidelines.addAll(redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("epa_guideline")).collect(Collectors.toList())); + guidelines.addAll(redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("ec_guideline")).collect(Collectors.toList())); + + String value = guidelines.stream().map(RedactionLogEntry::getValue).collect(Collectors.joining(", ")); + + if (!value.isEmpty()) { + return SCMComponent.builder() + .originalValue(value) + .scmAnnotations(guidelines.stream().map(this::toScmAnnotations).collect(Collectors.toList())) + .transformation(transformation) + .build(); + } + + return SCMComponent.builder().originalValue("").transformation(transformation).build(); + } + + + private boolean oecdIn(String oecd, Set oecdsToApply) { + + return oecd != null && oecdsToApply.contains(oecd); + } + + + private List getAsSentences(RedactionLog redactionLog, String type) { + + String transformation = String.format("Values of type '%s' as sentences", type); + + List sentences = new ArrayList<>(); + var typeStringsEntries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).collect(Collectors.toList()); + + if (typeStringsEntries.isEmpty()) { + return sentences; + } + + for (RedactionLogEntry typeStringEntry : typeStringsEntries) { + + BreakIterator iterator = BreakIterator.getSentenceInstance(Locale.US); + iterator.setText(typeStringEntry.getValue()); + int start = iterator.first(); + for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next()) { + + sentences.add(SCMComponent.builder() + .originalValue(typeStringEntry.getValue().substring(start, end).replaceAll("\\n", "").trim()) + .scmAnnotations(List.of(toScmAnnotations(typeStringEntry))) + .transformation(transformation) + .build()); + + } + } + + return sentences; + } + + + private SCMComponent getLongestBlockOrElse(RedactionLog redactionLog, String type, String elseValue) { + + String transformation = String.format("Longest value of type '%s' if present or else '%s'", type, elseValue); + + var entries = redactionLog.getRedactionLogEntry() + .stream() + .filter(r -> r.getType().equals(type)) + .sorted(Comparator.comparing(s -> s.getValue().length())) + .collect(Collectors.toList()); + + if (!entries.isEmpty()) { + + var firstEntry = entries.get(entries.size() - 1); + return SCMComponent.builder().originalValue(firstEntry.getValue()).scmAnnotations(List.of(toScmAnnotations(firstEntry))).transformation(transformation).build(); + } + + return SCMComponent.builder().originalValue(elseValue).transformation(transformation).build(); + + } + + + private SCMComponent getAsOneBlock(RedactionLog redactionLog, String type) { + + String transformation = String.format("Combine value of '%s' to one block", type); + + var entries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).collect(Collectors.toList()); + + String value = entries.stream().map(RedactionLogEntry::getValue).collect(Collectors.joining(" ")); + + return SCMComponent.builder() + .originalValue(value) + .scmAnnotations(entries.stream().map(this::toScmAnnotations).collect(Collectors.toList())) + .transformation(transformation) + .build(); + } + + + private SCMComponent getJoinedValues(RedactionLog redactionLog, String type, String seperator) { + + String transformation = String.format("Combine values of '%s' with seperator '%s'", type, seperator); + + var entries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).collect(Collectors.toList()); + + String value = entries.stream().map(RedactionLogEntry::getValue).collect(Collectors.joining(seperator)).trim(); + + return SCMComponent.builder() + .originalValue(value) + .scmAnnotations(entries.stream().map(this::toScmAnnotations).collect(Collectors.toList())) + .transformation(transformation) + .build(); + } + + + private SCMComponent getSex(RedactionLog redactionLog) { + + String transformation = "Combine unique values of 'sex', map plural values to singular"; + + var entries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("sex")).collect(Collectors.toSet()); + + var value = entries.stream().map(RedactionLogEntry::getValue).map(String::toLowerCase).map(s -> { + if (s.equals("females")) { + return "female"; + } else if (s.equals("males")) { + return "male"; + } + return s; + }).collect(Collectors.toSet()).stream().collect(Collectors.joining(", ")).trim(); + + return SCMComponent.builder() + .originalValue(value) + .scmAnnotations(entries.stream().map(this::toScmAnnotations).collect(Collectors.toList())) + .transformation(transformation) + .build(); + } + + + private SCMComponent getNumberOfAnimals(RedactionLog redactionLog) { + + String transformation = "Return value of 'number_of_animals' if present else return sum of unique 'animal_number' or else '' "; + + var numberOfAnimals = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("number_of_animals")).findFirst(); + + if (numberOfAnimals.isPresent()) { + return SCMComponent.builder() + .originalValue(numberOfAnimals.get().getValue()) + .scmAnnotations(List.of(toScmAnnotations(numberOfAnimals.get()))) + .transformation(transformation) + .build(); + } + + var uniqueAnimalNumbers = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("animal_number")).collect(Collectors.toSet()); + + if (uniqueAnimalNumbers.isEmpty()) { + return SCMComponent.builder().originalValue("").transformation(transformation).build(); + } + + int size = uniqueAnimalNumbers.stream().map(a -> a.getValue()).collect(Collectors.toSet()).size(); + + return SCMComponent.builder() + .originalValue(String.valueOf(size)) + .scmAnnotations(uniqueAnimalNumbers.stream().map(this::toScmAnnotations).collect(Collectors.toList())) + .transformation(transformation) + .build(); + } + + + private List getDoseMortality(RedactionLog redactionLog) { + + String transformation = "Combine values of 'dose_mortality' and 'dose_mortality_dose' of same row with ', ' "; + + var doseMortalityEntries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("dose_mortality")).collect(Collectors.toList()); + var doseMortalityDoseEntries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("dose_mortality_dose")).collect(Collectors.toList()); + + List result = new ArrayList<>(); + for (var mortality : doseMortalityEntries) { + + RedactionLogEntry doseWithSmallestDistance = null; + for (var dose : doseMortalityDoseEntries) { + if (Math.round(mortality.getPositions().get(0).getTopLeft().getY()) == Math.round(dose.getPositions().get(0).getTopLeft().getY())) { + doseWithSmallestDistance = dose; + break; + } + if (doseWithSmallestDistance == null) { + doseWithSmallestDistance = dose; + } else if (Math.abs(Math.round(mortality.getPositions().get(0).getTopLeft().getY()) - Math.round(dose.getPositions() + .get(0) + .getTopLeft() + .getY())) < Math.abs(Math.round(mortality.getPositions().get(0).getTopLeft().getY()) - Math.round(doseWithSmallestDistance.getPositions() + .get(0) + .getTopLeft() + .getY()))) { + doseWithSmallestDistance = dose; + } + } + + if (doseWithSmallestDistance != null) { + + result.add(SCMComponent.builder() + .originalValue(doseWithSmallestDistance.getValue() + ", " + mortality.getValue()) + .scmAnnotations(List.of(toScmAnnotations(doseWithSmallestDistance), toScmAnnotations(mortality))) + .transformation(transformation) + .build()); + + } else if (mortality != null) { + + result.add(SCMComponent.builder().originalValue(mortality.getValue()).scmAnnotations(List.of(toScmAnnotations(mortality))).transformation(transformation).build()); + } + + } + + return result; } @@ -470,318 +834,22 @@ public class RSSPoc2Service { } - private Map getKeyContains(Map components, String compontentName) { + @SneakyThrows + private void setOverrideValues(String dossierId, String fileId, Map result) { - Map resultMap = new LinkedHashMap<>(); + if (!reportStorageService.objectExists(dossierId, fileId, FileType.COMPONENTS)) { + return; + } - for (Map.Entry entry : components.entrySet()) { - if (entry.getKey().contains(compontentName)) { - resultMap.put(entry.getKey(), entry.getValue()); + var overrideBytes = reportStorageService.getStoredObjectBytes(dossierId, fileId, FileType.COMPONENTS); + ComponentsOverrides componentsOverrides = objectMapper.readValue(overrideBytes, ComponentsOverrides.class); + + for (Map.Entry entry : result.entrySet()) { + if (componentsOverrides.getComponentOverrides().containsKey(entry.getKey())) { + String overrideValue = componentsOverrides.getComponentOverrides().get(entry.getKey()); + entry.getValue().setValue(overrideValue); } } - - return resultMap; - } - - - private SCMComponent getSex(RedactionLog redactionLog) { - - String transformation = "Combine unique values of 'sex', map plural values to singular"; - - var entries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("sex")).collect(Collectors.toSet()); - - var value = entries.stream().map(RedactionLogEntry::getValue).map(String::toLowerCase).map(s -> { - if (s.equals("females")) { - return "female"; - } else if (s.equals("males")) { - return "male"; - } - return s; - }).collect(Collectors.toSet()).stream().collect(Collectors.joining(", ")).trim(); - - return SCMComponent.builder() - .originalValue(value) - .scmAnnotations(entries.stream().map(this::toScmAnnotations).collect(Collectors.toList())) - .transformation(transformation) - .build(); - } - - - private List getDoseMortality(RedactionLog redactionLog) { - - String transformation = "Combine values of 'dose_mortality' and 'dose_mortality_dose' of same row with ', ' "; - - var doseMortalityEntries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("dose_mortality")).collect(Collectors.toList()); - var doseMortalityDoseEntries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("dose_mortality_dose")).collect(Collectors.toList()); - - List result = new ArrayList<>(); - for (var mortality : doseMortalityEntries) { - - RedactionLogEntry doseWithSmallestDistance = null; - for (var dose : doseMortalityDoseEntries) { - if (Math.round(mortality.getPositions().get(0).getTopLeft().getY()) == Math.round(dose.getPositions().get(0).getTopLeft().getY())) { - doseWithSmallestDistance = dose; - break; - } - if (doseWithSmallestDistance == null) { - doseWithSmallestDistance = dose; - } else if (Math.abs(Math.round(mortality.getPositions().get(0).getTopLeft().getY()) - Math.round(dose.getPositions() - .get(0) - .getTopLeft() - .getY())) < Math.abs(Math.round(mortality.getPositions().get(0).getTopLeft().getY()) - Math.round(doseWithSmallestDistance.getPositions() - .get(0) - .getTopLeft() - .getY()))) { - doseWithSmallestDistance = dose; - } - } - - if (doseWithSmallestDistance != null) { - - result.add(SCMComponent.builder() - .originalValue(doseWithSmallestDistance.getValue() + ", " + mortality.getValue()) - .scmAnnotations(List.of(toScmAnnotations(doseWithSmallestDistance), toScmAnnotations(mortality))) - .transformation(transformation) - .build()); - - } else if (mortality != null) { - - result.add(SCMComponent.builder().originalValue(mortality.getValue()).scmAnnotations(List.of(toScmAnnotations(mortality))).transformation(transformation).build()); - } - - } - - return result; - } - - - private SCMComponent getJoinedValues(RedactionLog redactionLog, String type, String seperator) { - - String transformation = String.format("Combine values of '%s' with seperator '%s'", type, seperator); - - var entries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).collect(Collectors.toList()); - - String value = entries.stream().map(RedactionLogEntry::getValue).collect(Collectors.joining(seperator)).trim(); - - return SCMComponent.builder() - .originalValue(value) - .scmAnnotations(entries.stream().map(this::toScmAnnotations).collect(Collectors.toList())) - .transformation(transformation) - .build(); - } - - - private SCMComponent getJoinedUniqueValues(RedactionLog redactionLog, String type, String seperator) { - - String transformation = String.format("Combine unique values of '%s' with seperator '%s'", type, seperator); - - var uniqueEntries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).collect(Collectors.toSet()); - - String value = uniqueEntries.stream().map(RedactionLogEntry::getValue).collect(Collectors.toSet()).stream().collect(Collectors.joining(seperator)).trim(); - - return SCMComponent.builder() - .originalValue(value) - .scmAnnotations(uniqueEntries.stream().map(this::toScmAnnotations).collect(Collectors.toList())) - .transformation(transformation) - .build(); - } - - - private SCMComponent getLongestBlockOrElse(RedactionLog redactionLog, String type, String elseValue) { - - String transformation = String.format("Longest value of type '%s' if present or else '%s'", type, elseValue); - - var entries = redactionLog.getRedactionLogEntry() - .stream() - .filter(r -> r.getType().equals(type)) - .sorted(Comparator.comparing(s -> s.getValue().length())) - .collect(Collectors.toList()); - - if (!entries.isEmpty()) { - - var firstEntry = entries.get(entries.size() - 1); - return SCMComponent.builder().originalValue(firstEntry.getValue()).scmAnnotations(List.of(toScmAnnotations(firstEntry))).transformation(transformation).build(); - } - - return SCMComponent.builder().originalValue(elseValue).transformation(transformation).build(); - - } - - - private SCMComponent getAsOneBlock(RedactionLog redactionLog, String type) { - - String transformation = String.format("Combine value of '%s' to one block", type); - - var entries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).collect(Collectors.toList()); - - String value = entries.stream().map(RedactionLogEntry::getValue).collect(Collectors.joining(" ")); - - return SCMComponent.builder() - .originalValue(value) - .scmAnnotations(entries.stream().map(this::toScmAnnotations).collect(Collectors.toList())) - .transformation(transformation) - .build(); - } - - - private boolean oecdIn(String oecd, Set oecdsToApply) { - - if (oecd != null && oecdsToApply.contains(oecd)) { - return true; - } - return false; - } - - - public String getOecdNumber(FileModel file) { - - var fileAttributesConfig = fileAttributesClient.getFileAttributeConfigs(file.getDossierTemplateId()); - var oecdFileAttributeConf = fileAttributesConfig.stream().filter(f -> f.getLabel().equals("OECD Number")).map(f -> f.getId()).findFirst(); - if (oecdFileAttributeConf.isPresent()) { - return file.getFileAttributes().get(oecdFileAttributeConf.get()); - } - return null; - } - - - private SCMComponent getNumberOfAnimals(RedactionLog redactionLog) { - - String transformation = "Return value of 'number_of_animals' if present else return sum of unique 'animal_number' or else '' "; - - var numberOfAnimals = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("number_of_animals")).findFirst(); - - if (numberOfAnimals.isPresent()) { - return SCMComponent.builder() - .originalValue(numberOfAnimals.get().getValue()) - .scmAnnotations(List.of(toScmAnnotations(numberOfAnimals.get()))) - .transformation(transformation) - .build(); - } - - var uniqueAnimalNumbers = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("animal_number")).collect(Collectors.toSet()); - - if (uniqueAnimalNumbers.isEmpty()) { - return SCMComponent.builder().originalValue("").transformation(transformation).build(); - } - - int size = uniqueAnimalNumbers.stream().map(a -> a.getValue()).collect(Collectors.toSet()).size(); - - return SCMComponent.builder() - .originalValue(String.valueOf(size)) - .scmAnnotations(uniqueAnimalNumbers.stream().map(this::toScmAnnotations).collect(Collectors.toList())) - .transformation(transformation) - .build(); - } - - - private List getAsSentences(RedactionLog redactionLog, String type) { - - String transformation = String.format("Values of type '%s' as sentences", type); - - List sentences = new ArrayList<>(); - var typeStringsEntries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).collect(Collectors.toList()); - - if (typeStringsEntries.isEmpty()) { - return sentences; - } - - for (RedactionLogEntry typeStringEntry : typeStringsEntries) { - - BreakIterator iterator = BreakIterator.getSentenceInstance(Locale.US); - iterator.setText(typeStringEntry.getValue()); - int start = iterator.first(); - for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next()) { - - sentences.add(SCMComponent.builder() - .originalValue(typeStringEntry.getValue().substring(start, end).replaceAll("\\n", "").trim()) - .scmAnnotations(List.of(toScmAnnotations(typeStringEntry))) - .transformation(transformation) - .build()); - - } - } - - return sentences; - } - - - private SCMComponent getPerformingLaboratory(RedactionLog redactionLog) { - - String transformation = "Value of laboratory_name, combined with laboratory_country if distance is small"; - - var laboratoryEntry = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("laboratory_name")).findFirst(); - if (!laboratoryEntry.isPresent()) { - return SCMComponent.builder().originalValue("").transformation(transformation).build(); - } - - var laboratoryCountry = redactionLog.getRedactionLogEntry() - .stream() - .filter(r -> r.getType().equals("laboratory_country") && Math.abs(laboratoryEntry.get().getPositions().get(0).getTopLeft().getY() - r.getPositions() - .get(0) - .getTopLeft() - .getY()) < 80) - .collect(Collectors.toList()); - - RedactionLogEntry countryWithSmallestDistance = null; - for (var entry : laboratoryCountry) { - - if (countryWithSmallestDistance == null) { - countryWithSmallestDistance = entry; - } else if (Math.abs(laboratoryEntry.get().getPositions().get(0).getTopLeft().getY() - entry.getPositions().get(0).getTopLeft().getY()) < Math.abs(laboratoryEntry.get() - .getPositions() - .get(0) - .getTopLeft() - .getY() - countryWithSmallestDistance.getPositions().get(0).getTopLeft().getY())) { - countryWithSmallestDistance = entry; - } - - } - - List scmAnnotations = new ArrayList<>(); - scmAnnotations.add(toScmAnnotations(laboratoryEntry.get())); - - StringBuilder sb = new StringBuilder(); - if (laboratoryEntry.isPresent()) { - sb.append(laboratoryEntry.get().getValue()); - } - if (countryWithSmallestDistance != null) { - sb.append(", ").append(countryWithSmallestDistance.getValue()); - scmAnnotations.add(toScmAnnotations(countryWithSmallestDistance)); - } - - return SCMComponent.builder().originalValue(sb.toString().trim()).scmAnnotations(scmAnnotations).transformation(transformation).build(); - } - - - private SCMComponent ifPresentAddOrElse(RedactionLog redactionLog, String type, String presentValue, String elseValue) { - - String transformation = String.format("If type %s is present than '%s' else '%s'", type, presentValue, elseValue); - - var firstEntryOptional = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).findFirst(); - - if (firstEntryOptional.isPresent()) { - - var firstEntry = firstEntryOptional.get(); - return SCMComponent.builder().originalValue(presentValue).scmAnnotations(List.of(toScmAnnotations(firstEntry))).transformation(transformation).build(); - } - - return SCMComponent.builder().originalValue(elseValue).transformation(transformation).build(); - } - - - private SCMComponent getFirstEntryOrElse(RedactionLog redactionLog, String type, String elseValue) { - - String transformation = String.format("First found value of type '%s' or else '%s'", type, elseValue); - - var firstEntryOptional = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).findFirst(); - - if (firstEntryOptional.isPresent()) { - - var firstEntry = firstEntryOptional.get(); - return SCMComponent.builder().originalValue(firstEntry.getValue()).scmAnnotations(List.of(toScmAnnotations(firstEntry))).transformation(transformation).build(); - } - - return SCMComponent.builder().originalValue(elseValue).transformation(transformation).build(); } @@ -792,20 +860,6 @@ public class RSSPoc2Service { } - private SCMComponent getConvertedDates(RedactionLog redactionLog, String type) { - - List redactionLogEntries = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals(type)).collect(Collectors.toList()); - - String value = redactionLogEntries.stream().map(RedactionLogEntry::getValue).map(this::convertDate).collect(Collectors.joining(", ")); - - return SCMComponent.builder() - .originalValue(value) - .scmAnnotations(redactionLogEntries.stream().map(this::toScmAnnotations).collect(Collectors.toList())) - .transformation(String.format("Convert values of type '%s' to dd/MM/yyyy joined with ', '", type)) - .build(); - } - - @SuppressWarnings("PMD.EmptyCatchBlock") private String convertDate(String dateAsString) { @@ -828,74 +882,17 @@ public class RSSPoc2Service { } - private SCMComponent getTestGuideline1(RedactionLog redactionLog) { + private Map getKeyContains(Map components, String compontentName) { - String transformation = "If 'oecd_guideline_number' and 'oecd_guideline_year' are present than mapped by provided mapping table else value of 'oecd_guideline' if present or else ''"; + Map resultMap = new LinkedHashMap<>(); - var guidelineNumber = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("oecd_guideline_number")).findFirst(); - var guidelineYear = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("oecd_guideline_year")).findFirst(); - - if (guidelineNumber.isPresent() && guidelineYear.isPresent()) { - var guidelinePair = Pair.of(guidelineNumber.get().getValue(), guidelineYear.get().getValue()); - if (guidelineMapping.containsKey(guidelinePair)) { - String value = guidelineMapping.get(guidelinePair); - return SCMComponent.builder() - .originalValue(value) - .scmAnnotations(List.of(toScmAnnotations(guidelineNumber.get()), toScmAnnotations(guidelineYear.get()))) - .transformation(transformation) - .build(); + for (Map.Entry entry : components.entrySet()) { + if (entry.getKey().contains(compontentName)) { + resultMap.put(entry.getKey(), entry.getValue()); } } - var guideline = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("oecd_guideline")).findFirst(); - - if (guideline.isPresent()) { - return SCMComponent.builder() - .originalValue(guideline.get().getValue()) - .scmAnnotations(List.of(toScmAnnotations(guideline.get()))) - .transformation(transformation) - .build(); - } - - return SCMComponent.builder().originalValue("").transformation(transformation).build(); - } - - - private SCMComponent getTestGuideline2(RedactionLog redactionLog) { - - String transformation = "Combine values of 'epa_guideline' and 'ec_guideline' with seperator ', '"; - - List guidelines = new ArrayList<>(); - guidelines.addAll(redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("epa_guideline")).collect(Collectors.toList())); - guidelines.addAll(redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("ec_guideline")).collect(Collectors.toList())); - - String value = guidelines.stream().map(RedactionLogEntry::getValue).collect(Collectors.joining(", ")); - - if (!value.isEmpty()) { - return SCMComponent.builder() - .originalValue(value) - .scmAnnotations(guidelines.stream().map(this::toScmAnnotations).collect(Collectors.toList())) - .transformation(transformation) - .build(); - } - - return SCMComponent.builder().originalValue("").transformation(transformation).build(); - } - - - private void sortRedactionLog(RedactionLog redactionLog) { - - redactionLog.getRedactionLogEntry().sort((entry1, entry2) -> { - if (entry1.getPositions().get(0).getPage() == entry2.getPositions().get(0).getPage()) { - if (entry1.getPositions().get(0).getTopLeft().getY() == entry2.getPositions().get(0).getTopLeft().getY()) { - return entry1.getPositions().get(0).getTopLeft().getX() <= entry2.getPositions().get(0).getTopLeft().getX() ? -1 : 1; - } else { - return entry1.getPositions().get(0).getTopLeft().getY() <= entry2.getPositions().get(0).getTopLeft().getY() ? 1 : -1; - } - } - return entry1.getPositions().get(0).getPage() < entry2.getPositions().get(0).getPage() ? -1 : 1; - }); - + return resultMap; } } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RSSService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RSSService.java index 46eef0a..5608aeb 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RSSService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RSSService.java @@ -164,65 +164,58 @@ public class RSSService { } - private String getRule5Endpoint(RedactionLog redactionLog) { + private String getRule46Attachments(RedactionLog redactionLog) { - var studyType = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("study_type")).map(RedactionLogEntry::getValue).findFirst(); + var attachments = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("attachments")).map(RedactionLogEntry::getValue).findFirst(); - if (studyType.isPresent()) { - return studyType.get(); + if (attachments.isPresent()) { + return "Yes"; } - var guideline = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("guideline")).map(RedactionLogEntry::getValue).findFirst(); - - if (guideline.isPresent()) { - return mapGuideline(guideline.get()); - } - - return ""; + return "None"; } - private String getRule7StudyPeriod(RedactionLog redactionLog) { - - var startDate = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("experimental_start_date")).map(RedactionLogEntry::getValue).findFirst(); - - var endDate = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("experimental_end_date")).map(RedactionLogEntry::getValue).findFirst(); + private String getRule42BodyWeight(RedactionLog redactionLog) { + var bodyWeights = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("body_weight")).map(RedactionLogEntry::getValue).collect(Collectors.toList()); StringBuilder sb = new StringBuilder(); - startDate.ifPresent(sb::append); - endDate.ifPresent(s -> sb.append(" to ").append(s)); - - return sb.toString(); - } - - - private String get9RationaleForReliabilityIncludingDeficiencies(RedactionLog redactionLog) { - - var guideline = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("guideline")).map(RedactionLogEntry::getValue).findFirst(); - - if (guideline.isPresent()) { - return "Guideline study"; + for (var bodyWeight : bodyWeights) { + sb.append(bodyWeight).append(" / "); } - return ""; + return sb.toString(); } - private String getRule14Reference(RedactionLog redactionLog) { + private String getRule41ClinicalSigns(RedactionLog redactionLog) { - var title = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("title")).map(RedactionLogEntry::getValue).collect(Collectors.joining(" ")); - var author = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("author")).map(RedactionLogEntry::getValue).findFirst(); - var completionDate = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("completion_date")).map(RedactionLogEntry::getValue).findFirst(); - - StringBuilder sb = new StringBuilder("Study report/"); - sb.append(title).append('/'); - author.ifPresent(s -> sb.append('/').append(s)); - completionDate.ifPresent(s -> sb.append('/').append(s)); + var clinicalSigns = redactionLog.getRedactionLogEntry() + .stream() + .filter(r -> r.getType().equals("clinical_signs")) + .map(RedactionLogEntry::getValue) + .collect(Collectors.toList()); + StringBuilder sb = new StringBuilder(); + for (var clinicalSign : clinicalSigns) { + sb.append(clinicalSign).append(" / "); + } return sb.toString(); } + private String getRule49Conclusions(RedactionLog redactionLog) { + + var conclusions = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("conclusion")).map(RedactionLogEntry::getValue).collect(Collectors.toList()); + + if (conclusions.isEmpty()) { + return ""; + } + + return conclusions.get(conclusions.size() - 1); + } + + private String getRule15DataAccess(RedactionLog redactionLog) { var sponsor = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("sponsor")).map(RedactionLogEntry::getValue).findFirst(); @@ -239,153 +232,6 @@ public class RSSService { } - private String getRule17Guideline(RedactionLog redactionLog) { - - var guidelines = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("guideline")).map(RedactionLogEntry::getValue).collect(Collectors.toSet()); - - StringBuilder stringBuilder = new StringBuilder(); - int i = 1; - - for (String guideline : guidelines) { - stringBuilder.append(i).append(") according to guideline ").append(guideline).append(" (").append(mapGuideline(guideline)).append(") "); - i++; - } - - return stringBuilder.toString(); - } - - - private String getRule19GlpCompliance(RedactionLog redactionLog) { - - var glpCompliance = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("glp_compliance")).map(RedactionLogEntry::getValue).findFirst(); - - return glpCompliance.map(s -> "Yes. " + s).orElse("No."); - - } - - - private String getRule20TestType(RedactionLog redactionLog) { - - var upAndDownProcedure = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("up_and_down_procedure")).map(RedactionLogEntry::getValue).findFirst(); - - if (upAndDownProcedure.isPresent()) { - return "Up down Procedure"; - } - - var guideline8701100 = redactionLog.getRedactionLogEntry() - .stream() - .filter(r -> r.getType().equals("guideline")) - .map(RedactionLogEntry::getValue) - .filter(g -> g.contains("870.1100")) - .findFirst(); - - if (guideline8701100.isPresent()) { - return "Up down Procedure"; - } - - return "No"; - } - - - private String getRule21LimitTest(RedactionLog redactionLog) { - - var limitTest = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("limit_test")).map(RedactionLogEntry::getValue).findFirst(); - - var noLimitTest = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("no_limit_test")).map(RedactionLogEntry::getValue).findFirst(); - - if (limitTest.isPresent() && noLimitTest.isEmpty()) { - return "Yes"; - } - - return "No"; - } - - - private String getRule22TestMaterialInformation(RedactionLog redactionLog) { - - var testSubstance = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("test_substance")).map(RedactionLogEntry::getValue).findFirst(); - - return testSubstance.map(s -> s + "/CAS number").orElse(""); - - } - - - private String getRule24SpecificDetailsOnTestMaterial(RedactionLog redactionLog) { - - var materials = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("materials")).map(RedactionLogEntry::getValue).collect(Collectors.toList()); - StringBuilder sb = new StringBuilder(); - for (var material : materials) { - sb.append(material).append(' '); - } - - return sb.toString(); - } - - - private String getRule25Species(RedactionLog redactionLog) { - - var species = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("species")).map(RedactionLogEntry::getValue).findFirst(); - - return species.orElse(""); - - } - - - private String getRule26Strain(RedactionLog redactionLog) { - - var strain = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("strain")).map(RedactionLogEntry::getValue).findFirst(); - - return strain.orElse(""); - - } - - - private String getRule27Sex(RedactionLog redactionLog) { - - var sex = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("sex")).map(RedactionLogEntry::getValue).findFirst(); - - return sex.orElse(""); - } - - - private String getRule28DetailsOnTestAnimalsTestSystemEnvironmentalConditions(RedactionLog redactionLog) { - - return redactionLog.getRedactionLogEntry() - .stream() - .filter(r -> r.getType().equals("test_animals")) - .sorted(Comparator.comparing(e -> e.getPositions().get(0).getTopLeft().getX())) - .sorted(Comparator.comparing(e -> e.getPositions().get(0).getTopLeft().getY(), Comparator.reverseOrder())) - .sorted(Comparator.comparing(e -> e.getPositions().get(0).getPage())) - .map(RedactionLogEntry::getValue) - .collect(Collectors.joining(" ")); - } - - - private String getRule29RouteOfAdministration(RedactionLog redactionLog) { - - var routeOfAdministration = redactionLog.getRedactionLogEntry() - .stream() - .filter(r -> r.getType().equals("route_of_administration")) - .map(RedactionLogEntry::getValue) - .findFirst(); - - return routeOfAdministration.orElse(""); - - } - - - private String getRule30Vehicle(RedactionLog redactionLog) { - - var vehicles = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("vehicle")).map(RedactionLogEntry::getValue).collect(Collectors.toList()); - - if (vehicles.isEmpty()) { - return "Not Applicable"; - } - - return String.join(" / ", vehicles); - } - - private String getRule31DetailsOfOralExposure(RedactionLog redactionLog) { var oralExposures = redactionLog.getRedactionLogEntry() @@ -402,64 +248,6 @@ public class RSSService { } - private String getRule32Doses(RedactionLog redactionLog) { - - var dosagesPerAnimal = redactionLog.getRedactionLogEntry() - .stream() - .filter(r -> r.getType().equals("dosage_per_animal")) - .map(r -> r.getValue().replaceAll("\\n", "").trim()) - .collect(Collectors.toSet()); - var dosages = redactionLog.getRedactionLogEntry() - .stream() - .filter(r -> r.getType().equals("dosage")) - .map(r -> r.getValue().replaceAll("\\n", "").trim()) - .collect(Collectors.toSet()); - - Set allDosages = new HashSet<>(); - allDosages.addAll(dosagesPerAnimal); - allDosages.addAll(dosages); - - StringBuilder sb = new StringBuilder(); - for (var dosagePerAnimal : allDosages) { - sb.append(dosagePerAnimal).append(" mg/kg bw").append(" , "); - } - - return sb.toString().trim(); - } - - - private String getRule33NoOfAnimalsPerSexPerDose(RedactionLog redactionLog) { - - var dosagesPerAnimal = redactionLog.getRedactionLogEntry() - .stream() - .filter(r -> r.getType().equals("dosage_per_animal")) - .map(RedactionLogEntry::getValue) - .collect(Collectors.toList()); - var uniqueDosagesPerAnimal = new HashSet<>(dosagesPerAnimal); - var uniqueAnimalNumbers = redactionLog.getRedactionLogEntry() - .stream() - .filter(r -> r.getType().equals("animal_number")) - .map(RedactionLogEntry::getValue) - .collect(Collectors.toSet()); - - if (uniqueDosagesPerAnimal.size() == 1 && uniqueAnimalNumbers.size() > 1) { - return uniqueAnimalNumbers.size() + " * " + uniqueDosagesPerAnimal.iterator().next() + " mg/kg bw"; - } - - Map> dosagesPerAnimalMap = new HashMap<>(); - for (var dosage : dosagesPerAnimal) { - dosagesPerAnimalMap.computeIfAbsent(dosage, (x) -> new ArrayList<>()).add(dosage); - } - - StringBuilder sb = new StringBuilder(); - for (Map.Entry> entry : dosagesPerAnimalMap.entrySet()) { - sb.append(entry.getValue().size()).append(" * ").append(entry.getKey()).append(" mg/kg bw, "); - } - - return sb.toString().trim(); - } - - private String getRule35DetailsOnStudyDesign(RedactionLog redactionLog) { var necropsy = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("necropsy")).map(RedactionLogEntry::getValue).findFirst(); @@ -502,43 +290,82 @@ public class RSSService { } - private String getRule40Mortality(RedactionLog redactionLog) { + private String getRule28DetailsOnTestAnimalsTestSystemEnvironmentalConditions(RedactionLog redactionLog) { - var mortalitys = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("mortality")).map(RedactionLogEntry::getValue).collect(Collectors.toList()); - StringBuilder sb = new StringBuilder(); - for (var mortality : mortalitys) { - sb.append(mortality).append(' '); - } - - return sb.toString(); - } - - - private String getRule41ClinicalSigns(RedactionLog redactionLog) { - - var clinicalSigns = redactionLog.getRedactionLogEntry() + return redactionLog.getRedactionLogEntry() .stream() - .filter(r -> r.getType().equals("clinical_signs")) + .filter(r -> r.getType().equals("test_animals")) + .sorted(Comparator.comparing(e -> e.getPositions().get(0).getTopLeft().getX())) + .sorted(Comparator.comparing(e -> e.getPositions().get(0).getTopLeft().getY(), Comparator.reverseOrder())) + .sorted(Comparator.comparing(e -> e.getPositions().get(0).getPage())) .map(RedactionLogEntry::getValue) - .collect(Collectors.toList()); - StringBuilder sb = new StringBuilder(); - for (var clinicalSign : clinicalSigns) { - sb.append(clinicalSign).append(" / "); - } - - return sb.toString(); + .collect(Collectors.joining(" ")); } - private String getRule42BodyWeight(RedactionLog redactionLog) { + private String getRule32Doses(RedactionLog redactionLog) { + + var dosagesPerAnimal = redactionLog.getRedactionLogEntry() + .stream() + .filter(r -> r.getType().equals("dosage_per_animal")) + .map(r -> r.getValue().replaceAll("\\n", "").trim()) + .collect(Collectors.toSet()); + var dosages = redactionLog.getRedactionLogEntry() + .stream() + .filter(r -> r.getType().equals("dosage")) + .map(r -> r.getValue().replaceAll("\\n", "").trim()) + .collect(Collectors.toSet()); + + Set allDosages = new HashSet<>(); + allDosages.addAll(dosagesPerAnimal); + allDosages.addAll(dosages); - var bodyWeights = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("body_weight")).map(RedactionLogEntry::getValue).collect(Collectors.toList()); StringBuilder sb = new StringBuilder(); - for (var bodyWeight : bodyWeights) { - sb.append(bodyWeight).append(" / "); + for (var dosagePerAnimal : allDosages) { + sb.append(dosagePerAnimal).append(" mg/kg bw").append(" , "); } - return sb.toString(); + return sb.toString().trim(); + } + + + private String getRule5Endpoint(RedactionLog redactionLog) { + + var studyType = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("study_type")).map(RedactionLogEntry::getValue).findFirst(); + + if (studyType.isPresent()) { + return studyType.get(); + } + + var guideline = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("guideline")).map(RedactionLogEntry::getValue).findFirst(); + + if (guideline.isPresent()) { + return mapGuideline(guideline.get()); + } + + return ""; + } + + + private String getRule50ExecutiveSummary(RedactionLog redactionLog) { + + return redactionLog.getRedactionLogEntry() + .stream() + .filter(r -> r.getType().equals("executive_summary")) + .sorted(Comparator.comparing(e -> e.getPositions().get(0).getTopLeft().getX())) + .sorted(Comparator.comparing(e -> e.getPositions().get(0).getTopLeft().getY(), Comparator.reverseOrder())) + .sorted(Comparator.comparing(e -> e.getPositions().get(0).getPage())) + .map(RedactionLogEntry::getValue) + .collect(Collectors.joining(" ")); + } + + + private String getRule19GlpCompliance(RedactionLog redactionLog) { + + var glpCompliance = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("glp_compliance")).map(RedactionLogEntry::getValue).findFirst(); + + return glpCompliance.map(s -> "Yes. " + s).orElse("No."); + } @@ -558,18 +385,6 @@ public class RSSService { } - private String getRule46Attachments(RedactionLog redactionLog) { - - var attachments = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("attachments")).map(RedactionLogEntry::getValue).findFirst(); - - if (attachments.isPresent()) { - return "Yes"; - } - - return "None"; - } - - private String getRule47Illustration(RedactionLog redactionLog) { var illustration = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("formula") || r.getType().equals("image")).findFirst(); @@ -580,28 +395,213 @@ public class RSSService { } - private String getRule49Conclusions(RedactionLog redactionLog) { + private String getRule21LimitTest(RedactionLog redactionLog) { - var conclusions = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("conclusion")).map(RedactionLogEntry::getValue).collect(Collectors.toList()); + var limitTest = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("limit_test")).map(RedactionLogEntry::getValue).findFirst(); - if (conclusions.isEmpty()) { - return ""; + var noLimitTest = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("no_limit_test")).map(RedactionLogEntry::getValue).findFirst(); + + if (limitTest.isPresent() && noLimitTest.isEmpty()) { + return "Yes"; } - return conclusions.get(conclusions.size() - 1); + return "No"; } - private String getRule50ExecutiveSummary(RedactionLog redactionLog) { + private String getRule40Mortality(RedactionLog redactionLog) { - return redactionLog.getRedactionLogEntry() + var mortalitys = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("mortality")).map(RedactionLogEntry::getValue).collect(Collectors.toList()); + StringBuilder sb = new StringBuilder(); + for (var mortality : mortalitys) { + sb.append(mortality).append(' '); + } + + return sb.toString(); + } + + + private String getRule33NoOfAnimalsPerSexPerDose(RedactionLog redactionLog) { + + var dosagesPerAnimal = redactionLog.getRedactionLogEntry() .stream() - .filter(r -> r.getType().equals("executive_summary")) - .sorted(Comparator.comparing(e -> e.getPositions().get(0).getTopLeft().getX())) - .sorted(Comparator.comparing(e -> e.getPositions().get(0).getTopLeft().getY(), Comparator.reverseOrder())) - .sorted(Comparator.comparing(e -> e.getPositions().get(0).getPage())) + .filter(r -> r.getType().equals("dosage_per_animal")) .map(RedactionLogEntry::getValue) - .collect(Collectors.joining(" ")); + .collect(Collectors.toList()); + var uniqueDosagesPerAnimal = new HashSet<>(dosagesPerAnimal); + var uniqueAnimalNumbers = redactionLog.getRedactionLogEntry() + .stream() + .filter(r -> r.getType().equals("animal_number")) + .map(RedactionLogEntry::getValue) + .collect(Collectors.toSet()); + + if (uniqueDosagesPerAnimal.size() == 1 && uniqueAnimalNumbers.size() > 1) { + return uniqueAnimalNumbers.size() + " * " + uniqueDosagesPerAnimal.iterator().next() + " mg/kg bw"; + } + + Map> dosagesPerAnimalMap = new HashMap<>(); + for (var dosage : dosagesPerAnimal) { + dosagesPerAnimalMap.computeIfAbsent(dosage, (x) -> new ArrayList<>()).add(dosage); + } + + StringBuilder sb = new StringBuilder(); + for (Map.Entry> entry : dosagesPerAnimalMap.entrySet()) { + sb.append(entry.getValue().size()).append(" * ").append(entry.getKey()).append(" mg/kg bw, "); + } + + return sb.toString().trim(); + } + + + private String get9RationaleForReliabilityIncludingDeficiencies(RedactionLog redactionLog) { + + var guideline = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("guideline")).map(RedactionLogEntry::getValue).findFirst(); + + if (guideline.isPresent()) { + return "Guideline study"; + } + + return ""; + } + + + private String getRule14Reference(RedactionLog redactionLog) { + + var title = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("title")).map(RedactionLogEntry::getValue).collect(Collectors.joining(" ")); + var author = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("author")).map(RedactionLogEntry::getValue).findFirst(); + var completionDate = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("completion_date")).map(RedactionLogEntry::getValue).findFirst(); + + StringBuilder sb = new StringBuilder("Study report/"); + sb.append(title).append('/'); + author.ifPresent(s -> sb.append('/').append(s)); + completionDate.ifPresent(s -> sb.append('/').append(s)); + + return sb.toString(); + } + + + private String getRule29RouteOfAdministration(RedactionLog redactionLog) { + + var routeOfAdministration = redactionLog.getRedactionLogEntry() + .stream() + .filter(r -> r.getType().equals("route_of_administration")) + .map(RedactionLogEntry::getValue) + .findFirst(); + + return routeOfAdministration.orElse(""); + + } + + + private String getRule27Sex(RedactionLog redactionLog) { + + var sex = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("sex")).map(RedactionLogEntry::getValue).findFirst(); + + return sex.orElse(""); + } + + + private String getRule25Species(RedactionLog redactionLog) { + + var species = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("species")).map(RedactionLogEntry::getValue).findFirst(); + + return species.orElse(""); + + } + + + private String getRule24SpecificDetailsOnTestMaterial(RedactionLog redactionLog) { + + var materials = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("materials")).map(RedactionLogEntry::getValue).collect(Collectors.toList()); + StringBuilder sb = new StringBuilder(); + for (var material : materials) { + sb.append(material).append(' '); + } + + return sb.toString(); + } + + + private String getRule26Strain(RedactionLog redactionLog) { + + var strain = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("strain")).map(RedactionLogEntry::getValue).findFirst(); + + return strain.orElse(""); + + } + + + private String getRule7StudyPeriod(RedactionLog redactionLog) { + + var startDate = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("experimental_start_date")).map(RedactionLogEntry::getValue).findFirst(); + + var endDate = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("experimental_end_date")).map(RedactionLogEntry::getValue).findFirst(); + + StringBuilder sb = new StringBuilder(); + startDate.ifPresent(sb::append); + endDate.ifPresent(s -> sb.append(" to ").append(s)); + + return sb.toString(); + } + + + private String getRule17Guideline(RedactionLog redactionLog) { + + var guidelines = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("guideline")).map(RedactionLogEntry::getValue).collect(Collectors.toSet()); + + StringBuilder stringBuilder = new StringBuilder(); + int i = 1; + + for (String guideline : guidelines) { + stringBuilder.append(i).append(") according to guideline ").append(guideline).append(" (").append(mapGuideline(guideline)).append(") "); + i++; + } + + return stringBuilder.toString(); + } + + + private String getRule22TestMaterialInformation(RedactionLog redactionLog) { + + var testSubstance = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("test_substance")).map(RedactionLogEntry::getValue).findFirst(); + + return testSubstance.map(s -> s + "/CAS number").orElse(""); + + } + + + private String getRule20TestType(RedactionLog redactionLog) { + + var upAndDownProcedure = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("up_and_down_procedure")).map(RedactionLogEntry::getValue).findFirst(); + + if (upAndDownProcedure.isPresent()) { + return "Up down Procedure"; + } + + var guideline8701100 = redactionLog.getRedactionLogEntry() + .stream() + .filter(r -> r.getType().equals("guideline")) + .map(RedactionLogEntry::getValue) + .filter(g -> g.contains("870.1100")) + .findFirst(); + + if (guideline8701100.isPresent()) { + return "Up down Procedure"; + } + + return "No"; + } + + + private String getRule30Vehicle(RedactionLog redactionLog) { + + var vehicles = redactionLog.getRedactionLogEntry().stream().filter(r -> r.getType().equals("vehicle")).map(RedactionLogEntry::getValue).collect(Collectors.toList()); + + if (vehicles.isEmpty()) { + return "Not Applicable"; + } + + return String.join(" / ", vehicles); } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RedactionLogConverterService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RedactionLogConverterService.java index 6b5d3ef..bd0f691 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RedactionLogConverterService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/RedactionLogConverterService.java @@ -162,30 +162,14 @@ public class RedactionLogConverterService { } - private String checkTextForNull(String text) { - - if (text == null) { - return ""; - } - return text; - - } - - - private String humanize(String label) { - - String str = label; - str = str.replaceAll("-+?", " "); - str = str.replaceAll("_+?", " "); - str = str.replaceAll(" +", " "); - - StringBuilder stringBuilder = new StringBuilder(); - Matcher match = Pattern.compile("([a-z])([a-z]*)", Pattern.CASE_INSENSITIVE).matcher(str); - while (match.find()) { - match.appendReplacement(stringBuilder, match.group(1).toUpperCase() + match.group(2)); - } - return match.appendTail(stringBuilder).toString(); + /* + This method catches types like hint_only or published_information + */ + private boolean isHintType(List types, String type) { + var matchingTypes = getMatchingTypes(types, type); + Optional foundType = matchingTypes.stream().findFirst(); + return foundType.map(Type::isHint).orElse(false); } @@ -207,14 +191,13 @@ public class RedactionLogConverterService { } - /* - This method catches types like hint_only or published_information - */ - private boolean isHintType(List types, String type) { + private String checkTextForNull(String text) { + + if (text == null) { + return ""; + } + return text; - var matchingTypes = getMatchingTypes(types, type); - Optional foundType = matchingTypes.stream().findFirst(); - return foundType.map(Type::isHint).orElse(false); } @@ -223,4 +206,21 @@ public class RedactionLogConverterService { return types.stream().filter(t -> t.getType().equals(type)).collect(Collectors.toList()); } + + private String humanize(String label) { + + String str = label; + str = str.replaceAll("-+?", " "); + str = str.replaceAll("_+?", " "); + str = str.replaceAll(" +", " "); + + StringBuilder stringBuilder = new StringBuilder(); + Matcher match = Pattern.compile("([a-z])([a-z]*)", Pattern.CASE_INSENSITIVE).matcher(str); + while (match.find()) { + match.appendReplacement(stringBuilder, match.group(1).toUpperCase() + match.group(2)); + } + return match.appendTail(stringBuilder).toString(); + + } + } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportGenerationService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportGenerationService.java index 14c032c..c3d21a3 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportGenerationService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportGenerationService.java @@ -228,8 +228,10 @@ public class ReportGenerationService { } - private void generateSingleFileReports(List singleFilesTemplates, List storedFileInformation, - Dossier dossier, PlaceholderModel placeholderModel, + private void generateSingleFileReports(List singleFilesTemplates, + List storedFileInformation, + Dossier dossier, + PlaceholderModel placeholderModel, String downloadId, FileModel fileStatus, List reportEntries) { @@ -291,11 +293,6 @@ public class ReportGenerationService { } - - - - - @FieldDefaults(makeFinal = true, level = AccessLevel.PUBLIC) private static final class ReportTemplates { diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportMessageReceiver.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportMessageReceiver.java index 49df087..6db47c0 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportMessageReceiver.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportMessageReceiver.java @@ -10,7 +10,6 @@ import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.stereotype.Service; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.iqser.red.service.redaction.report.v1.api.model.ReportRequestMessage; import com.iqser.red.service.redaction.report.v1.api.model.ReportResultMessage; @@ -54,16 +53,10 @@ public class ReportMessageReceiver { private void addToReportResultQueue(String userId, String downloadId, String reportFileInformationStorageId, int priority) { - try { - rabbitTemplate.convertAndSend(REPORT_RESULT_QUEUE, - objectMapper.writeValueAsString(new ReportResultMessage(userId, downloadId, reportFileInformationStorageId)), - message -> { - message.getMessageProperties().setPriority(priority); - return message; - }); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } + rabbitTemplate.convertAndSend(REPORT_RESULT_QUEUE, new ReportResultMessage(userId, downloadId, reportFileInformationStorageId), message -> { + message.getMessageProperties().setPriority(priority); + return message; + }); } } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/storage/ReportStorageService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/storage/ReportStorageService.java index 8516a60..1aabe64 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/storage/ReportStorageService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/storage/ReportStorageService.java @@ -10,8 +10,8 @@ import org.springframework.stereotype.Service; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; import com.iqser.red.service.redaction.report.v1.api.model.StoredFileInformation; -import com.iqser.red.service.redaction.report.v1.server.multitenancy.TenantContext; import com.iqser.red.storage.commons.service.StorageService; +import com.knecon.fforesight.tenantcommons.TenantContext; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/storage/StorageIdUtils.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/storage/StorageIdUtils.java index 21a8864..e1f1e9d 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/storage/StorageIdUtils.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/storage/StorageIdUtils.java @@ -4,20 +4,21 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp public final class StorageIdUtils { + private StorageIdUtils() { + + throw new IllegalStateException("Utility class"); + } + + public static String getStorageId(String downloadId, String tmpFilename) { return downloadId.substring(0, downloadId.length() - 3) + "/" + tmpFilename; } + public static String getStorageId(String dossierId, String fileId, FileType fileType) { return dossierId + "/" + fileId + "." + fileType.name() + fileType.getExtension(); } - - private StorageIdUtils() { - - throw new IllegalStateException("Utility class"); - } - } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/application-dev.yml b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/application-dev.yml index 94d5f4c..0a853a5 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/application-dev.yml +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/application-dev.yml @@ -2,4 +2,5 @@ server: port: 8084 -persistence-service.url: "http://persistence-service-v1:8080" \ No newline at end of file +persistence-service.url: "http://localhost:8085" +tenant-user-management-service.url: "http://localhost:8091/internal" diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/application.yml b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/application.yml index cf3fcf4..2dbf3ac 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/application.yml +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/application.yml @@ -2,6 +2,8 @@ info: description: Redaction Report Server v1 persistence-service.url: "http://persistence-service-v1:8080" +tenant-user-management-service.url: "http://tenant-user-management-service:8080/internal" +fforesight.tenants.remote: true server: port: 8080 @@ -35,4 +37,4 @@ management: metrics.export.prometheus.enabled: ${monitoring.enabled:false} storage: - backend: 's3' \ No newline at end of file + backend: 's3' diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/PlaceholderTest.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/PlaceholderTest.java index b8026ee..1aab64c 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/PlaceholderTest.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/PlaceholderTest.java @@ -33,6 +33,7 @@ import com.iqser.red.service.redaction.report.v1.server.service.PlaceholderServi import com.iqser.red.service.redaction.report.v1.server.storage.ReportStorageService; import com.iqser.red.storage.commons.StorageAutoConfiguration; import com.iqser.red.storage.commons.service.StorageService; +import com.knecon.fforesight.tenantcommons.TenantsClient; @ExtendWith(SpringExtension.class) @EnableAutoConfiguration(exclude = {/*StorageAutoConfiguration.class, */RabbitAutoConfiguration.class}) @@ -40,6 +41,9 @@ import com.iqser.red.storage.commons.service.StorageService; @SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class PlaceholderTest { + @MockBean + TenantsClient tenantsClient; + @Autowired private PlaceholderService placeholderService; diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java index 1dd11de..c062181 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java @@ -71,6 +71,7 @@ import com.iqser.red.service.redaction.report.v1.server.service.WordReportGenera import com.iqser.red.service.redaction.report.v1.server.storage.ReportStorageService; import com.iqser.red.storage.commons.StorageAutoConfiguration; import com.iqser.red.storage.commons.service.StorageService; +import com.knecon.fforesight.tenantcommons.TenantsClient; import lombok.SneakyThrows; @@ -80,6 +81,9 @@ import lombok.SneakyThrows; @ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = StorageAutoConfiguration.class)}) public class RedactionReportIntegrationTest { + @MockBean + TenantsClient tenantsClient; + @Autowired private ObjectMapper objectMapper; diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportV2IntegrationTest.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportV2IntegrationTest.java index bcac01e..2de77b8 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportV2IntegrationTest.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportV2IntegrationTest.java @@ -55,12 +55,13 @@ import com.iqser.red.service.redaction.report.v1.server.client.FileStatusClient; import com.iqser.red.service.redaction.report.v1.server.client.RedactionLogClient; import com.iqser.red.service.redaction.report.v1.server.client.ReportTemplateClient; import com.iqser.red.service.redaction.report.v1.server.configuration.MessagingConfiguration; -import com.iqser.red.service.redaction.report.v1.server.multitenancy.TenantContext; import com.iqser.red.service.redaction.report.v1.server.service.ReportGenerationService; import com.iqser.red.service.redaction.report.v1.server.utils.FileSystemBackedStorageService; import com.iqser.red.service.redaction.report.v1.server.utils.MetricValidationUtils; import com.iqser.red.storage.commons.StorageAutoConfiguration; import com.iqser.red.storage.commons.service.StorageService; +import com.knecon.fforesight.tenantcommons.TenantContext; +import com.knecon.fforesight.tenantcommons.TenantsClient; import io.micrometer.prometheus.PrometheusMeterRegistry; import lombok.SneakyThrows; @@ -73,6 +74,9 @@ import lombok.extern.slf4j.Slf4j; @AutoConfigureObservability public class RedactionReportV2IntegrationTest { + @MockBean + TenantsClient tenantsClient; + @MockBean private RabbitTemplate rabbitTemplate;