RED-4512: Implemented multitenancy for persistence
This commit is contained in:
parent
a4781dba7d
commit
0adf8026ce
@ -0,0 +1,19 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.model.multitenancy;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Tenant {
|
||||
|
||||
private String tenantId;
|
||||
private String jdbcUrl;
|
||||
private String user;
|
||||
private String password;
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.resources;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.multitenancy.Tenant;
|
||||
|
||||
public interface TenantsResource {
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping("/tenants")
|
||||
void createTenant(@RequestBody Tenant tenant);
|
||||
|
||||
|
||||
}
|
||||
@ -1,29 +1,16 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor;
|
||||
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.cloud.openfeign.support.PageJacksonModule;
|
||||
import org.springframework.cloud.openfeign.support.SortJacksonModule;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.client.PDFTronRedactionClient;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.CommentEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.audit.AuditEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.ColorsEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.download.DownloadStatusEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.index.IndexInformationEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.migration.MigrationEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.notification.NotificationEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ColorsRepository;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EntityScan(basePackageClasses = {CommentEntity.class, AuditEntity.class, NotificationEntity.class, ColorsEntity.class, DossierEntity.class, DownloadStatusEntity.class, MigrationEntity.class, IndexInformationEntity.class})
|
||||
@EnableJpaRepositories(basePackageClasses = ColorsRepository.class)
|
||||
@EnableFeignClients(basePackageClasses = {PDFTronRedactionClient.class})
|
||||
public class PersistenceServiceProcessorConfiguration {
|
||||
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.multitenancy.entity;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table(name = "tenant")
|
||||
public class TenantEntity {
|
||||
|
||||
@Id
|
||||
private String tenantId;
|
||||
@Column
|
||||
private String jdbcUrl;
|
||||
@Column(name = "username")
|
||||
private String user;
|
||||
@Column
|
||||
private String password;
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy;
|
||||
|
||||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
|
||||
@Component("currentTenantIdentifierResolver")
|
||||
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
|
||||
|
||||
@Override
|
||||
public String resolveCurrentTenantIdentifier() {
|
||||
String tenantId = TenantContext.getTenantId();
|
||||
if (tenantId != null && !tenantId.isEmpty()) {
|
||||
return tenantId;
|
||||
} else {
|
||||
// Allow bootstrapping the EntityManagerFactory, in which case no tenant is needed
|
||||
return "BOOTSTRAP";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateExistingCurrentSessions() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,105 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.engine.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.cache.RemovalListener;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.multitenancy.entity.TenantEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.EncryptionDecryptionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DynamicDataSourceBasedMultiTenantConnectionProvider extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
|
||||
|
||||
private static final String TENANT_POOL_NAME_SUFFIX = "DataSource";
|
||||
|
||||
private final DataSource masterDataSource;
|
||||
private final DataSourceProperties masterDataSourceProperties;
|
||||
private final TenantRepository masterTenantRepository;
|
||||
private final EncryptionDecryptionService encryptionService;
|
||||
|
||||
@Value("${multitenancy.datasource-cache.maximumSize:100}")
|
||||
private Long maximumSize;
|
||||
|
||||
@Value("${multitenancy.datasource-cache.expireAfterAccess:10}")
|
||||
private Integer expireAfterAccess;
|
||||
|
||||
private LoadingCache<String, DataSource> tenantDataSources;
|
||||
|
||||
|
||||
@PostConstruct
|
||||
protected void createCache() {
|
||||
|
||||
tenantDataSources = CacheBuilder.newBuilder()
|
||||
.maximumSize(maximumSize)
|
||||
.expireAfterAccess(expireAfterAccess, TimeUnit.MINUTES)
|
||||
.removalListener((RemovalListener<String, DataSource>) removal -> {
|
||||
HikariDataSource ds = (HikariDataSource) removal.getValue();
|
||||
ds.close(); // tear down properly
|
||||
log.info("Closed datasource: {}", ds.getPoolName());
|
||||
})
|
||||
.build(new CacheLoader<String, DataSource>() {
|
||||
public DataSource load(String key) {
|
||||
|
||||
TenantEntity tenant = masterTenantRepository.findByTenantId(key)
|
||||
.orElseThrow(() -> new RuntimeException("No such tenant: " + key));
|
||||
return createAndConfigureDataSource(tenant);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected DataSource selectAnyDataSource() {
|
||||
|
||||
return masterDataSource;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DataSource selectDataSource(String tenantIdentifier) {
|
||||
|
||||
try {
|
||||
return tenantDataSources.get(tenantIdentifier);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException("Failed to load DataSource for tenant: " + tenantIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private DataSource createAndConfigureDataSource(TenantEntity tenant) {
|
||||
|
||||
String decryptedPassword = encryptionService.decrypt(tenant.getPassword());
|
||||
|
||||
HikariDataSource ds = masterDataSourceProperties.initializeDataSourceBuilder()
|
||||
.type(HikariDataSource.class)
|
||||
.build();
|
||||
|
||||
ds.setUsername(tenant.getUser());
|
||||
ds.setPassword(decryptedPassword);
|
||||
ds.setJdbcUrl(tenant.getJdbcUrl());
|
||||
|
||||
ds.setPoolName(tenant.getTenantId() + TENANT_POOL_NAME_SUFFIX);
|
||||
|
||||
log.info("Configured datasource: {}", ds.getPoolName());
|
||||
return ds;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.multitenancy.entity.TenantEntity;
|
||||
|
||||
public interface TenantRepository extends JpaRepository<TenantEntity, String> {
|
||||
|
||||
@Query("select t from TenantEntity t where t.tenantId = :tenantId")
|
||||
Optional<TenantEntity> findByTenantId(@Param("tenantId") String tenantId);
|
||||
}
|
||||
@ -1,17 +1,7 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.utils.jdbc;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import static org.apache.commons.lang3.StringUtils.capitalize;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Table;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.PreparedStatement;
|
||||
@ -21,7 +11,22 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.capitalize;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.DynamicDataSourceBasedMultiTenantConnectionProvider;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@ -35,7 +40,12 @@ public class JDBCWriteUtils {
|
||||
|
||||
private final EntityManager entityManager;
|
||||
|
||||
private final DynamicDataSourceBasedMultiTenantConnectionProvider dynamicDataSourceBasedMultiTenantConnectionProvider;
|
||||
|
||||
public <T> void saveBatch(final List<T> entities) {
|
||||
|
||||
jdbcTemplate.setDataSource(dynamicDataSourceBasedMultiTenantConnectionProvider.selectDataSource(TenantContext.getTenantId()));
|
||||
|
||||
if (entities.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public final class TenantContext {
|
||||
|
||||
private static InheritableThreadLocal<String> 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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,15 +1,11 @@
|
||||
package com.iqser.red.service.peristence.v1.server;
|
||||
|
||||
import com.iqser.red.commons.spring.DefaultWebMvcConfiguration;
|
||||
import com.iqser.red.service.peristence.v1.server.client.RedactionClient;
|
||||
import com.iqser.red.service.peristence.v1.server.configuration.CleanupDownloadSchedulerConfiguration;
|
||||
import com.iqser.red.service.peristence.v1.server.configuration.MessagingConfiguration;
|
||||
import com.iqser.red.service.peristence.v1.server.settings.FileManagementServiceSettings;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.PersistenceServiceProcessorConfiguration;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
@ -22,12 +18,20 @@ import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.client.RedactionClient;
|
||||
import com.iqser.red.service.peristence.v1.server.configuration.CleanupDownloadSchedulerConfiguration;
|
||||
import com.iqser.red.service.peristence.v1.server.configuration.MessagingConfiguration;
|
||||
import com.iqser.red.service.peristence.v1.server.multitenancy.AsyncConfig;
|
||||
import com.iqser.red.service.peristence.v1.server.multitenancy.MultiTenancyWebConfiguration;
|
||||
import com.iqser.red.service.peristence.v1.server.settings.FileManagementServiceSettings;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.PersistenceServiceProcessorConfiguration;
|
||||
|
||||
@EnableAsync
|
||||
@EnableRetry
|
||||
@EnableScheduling
|
||||
@EnableConfigurationProperties(FileManagementServiceSettings.class)
|
||||
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class, CassandraAutoConfiguration.class})
|
||||
@Import({DefaultWebMvcConfiguration.class, PersistenceServiceProcessorConfiguration.class, MessagingConfiguration.class, CleanupDownloadSchedulerConfiguration.class})
|
||||
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class, CassandraAutoConfiguration.class, DataSourceAutoConfiguration.class, LiquibaseAutoConfiguration.class})
|
||||
@Import({MultiTenancyWebConfiguration.class, PersistenceServiceProcessorConfiguration.class, MessagingConfiguration.class, CleanupDownloadSchedulerConfiguration.class, AsyncConfig.class})
|
||||
@EnableFeignClients(basePackageClasses = {RedactionClient.class})
|
||||
public class Application {
|
||||
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
package com.iqser.red.service.peristence.v1.server.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.service.TenantManagementService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.multitenancy.Tenant;
|
||||
import com.iqser.red.service.persistence.service.v1.api.resources.TenantsResource;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class TenantsController implements TenantsResource {
|
||||
|
||||
private final TenantManagementService tenantManagementService;
|
||||
|
||||
|
||||
@PostMapping("/tenants")
|
||||
public void createTenant(@RequestBody Tenant tenant) {
|
||||
|
||||
tenantManagementService.createTenant(tenant);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,14 +1,14 @@
|
||||
package com.iqser.red.service.peristence.v1.server.migration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Data
|
||||
@RestController
|
||||
|
||||
@ -11,6 +11,8 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.settings.FileManagementServiceSettings;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.MigrationPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -24,26 +26,39 @@ public class MigrationStarterService {
|
||||
private final FileManagementServiceSettings settings;
|
||||
private final ApplicationContext ctx;
|
||||
private final MigrationPersistenceService migrationPersistenceService;
|
||||
private final TenantRepository tenantRepository;
|
||||
|
||||
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void migrate() {
|
||||
|
||||
//This is always running on startup
|
||||
seedMigration();
|
||||
tenantRepository.findAll().forEach(tenant -> {
|
||||
|
||||
TenantContext.setTenantId(tenant.getTenantId());
|
||||
|
||||
//This is always running on startup
|
||||
seedMigration();
|
||||
});
|
||||
|
||||
// This should only run in post upgrade hook
|
||||
if (settings.isMigrateOnly()) {
|
||||
log.info("Start migration");
|
||||
|
||||
migrations.sort(Comparator.comparing(Migration::getVersion));
|
||||
tenantRepository.findAll().forEach(tenant -> {
|
||||
|
||||
for (var migration : migrations) {
|
||||
migration.run();
|
||||
}
|
||||
TenantContext.setTenantId(tenant.getTenantId());
|
||||
|
||||
log.info("Start migration for tentant: " + tenant);
|
||||
|
||||
migrations.sort(Comparator.comparing(Migration::getVersion));
|
||||
|
||||
for (var migration : migrations) {
|
||||
migration.run();
|
||||
}
|
||||
});
|
||||
|
||||
log.info("Migration is finished");
|
||||
System.exit(SpringApplication.exit(ctx, () -> 0));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,20 @@
|
||||
package com.iqser.red.service.peristence.v1.server.migration.migrations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.migration.Migration;
|
||||
import com.iqser.red.service.peristence.v1.server.service.ManualRedactionProviderService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Setter
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
package com.iqser.red.service.peristence.v1.server.migration.migrations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.iqser.red.service.peristence.v1.server.migration.Migration;
|
||||
@ -9,12 +14,9 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileType;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Slf4j
|
||||
@Setter
|
||||
|
||||
@ -1,18 +1,20 @@
|
||||
package com.iqser.red.service.peristence.v1.server.migration.migrations;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.migration.Migration;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.BaseDictionaryEntry;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.TypeEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.type.DictionaryEntryType;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Slf4j
|
||||
@Setter
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
package com.iqser.red.service.peristence.v1.server.migration.migrations;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.migration.Migration;
|
||||
import com.iqser.red.service.peristence.v1.server.service.IndexingService;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Setter
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
package com.iqser.red.service.peristence.v1.server.migration.migrations;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.migration.Migration;
|
||||
import com.iqser.red.service.peristence.v1.server.service.FileManagementStorageService;
|
||||
import com.iqser.red.service.peristence.v1.server.service.FileStatusService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileType;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
package com.iqser.red.service.peristence.v1.server.migration.migrations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.controller.ManualRedactionController;
|
||||
import com.iqser.red.service.peristence.v1.server.migration.Migration;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Slf4j
|
||||
@Setter
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
package com.iqser.red.service.peristence.v1.server.migration.migrations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.controller.DictionaryController;
|
||||
import com.iqser.red.service.peristence.v1.server.migration.Migration;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.BaseDictionaryEntry;
|
||||
@ -7,17 +17,9 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.type.DictionaryEntryType;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Setter
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
package com.iqser.red.service.peristence.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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.iqser.red.service.peristence.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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.iqser.red.service.peristence.v1.server.multitenancy;
|
||||
|
||||
import org.springframework.core.task.TaskDecorator;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.iqser.red.service.peristence.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;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
|
||||
@Component
|
||||
public class TenantInterceptor implements WebRequestInterceptor {
|
||||
|
||||
public static final String DEFAULT_TENANT = "redaction";
|
||||
|
||||
|
||||
@Override
|
||||
public void preHandle(WebRequest request) {
|
||||
|
||||
String tenantId = null;
|
||||
if (request.getHeader("X-TENANT-ID") != null) {
|
||||
tenantId = request.getHeader("X-TENANT-ID");
|
||||
} else {
|
||||
tenantId = DEFAULT_TENANT; // TODO Remove if multitenancy is fully integrated.
|
||||
}
|
||||
TenantContext.setTenantId(tenantId);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void postHandle(WebRequest request, ModelMap model) {
|
||||
|
||||
TenantContext.clear();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterCompletion(WebRequest request, Exception ex) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
package com.iqser.red.service.peristence.v1.server.multitenancy.persistence;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseDataSource;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.orm.hibernate5.SpringBeanContainer;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
import liquibase.integration.spring.SpringLiquibase;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaRepositories(basePackageClasses = TenantRepository.class, entityManagerFactoryRef = "masterEntityManagerFactory", transactionManagerRef = "masterTransactionManager")
|
||||
@EnableConfigurationProperties({DataSourceProperties.class, JpaProperties.class})
|
||||
@RequiredArgsConstructor
|
||||
public class MasterPersistenceConfig {
|
||||
|
||||
private final ConfigurableListableBeanFactory beanFactory;
|
||||
private final JpaProperties jpaProperties;
|
||||
private final String entityPackages = "com.iqser.red.service.persistence.management.v1.processor.multitenancy.entity";
|
||||
|
||||
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean masterEntityManagerFactory(
|
||||
@Qualifier("masterDataSource") DataSource dataSource) {
|
||||
|
||||
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
|
||||
|
||||
em.setPersistenceUnitName("master-persistence-unit");
|
||||
em.setPackagesToScan(entityPackages);
|
||||
em.setDataSource(dataSource);
|
||||
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>(this.jpaProperties.getProperties());
|
||||
properties.put(AvailableSettings.PHYSICAL_NAMING_STRATEGY, "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
|
||||
properties.put(AvailableSettings.IMPLICIT_NAMING_STRATEGY, "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
|
||||
properties.put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(this.beanFactory));
|
||||
em.setJpaPropertyMap(properties);
|
||||
|
||||
return em;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public JpaTransactionManager masterTransactionManager(
|
||||
@Qualifier("masterEntityManagerFactory") EntityManagerFactory emf) {
|
||||
|
||||
JpaTransactionManager transactionManager = new JpaTransactionManager();
|
||||
transactionManager.setEntityManagerFactory(emf);
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("multitenancy.master.liquibase")
|
||||
public LiquibaseProperties masterLiquibaseProperties() {
|
||||
|
||||
return new LiquibaseProperties();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public SpringLiquibase masterLiquibase(@LiquibaseDataSource ObjectProvider<DataSource> liquibaseDataSource) {
|
||||
|
||||
LiquibaseProperties liquibaseProperties = masterLiquibaseProperties();
|
||||
SpringLiquibase liquibase = new SpringLiquibase();
|
||||
liquibase.setDataSource(liquibaseDataSource.getIfAvailable());
|
||||
liquibase.setChangeLog(liquibaseProperties.getChangeLog());
|
||||
liquibase.setContexts(liquibaseProperties.getContexts());
|
||||
return liquibase;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("multitenancy.master.datasource")
|
||||
public DataSourceProperties masterDataSourceProperties() {
|
||||
|
||||
return new DataSourceProperties();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@LiquibaseDataSource
|
||||
@ConfigurationProperties("multitenancy.master.datasource.hikari")
|
||||
public DataSource masterDataSource() {
|
||||
|
||||
HikariDataSource dataSource = masterDataSourceProperties().initializeDataSourceBuilder()
|
||||
.type(HikariDataSource.class)
|
||||
.build();
|
||||
dataSource.setPoolName("masterDataSource");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
package com.iqser.red.service.peristence.v1.server.multitenancy.persistence;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.orm.hibernate5.SpringBeanContainer;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.EncryptionDecryptionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.CurrentTenantIdentifierResolverImpl;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.DynamicDataSourceBasedMultiTenantConnectionProvider;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ColorsRepository;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaRepositories(basePackageClasses = ColorsRepository.class, entityManagerFactoryRef = "tenantEntityManagerFactory", transactionManagerRef = "tenantTransactionManager")
|
||||
@EnableConfigurationProperties(JpaProperties.class)
|
||||
@RequiredArgsConstructor
|
||||
public class TenantPersistenceConfig {
|
||||
|
||||
private final ConfigurableListableBeanFactory beanFactory;
|
||||
private final JpaProperties jpaProperties;
|
||||
private final String entityPackages = "com.iqser.red.service.persistence.management.v1.processor.entity";
|
||||
|
||||
|
||||
@Primary
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean tenantEntityManagerFactory(
|
||||
DynamicDataSourceBasedMultiTenantConnectionProvider connectionProvider,
|
||||
CurrentTenantIdentifierResolverImpl tenantResolver) {
|
||||
|
||||
LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
|
||||
emfBean.setPersistenceUnitName("tenant-persistence-unit");
|
||||
emfBean.setPackagesToScan(entityPackages);
|
||||
emfBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>(this.jpaProperties.getProperties());
|
||||
properties.put(AvailableSettings.PHYSICAL_NAMING_STRATEGY, "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
|
||||
properties.put(AvailableSettings.IMPLICIT_NAMING_STRATEGY, "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
|
||||
properties.put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(this.beanFactory));
|
||||
properties.put(AvailableSettings.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
|
||||
properties.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
|
||||
properties.put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
|
||||
emfBean.setJpaPropertyMap(properties);
|
||||
|
||||
return emfBean;
|
||||
}
|
||||
|
||||
|
||||
@Primary
|
||||
@Bean
|
||||
public JpaTransactionManager tenantTransactionManager(
|
||||
@Qualifier("tenantEntityManagerFactory") EntityManagerFactory emf) {
|
||||
|
||||
JpaTransactionManager tenantTransactionManager = new JpaTransactionManager();
|
||||
tenantTransactionManager.setEntityManagerFactory(emf);
|
||||
return tenantTransactionManager;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("multitenancy.tenant.liquibase")
|
||||
public LiquibaseProperties tenantLiquibaseProperties() {
|
||||
|
||||
return new LiquibaseProperties();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@DependsOn("masterLiquibase")
|
||||
public TenantSpringLiquibaseExecutor tenantLiquibase(EncryptionDecryptionService encryptionService,
|
||||
TenantRepository tenantRepository,
|
||||
LiquibaseProperties tenantLiquibaseProperties) {
|
||||
|
||||
return new TenantSpringLiquibaseExecutor(encryptionService, tenantRepository, tenantLiquibaseProperties);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.iqser.red.service.peristence.v1.server.multitenancy.persistence;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.multitenancy.entity.TenantEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.EncryptionDecryptionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
|
||||
import liquibase.integration.spring.SpringLiquibase;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class TenantSpringLiquibaseExecutor implements InitializingBean, ResourceLoaderAware {
|
||||
|
||||
private final EncryptionDecryptionService encryptionService;
|
||||
private final TenantRepository tenantRepository;
|
||||
|
||||
@Qualifier("tenantLiquibaseProperties")
|
||||
private final LiquibaseProperties tenantLiquibaseProperties;
|
||||
|
||||
@Setter
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
log.info("DynamicDataSources based multitenancy enabled");
|
||||
this.runOnAllTenants(tenantRepository.findAll());
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
protected void runOnAllTenants(List<TenantEntity> tenants) {
|
||||
|
||||
for (TenantEntity tenant : tenants) {
|
||||
|
||||
log.info("Initializing Liquibase for tenant " + tenant.getTenantId());
|
||||
try (Connection connection = DriverManager.getConnection(tenant.getJdbcUrl(), tenant.getUser(), encryptionService.decrypt(tenant.getPassword()))) {
|
||||
DataSource tenantDataSource = new SingleConnectionDataSource(connection, false);
|
||||
SpringLiquibase liquibase = this.getSpringLiquibase(tenantDataSource);
|
||||
liquibase.afterPropertiesSet();
|
||||
}
|
||||
log.info("Liquibase ran for tenant " + tenant.getTenantId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected SpringLiquibase getSpringLiquibase(DataSource dataSource) {
|
||||
|
||||
SpringLiquibase liquibase = new SpringLiquibase();
|
||||
liquibase.setResourceLoader(resourceLoader);
|
||||
liquibase.setDataSource(dataSource);
|
||||
liquibase.setChangeLog(tenantLiquibaseProperties.getChangeLog());
|
||||
liquibase.setContexts(tenantLiquibaseProperties.getContexts());
|
||||
return liquibase;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +1,15 @@
|
||||
package com.iqser.red.service.peristence.v1.server.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierTemplateEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
|
||||
@ -12,12 +22,9 @@ import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.Do
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.DossierTemplateStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.type.DictionarySummary;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.type.DictionarySummaryResponse;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -49,7 +56,7 @@ public class DossierTemplateStatsService {
|
||||
List<DossierTemplateEntity> templates = allUnDeletedTemplates.stream().filter(dt -> !DossierTemplateStatus.INCOMPLETE.equals(dt.getDossierTemplateStatus())).collect(Collectors.toList());
|
||||
|
||||
final List<DossierTemplateStats> dossierTemplateStatsList = Collections.synchronizedList(new ArrayList<>());
|
||||
templates.parallelStream().forEach(dt -> dossierTemplateStatsList.add(getDossierTemplateStats(dt.getId(), dt.getName(), dt.getDossierTemplateStatus())));
|
||||
templates.stream().forEach(dt -> dossierTemplateStatsList.add(getDossierTemplateStats(dt.getId(), dt.getName(), dt.getDossierTemplateStatus())));
|
||||
|
||||
List<DossierTemplateStats> result = dossierTemplateStatsList.stream().filter(stat -> !(DossierTemplateStatus.INACTIVE.equals(stat.getDossierTemplateStatus())
|
||||
&& stat.getNumberOfActiveDossiers() == 0 && stat.getNumberOfArchivedDossiers() == 0)).collect(Collectors.toList());
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
package com.iqser.red.service.peristence.v1.server.service;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.multitenancy.entity.TenantEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.EncryptionDecryptionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.multitenancy.Tenant;
|
||||
|
||||
import liquibase.exception.LiquibaseException;
|
||||
import liquibase.integration.spring.SpringLiquibase;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
@Service
|
||||
@EnableConfigurationProperties(LiquibaseProperties.class)
|
||||
public class TenantManagementService {
|
||||
|
||||
private final EncryptionDecryptionService encryptionService;
|
||||
|
||||
private final LiquibaseProperties liquibaseProperties;
|
||||
private final ResourceLoader resourceLoader;
|
||||
private final TenantRepository tenantRepository;
|
||||
|
||||
|
||||
public TenantManagementService(EncryptionDecryptionService encryptionService,
|
||||
@Qualifier("tenantLiquibaseProperties") LiquibaseProperties liquibaseProperties,
|
||||
ResourceLoader resourceLoader, TenantRepository tenantRepository) {
|
||||
|
||||
this.encryptionService = encryptionService;
|
||||
this.liquibaseProperties = liquibaseProperties;
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.tenantRepository = tenantRepository;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public void createTenant(Tenant tenant) {
|
||||
|
||||
if (!tenantRepository.findById(tenant.getTenantId()).isPresent()) {
|
||||
|
||||
String encryptedPassword = encryptionService.encrypt(tenant.getPassword());
|
||||
|
||||
try (Connection connection = DriverManager.getConnection(tenant.getJdbcUrl(), tenant.getUser(), tenant.getPassword())) {
|
||||
DataSource tenantDataSource = new SingleConnectionDataSource(connection, false);
|
||||
runLiquibase(tenantDataSource);
|
||||
}
|
||||
|
||||
TenantEntity tenantEntity = TenantEntity.builder()
|
||||
.tenantId(tenant.getTenantId())
|
||||
.user(tenant.getUser())
|
||||
.jdbcUrl(tenant.getJdbcUrl())
|
||||
.password(encryptedPassword)
|
||||
.build();
|
||||
tenantRepository.save(tenantEntity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void runLiquibase(DataSource dataSource) throws LiquibaseException {
|
||||
|
||||
SpringLiquibase liquibase = getSpringLiquibase(dataSource);
|
||||
liquibase.afterPropertiesSet();
|
||||
}
|
||||
|
||||
|
||||
protected SpringLiquibase getSpringLiquibase(DataSource dataSource) {
|
||||
|
||||
SpringLiquibase liquibase = new SpringLiquibase();
|
||||
liquibase.setResourceLoader(resourceLoader);
|
||||
liquibase.setDataSource(dataSource);
|
||||
liquibase.setChangeLog(liquibaseProperties.getChangeLog());
|
||||
liquibase.setContexts(liquibaseProperties.getContexts());
|
||||
return liquibase;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,20 +1,22 @@
|
||||
package com.iqser.red.service.peristence.v1.server.service.job;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.configuration.MessagingConfiguration;
|
||||
import com.iqser.red.service.peristence.v1.server.service.FileStatusService;
|
||||
import com.iqser.red.service.peristence.v1.server.settings.FileManagementServiceSettings;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileModel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.springframework.amqp.core.AmqpAdmin;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import com.iqser.red.service.peristence.v1.server.configuration.MessagingConfiguration;
|
||||
import com.iqser.red.service.peristence.v1.server.service.FileStatusService;
|
||||
import com.iqser.red.service.peristence.v1.server.settings.FileManagementServiceSettings;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileModel;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -24,6 +26,7 @@ public class AutomaticAnalysisJob implements Job {
|
||||
private final AmqpAdmin amqpAdmin;
|
||||
private final FileManagementServiceSettings fileManagementServiceSettings;
|
||||
private final FileStatusService fileStatusService;
|
||||
private final TenantRepository tenantRepository;
|
||||
|
||||
|
||||
@Override
|
||||
@ -34,42 +37,48 @@ public class AutomaticAnalysisJob implements Job {
|
||||
return;
|
||||
}
|
||||
|
||||
var redactionQueueInfo = amqpAdmin.getQueueInfo(MessagingConfiguration.REDACTION_QUEUE);
|
||||
if (redactionQueueInfo != null) {
|
||||
log.info("Checking queue status to see if background analysis can happen. Currently {} holds {} elements and has {} consumers", MessagingConfiguration.REDACTION_QUEUE, redactionQueueInfo
|
||||
.getMessageCount(), redactionQueueInfo.getConsumerCount());
|
||||
// only 1 file in queue
|
||||
var consumerCount = redactionQueueInfo.getConsumerCount();
|
||||
if (redactionQueueInfo.getMessageCount() <= consumerCount * 5) {
|
||||
// queue up 5 files
|
||||
var allStatuses = getAllRelevantStatuses();
|
||||
|
||||
allStatuses.sort(Comparator.comparing(FileModel::getLastUpdated));
|
||||
tenantRepository.findAll().forEach(tenant -> {
|
||||
|
||||
var allStatusesIterator = allStatuses.iterator();
|
||||
log.info("Files that require reanalysis: {}", allStatuses.size());
|
||||
TenantContext.setTenantId(tenant.getTenantId());
|
||||
|
||||
var queuedFiles = 0;
|
||||
var redactionQueueInfo = amqpAdmin.getQueueInfo(MessagingConfiguration.REDACTION_QUEUE);
|
||||
if (redactionQueueInfo != null) {
|
||||
log.info("Checking queue status to see if background analysis can happen. Currently {} holds {} elements and has {} consumers", MessagingConfiguration.REDACTION_QUEUE, redactionQueueInfo.getMessageCount(), redactionQueueInfo.getConsumerCount());
|
||||
// only 1 file in queue
|
||||
var consumerCount = redactionQueueInfo.getConsumerCount();
|
||||
if (redactionQueueInfo.getMessageCount() <= consumerCount * 5) {
|
||||
// queue up 5 files
|
||||
var allStatuses = getAllRelevantStatuses();
|
||||
|
||||
while (queuedFiles < (consumerCount * 5) && allStatusesIterator.hasNext()) {
|
||||
var next = allStatusesIterator.next();
|
||||
// in case the file doesn't have numberOfPages set, we assume an average.
|
||||
allStatuses.sort(Comparator.comparing(FileModel::getLastUpdated));
|
||||
|
||||
if (next.isFullAnalysisRequired()) {
|
||||
log.info("Queued file: {} for automatic full analysis! ", next.getFilename());
|
||||
fileStatusService.setStatusFullReprocess(next.getDossierId(), next.getId(), false, false);
|
||||
} else if (next.isReanalysisRequired()) {
|
||||
log.info("Queued file: {} for automatic reanalysis! ", next.getFilename());
|
||||
fileStatusService.setStatusReprocess(next.getDossierId(), next.getId(), false);
|
||||
var allStatusesIterator = allStatuses.iterator();
|
||||
log.info("Files that require reanalysis: {}", allStatuses.size());
|
||||
|
||||
var queuedFiles = 0;
|
||||
|
||||
while (queuedFiles < (consumerCount * 5) && allStatusesIterator.hasNext()) {
|
||||
var next = allStatusesIterator.next();
|
||||
// in case the file doesn't have numberOfPages set, we assume an average.
|
||||
|
||||
if (next.isFullAnalysisRequired()) {
|
||||
log.info("Queued file: {} for automatic full analysis! ", next.getFilename());
|
||||
fileStatusService.setStatusFullReprocess(next.getDossierId(), next.getId(), false, false);
|
||||
} else if (next.isReanalysisRequired()) {
|
||||
log.info("Queued file: {} for automatic reanalysis! ", next.getFilename());
|
||||
fileStatusService.setStatusReprocess(next.getDossierId(), next.getId(), false);
|
||||
}
|
||||
|
||||
queuedFiles++;
|
||||
}
|
||||
|
||||
queuedFiles++;
|
||||
}
|
||||
|
||||
} else {
|
||||
log.info("Failed to obtain queue info for queue: {}", MessagingConfiguration.REDACTION_QUEUE);
|
||||
}
|
||||
|
||||
} else {
|
||||
log.info("Failed to obtain queue info for queue: {}", MessagingConfiguration.REDACTION_QUEUE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@ package com.iqser.red.service.peristence.v1.server.service.job;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -12,6 +11,9 @@ import com.iqser.red.service.peristence.v1.server.service.DossierService;
|
||||
import com.iqser.red.service.peristence.v1.server.service.FileService;
|
||||
import com.iqser.red.service.peristence.v1.server.service.FileStatusService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -25,33 +27,39 @@ public class DeletedFilesCleanupJob implements Job {
|
||||
private final FileStatusService fileStatusService;
|
||||
private final FileService fileService;
|
||||
private final ApplicationConfigService applicationConfigService;
|
||||
private final TenantRepository tenantRepository;
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) {
|
||||
|
||||
var now = OffsetDateTime.now();
|
||||
List<DossierEntity> dossiers = dossierService.getAllDossiers();
|
||||
var applicationConfigurationEntity = applicationConfigService.getApplicationConfig();
|
||||
tenantRepository.findAll().forEach(tenant -> {
|
||||
|
||||
for (DossierEntity dossierEntity : dossiers) {
|
||||
if (dossierEntity.getSoftDeletedTime() != null && dossierEntity.getHardDeletedTime() == null) {
|
||||
if (dossierEntity.getSoftDeletedTime().isBefore(now.minusHours(applicationConfigurationEntity.getSoftDeleteCleanupTime()))) {
|
||||
dossierService.hardDeleteDossier(dossierEntity.getId());
|
||||
log.info("Hard deleted dossier with dossier id {} ", dossierEntity.getId());
|
||||
}
|
||||
} else {
|
||||
var files = fileStatusService.getDossierStatus(dossierEntity.getId());
|
||||
for (var file : files) {
|
||||
if (file.getHardDeletedTime() == null && file.getDeleted() != null && file.getDeleted()
|
||||
.isBefore(now.minusHours(applicationConfigurationEntity.getSoftDeleteCleanupTime()))) {
|
||||
fileService.hardDeleteFile(dossierEntity.getId(), file.getId());
|
||||
fileStatusService.setFileStatusHardDeleted(file.getId());
|
||||
log.info("Hard deleted file with dossier id {} and file id {}", dossierEntity.getId(), file.getId());
|
||||
TenantContext.setTenantId(tenant.getTenantId());
|
||||
|
||||
var now = OffsetDateTime.now();
|
||||
List<DossierEntity> dossiers = dossierService.getAllDossiers();
|
||||
var applicationConfigurationEntity = applicationConfigService.getApplicationConfig();
|
||||
|
||||
for (DossierEntity dossierEntity : dossiers) {
|
||||
if (dossierEntity.getSoftDeletedTime() != null && dossierEntity.getHardDeletedTime() == null) {
|
||||
if (dossierEntity.getSoftDeletedTime().isBefore(now.minusHours(applicationConfigurationEntity.getSoftDeleteCleanupTime()))) {
|
||||
dossierService.hardDeleteDossier(dossierEntity.getId());
|
||||
log.info("Hard deleted dossier with dossier id {} ", dossierEntity.getId());
|
||||
}
|
||||
} else {
|
||||
var files = fileStatusService.getDossierStatus(dossierEntity.getId());
|
||||
for (var file : files) {
|
||||
if (file.getHardDeletedTime() == null && file.getDeleted() != null && file.getDeleted().isBefore(now.minusHours(applicationConfigurationEntity.getSoftDeleteCleanupTime()))) {
|
||||
fileService.hardDeleteFile(dossierEntity.getId(), file.getId());
|
||||
fileStatusService.setFileStatusHardDeleted(file.getId());
|
||||
log.info("Hard deleted file with dossier id {} and file id {}", dossierEntity.getId(), file.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,19 +1,23 @@
|
||||
package com.iqser.red.service.peristence.v1.server.service.job;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.service.DossierService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.download.DownloadStatusEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
import com.iqser.red.storage.commons.service.StorageService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@ -24,35 +28,39 @@ public class DownloadCleanupJob implements Job {
|
||||
private final StorageService storageService;
|
||||
private final DossierService dossierService;
|
||||
private final ApplicationConfigService applicationConfigService;
|
||||
private final TenantRepository tenantRepository;
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) {
|
||||
|
||||
var now = OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS);
|
||||
log.info("Checking for downloads to delete at {}", now);
|
||||
List<DownloadStatusEntity> downloadStatusList = downloadStatusPersistenceService.getStatus();
|
||||
downloadStatusList.forEach(downloadStatus -> {
|
||||
tenantRepository.findAll().forEach(tenant -> {
|
||||
|
||||
var dossier = downloadStatus.getDossier();
|
||||
var applicationConfigurationEntity = applicationConfigService.getApplicationConfig();
|
||||
if (downloadStatus.getLastDownload() != null && downloadStatus.getLastDownload()
|
||||
.plusHours(applicationConfigurationEntity.getDownloadCleanupDownloadFilesHours())
|
||||
.isBefore(now)) {
|
||||
log.info("1. Deleting download status {} because DownloadCleanupDownloadFilesHours is {} and c+h {} is after {}", downloadStatus,
|
||||
applicationConfigurationEntity.getDownloadCleanupDownloadFilesHours(), downloadStatus.getCreationDate()
|
||||
.plusHours(applicationConfigurationEntity.getDownloadCleanupDownloadFilesHours()), now);
|
||||
deleteDownload(downloadStatus);
|
||||
} else if (downloadStatus.getLastDownload() == null && downloadStatus.getCreationDate()
|
||||
.plusHours(applicationConfigurationEntity.getDownloadCleanupNotDownloadFilesHours())
|
||||
.isBefore(now)) {
|
||||
log.info("2. Deleting download status {} because DownloadCleanupNotDownloadFilesHours is {} and c+h {} is after {}", downloadStatus,
|
||||
applicationConfigurationEntity.getDownloadCleanupNotDownloadFilesHours(), downloadStatus.getCreationDate()
|
||||
.plusHours(applicationConfigurationEntity.getDownloadCleanupNotDownloadFilesHours()), now);
|
||||
deleteDownload(downloadStatus);
|
||||
} else if (dossierService.getDossierById(dossier.getId()).getSoftDeletedTime() != null) {
|
||||
log.info("3. Deleting download {}, because dossier does not exist", downloadStatus.getStorageId());
|
||||
deleteDownload(downloadStatus);
|
||||
}
|
||||
TenantContext.setTenantId(tenant.getTenantId());
|
||||
|
||||
var now = OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS);
|
||||
log.info("Checking for downloads to delete at {}", now);
|
||||
List<DownloadStatusEntity> downloadStatusList = downloadStatusPersistenceService.getStatus();
|
||||
downloadStatusList.forEach(downloadStatus -> {
|
||||
|
||||
var dossier = downloadStatus.getDossier();
|
||||
var applicationConfigurationEntity = applicationConfigService.getApplicationConfig();
|
||||
if (downloadStatus.getLastDownload() != null && downloadStatus.getLastDownload()
|
||||
.plusHours(applicationConfigurationEntity.getDownloadCleanupDownloadFilesHours())
|
||||
.isBefore(now)) {
|
||||
log.info("1. Deleting download status {} because DownloadCleanupDownloadFilesHours is {} and c+h {} is after {}", downloadStatus, applicationConfigurationEntity.getDownloadCleanupDownloadFilesHours(), downloadStatus.getCreationDate()
|
||||
.plusHours(applicationConfigurationEntity.getDownloadCleanupDownloadFilesHours()), now);
|
||||
deleteDownload(downloadStatus);
|
||||
} else if (downloadStatus.getLastDownload() == null && downloadStatus.getCreationDate()
|
||||
.plusHours(applicationConfigurationEntity.getDownloadCleanupNotDownloadFilesHours())
|
||||
.isBefore(now)) {
|
||||
log.info("2. Deleting download status {} because DownloadCleanupNotDownloadFilesHours is {} and c+h {} is after {}", downloadStatus, applicationConfigurationEntity.getDownloadCleanupNotDownloadFilesHours(), downloadStatus.getCreationDate()
|
||||
.plusHours(applicationConfigurationEntity.getDownloadCleanupNotDownloadFilesHours()), now);
|
||||
deleteDownload(downloadStatus);
|
||||
} else if (dossierService.getDossierById(dossier.getId()).getSoftDeletedTime() != null) {
|
||||
log.info("3. Deleting download {}, because dossier does not exist", downloadStatus.getStorageId());
|
||||
deleteDownload(downloadStatus);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -1,19 +1,23 @@
|
||||
package com.iqser.red.service.peristence.v1.server.service.job;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationEmailService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPreferencesPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.notification.EmailNotificationType;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationEmailService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPreferencesPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.notification.EmailNotificationType;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@ -22,37 +26,41 @@ public class SendNotificationEmailJob implements Job {
|
||||
private final NotificationEmailService notificationEmailService;
|
||||
private final NotificationPersistenceService notificationPersistenceService;
|
||||
private final NotificationPreferencesPersistenceService notificationPreferencesPersistenceService;
|
||||
private final TenantRepository tenantRepository;
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) {
|
||||
|
||||
tenantRepository.findAll().forEach(tenant -> {
|
||||
|
||||
var allConfiguredPreferences = notificationPreferencesPersistenceService.findAll();
|
||||
allConfiguredPreferences.forEach(preference -> {
|
||||
if (preference.isEmailNotificationsEnabled() && preference.getEmailNotificationType() == EmailNotificationType.WEEKLY_SUMMARY || preference.getEmailNotificationType() == EmailNotificationType.DAILY_SUMMARY) {
|
||||
TenantContext.setTenantId(tenant.getTenantId());
|
||||
|
||||
var now = OffsetDateTime.now().truncatedTo(ChronoUnit.HOURS);
|
||||
var allConfiguredPreferences = notificationPreferencesPersistenceService.findAll();
|
||||
allConfiguredPreferences.forEach(preference -> {
|
||||
if (preference.isEmailNotificationsEnabled() && preference.getEmailNotificationType() == EmailNotificationType.WEEKLY_SUMMARY || preference.getEmailNotificationType() == EmailNotificationType.DAILY_SUMMARY) {
|
||||
|
||||
// Weekly summary is sent monday night
|
||||
if (now.getDayOfWeek() == DayOfWeek.MONDAY && preference.getEmailNotificationType() == EmailNotificationType.WEEKLY_SUMMARY) {
|
||||
var from = OffsetDateTime.now().minusDays(7).truncatedTo(ChronoUnit.HOURS).withHour(0);
|
||||
var to = OffsetDateTime.now().truncatedTo(ChronoUnit.HOURS).withHour(0);
|
||||
var notifications = notificationPersistenceService.getNotificationsForEmailSummary(preference.getUserId(), from, to);
|
||||
var now = OffsetDateTime.now().truncatedTo(ChronoUnit.HOURS);
|
||||
|
||||
notificationEmailService.sendNotificationEmail(preference.getUserId(), EmailNotificationType.WEEKLY_SUMMARY, notifications);
|
||||
} else {
|
||||
var from = OffsetDateTime.now().minusDays(1).withHour(0).truncatedTo(ChronoUnit.HOURS);
|
||||
var to = OffsetDateTime.now().minusDays(1).withHour(23).truncatedTo(ChronoUnit.HOURS);
|
||||
var notifications = notificationPersistenceService.getNotificationsForEmailSummary(preference.getUserId(), from, to);
|
||||
// Weekly summary is sent monday night
|
||||
if (now.getDayOfWeek() == DayOfWeek.MONDAY && preference.getEmailNotificationType() == EmailNotificationType.WEEKLY_SUMMARY) {
|
||||
var from = OffsetDateTime.now().minusDays(7).truncatedTo(ChronoUnit.HOURS).withHour(0);
|
||||
var to = OffsetDateTime.now().truncatedTo(ChronoUnit.HOURS).withHour(0);
|
||||
var notifications = notificationPersistenceService.getNotificationsForEmailSummary(preference.getUserId(), from, to);
|
||||
|
||||
notificationEmailService.sendNotificationEmail(preference.getUserId(), EmailNotificationType.DAILY_SUMMARY, notifications);
|
||||
notificationEmailService.sendNotificationEmail(preference.getUserId(), EmailNotificationType.WEEKLY_SUMMARY, notifications);
|
||||
} else {
|
||||
var from = OffsetDateTime.now().minusDays(1).withHour(0).truncatedTo(ChronoUnit.HOURS);
|
||||
var to = OffsetDateTime.now().minusDays(1).withHour(23).truncatedTo(ChronoUnit.HOURS);
|
||||
var notifications = notificationPersistenceService.getNotificationsForEmailSummary(preference.getUserId(), from, to);
|
||||
|
||||
notificationEmailService.sendNotificationEmail(preference.getUserId(), EmailNotificationType.DAILY_SUMMARY, notifications);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,17 +12,6 @@ server:
|
||||
spring:
|
||||
main:
|
||||
allow-circular-references: true # FIXME
|
||||
datasource:
|
||||
url: jdbc:postgresql://${PSQL_HOST:localhost}:${PSQL_PORT:5432}/${PSQL_DATABASE:redaction}?cachePrepStmts=true&useServerPrepStmts=true&rewriteBatchedStatements=true
|
||||
driverClassName: org.postgresql.Driver
|
||||
username: ${PSQL_USERNAME:redaction}
|
||||
password: ${PSQL_PASSWORD:redaction}
|
||||
platform: org.hibernate.dialect.PostgreSQL95Dialect
|
||||
hikari:
|
||||
data-source-properties:
|
||||
cachePrepStmts: true
|
||||
prepStmtCacheSize: 1000
|
||||
prepStmtCacheSqlLimit: 2048
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.PostgreSQL95Dialect
|
||||
hibernate:
|
||||
@ -89,4 +78,31 @@ storage:
|
||||
endpoint: 'https://s3.amazonaws.com'
|
||||
backend: 's3'
|
||||
|
||||
|
||||
multitenancy:
|
||||
datasource-cache:
|
||||
maximumSize: 100
|
||||
expireAfterAccess: 1
|
||||
master:
|
||||
datasource:
|
||||
url: jdbc:postgresql://${PSQL_HOST:localhost}:${PSQL_PORT:5432}/${PSQL_DATABASE:master}?cachePrepStmts=true&useServerPrepStmts=true&rewriteBatchedStatements=true
|
||||
driverClassName: org.postgresql.Driver
|
||||
username: ${PSQL_USERNAME:redaction}
|
||||
password: ${PSQL_PASSWORD:redaction}
|
||||
platform: org.hibernate.dialect.PostgreSQL95Dialect
|
||||
hikari:
|
||||
data-source-properties:
|
||||
cachePrepStmts: true
|
||||
prepStmtCacheSize: 1000
|
||||
prepStmtCacheSqlLimit: 2048
|
||||
liquibase:
|
||||
changeLog: classpath:db/changelog/db.changelog-master.yaml
|
||||
tenant:
|
||||
datasource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
hikari:
|
||||
data-source-properties:
|
||||
cachePrepStmts: true
|
||||
prepStmtCacheSize: 1000
|
||||
prepStmtCacheSqlLimit: 2048
|
||||
liquibase:
|
||||
changeLog: classpath:db/changelog/db.changelog-tenant.yaml
|
||||
@ -1,101 +1,3 @@
|
||||
databaseChangeLog:
|
||||
- include:
|
||||
file: db/changelog/1-initial-schema.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/2-ignored-hint-color.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/3-added-annotation-modification-date.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/4-archived-dossier.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/5-excluded-from-automatic-analysis-file-column.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/6-dossier-status-table.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/7-json-column-mapping.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/sql/7.1-set-json-fields.sql
|
||||
- include:
|
||||
file: db/changelog/sql/7.2-set-dossier-status.sql
|
||||
- include:
|
||||
file: db/changelog/9-changed-annotation-modification-date.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/10-added-file-manipulation-date.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/sql/10-set-file-manipulation-date.sql
|
||||
- include:
|
||||
file: db/changelog/11-added-dictionary_false_positive_tables.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/12-dossier-visibility.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/12-added-rank-dossier-status.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/13-file-manual-change-date.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/release-3.2.0/1-add-index-on-dictionary-entry.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/14-add-redaction-source-id.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/15-dossier-remove-dossier-state.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/16-added-has-dictionary-to-entities.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/17-digital-signature-kms.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/18-add-migration-table.yaml
|
||||
- include:
|
||||
file: db/changelog/19-added-has-highlights-to-file.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/20-add-index-information-table.yaml
|
||||
- include:
|
||||
file: db/changelog/21-added-auto-hide-skipped-to-entities.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/sql/22-update-file-dossier-attributes.sql
|
||||
- include:
|
||||
file: db/changelog/22-add-soft-delete-time-to-entity.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/23-quartz.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/sql/24.0-clean-up-duplicate-dictionary-entries.sql
|
||||
- include:
|
||||
file: db/changelog/24-add-unique-constraint-for-dictionary.yaml
|
||||
- include:
|
||||
file: db/changelog/release-3.3.12/1-fix-dossier-dictionary.sql
|
||||
- include:
|
||||
file: db/changelog/25-add-index-to-dictionary-entry-tables.yaml
|
||||
- include:
|
||||
file: db/changelog/26-application-config-table.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/sql/26-initiliaze-application-configuration-table.sql
|
||||
- include:
|
||||
file: db/changelog/sql/27-update-soft-delete-date.sql
|
||||
- include:
|
||||
file: db/changelog/28-add-update-dictionary-to-manual-resize-redactions.yaml
|
||||
- include:
|
||||
file: db/changelog/sql/30-change-bigint-to-serial.sql
|
||||
- include:
|
||||
file: db/changelog/31-add-file-size-column.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/sql/31-watermark-configuration.sql
|
||||
- include:
|
||||
file: db/changelog/32-added-skipped-color-type-table.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/33-add-file-processing-error-counter-column.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/sql/33-set-file-processing-error-counter.sql
|
||||
- include:
|
||||
file: db/changelog/34-add-reports-information-column.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/sql/35-update-skipped-color-existing-types.sql
|
||||
- include:
|
||||
file: db/changelog/36-revert-reports-information-column.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/sql/37-update-colors.sql
|
||||
- include:
|
||||
file: db/changelog/sql/38-update-soft-deleted-processed-flag.sql
|
||||
- include:
|
||||
file: db/changelog/sql/39-update-manual-redaction-source-id.sql
|
||||
- include:
|
||||
file: db/changelog/release-3.3.13/1-update-soft-deleted-processed-flag.sql
|
||||
- include:
|
||||
file: db/changelog/release-3.3.14/1-bump-rules-version.sql
|
||||
file: db/changelog/master/1-initial-schema.changelog.yaml
|
||||
|
||||
@ -0,0 +1,101 @@
|
||||
databaseChangeLog:
|
||||
- include:
|
||||
file: db/changelog/tenant/1-initial-schema.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/2-ignored-hint-color.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/3-added-annotation-modification-date.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/4-archived-dossier.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/5-excluded-from-automatic-analysis-file-column.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/6-dossier-status-table.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/7-json-column-mapping.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/7.1-set-json-fields.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/7.2-set-dossier-status.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/9-changed-annotation-modification-date.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/10-added-file-manipulation-date.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/10-set-file-manipulation-date.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/11-added-dictionary_false_positive_tables.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/12-dossier-visibility.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/12-added-rank-dossier-status.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/13-file-manual-change-date.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/release-3.2.0/1-add-index-on-dictionary-entry.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/14-add-redaction-source-id.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/15-dossier-remove-dossier-state.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/16-added-has-dictionary-to-entities.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/17-digital-signature-kms.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/18-add-migration-table.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/19-added-has-highlights-to-file.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/20-add-index-information-table.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/21-added-auto-hide-skipped-to-entities.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/22-update-file-dossier-attributes.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/22-add-soft-delete-time-to-entity.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/23-quartz.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/24.0-clean-up-duplicate-dictionary-entries.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/24-add-unique-constraint-for-dictionary.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/release-3.3.12/1-fix-dossier-dictionary.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/25-add-index-to-dictionary-entry-tables.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/26-application-config-table.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/26-initiliaze-application-configuration-table.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/27-update-soft-delete-date.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/28-add-update-dictionary-to-manual-resize-redactions.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/30-change-bigint-to-serial.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/31-add-file-size-column.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/31-watermark-configuration.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/32-added-skipped-color-type-table.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/33-add-file-processing-error-counter-column.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/33-set-file-processing-error-counter.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/34-add-reports-information-column.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/35-update-skipped-color-existing-types.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/36-revert-reports-information-column.changelog.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/37-update-colors.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/38-update-soft-deleted-processed-flag.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/sql/39-update-manual-redaction-source-id.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/release-3.3.13/1-update-soft-deleted-processed-flag.sql
|
||||
- include:
|
||||
file: db/changelog/tenant/release-3.3.14/1-bump-rules-version.sql
|
||||
@ -0,0 +1,24 @@
|
||||
databaseChangeLog:
|
||||
- changeSet:
|
||||
id: create-tenants-table
|
||||
author: dom
|
||||
changes:
|
||||
- createTable:
|
||||
columns:
|
||||
- column:
|
||||
constraints:
|
||||
nullable: false
|
||||
primaryKey: true
|
||||
primaryKeyName: tenant_pkey
|
||||
name: tenant_id
|
||||
type: VARCHAR(255)
|
||||
- column:
|
||||
name: username
|
||||
type: VARCHAR(255)
|
||||
- column:
|
||||
name: password
|
||||
type: VARCHAR(255)
|
||||
- column:
|
||||
name: jdbc_url
|
||||
type: VARCHAR(255)
|
||||
tableName: tenant
|
||||
@ -19,6 +19,5 @@ databaseChangeLog:
|
||||
- column:
|
||||
name: excluded_from_automatic_analysis
|
||||
value: true
|
||||
schemaName: public
|
||||
tableName: file
|
||||
where: workflow_status = 'APPROVED'
|
||||
@ -0,0 +1,11 @@
|
||||
package com.iqser.red.service.peristence.v1.server.integration.client;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.resources.TenantsResource;
|
||||
|
||||
|
||||
@FeignClient(name = "TenantsClient", url = "http://localhost:${server.port}")
|
||||
public interface TenantsClient extends TenantsResource {
|
||||
|
||||
}
|
||||
@ -1,7 +1,26 @@
|
||||
package com.iqser.red.service.peristence.v1.server.integration.tests;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.*;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.DictionaryClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.DossierClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.DossierStatusClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.DossierTemplateClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.DossierTemplateStatsClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.FileClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.UploadClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider;
|
||||
@ -16,18 +35,6 @@ import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.ty
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.type.DictionaryEntryType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.type.DictionarySummary;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.type.Type;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class DossierTemplateStatsTest extends AbstractPersistenceServerServiceTest {
|
||||
private static final String TYPE_ID_1 = "type1";
|
||||
@ -239,6 +246,8 @@ public class DossierTemplateStatsTest extends AbstractPersistenceServerServiceTe
|
||||
@Test
|
||||
public void testDossierTemplateStats() {
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
var template = dossierTemplateTesterAndProvider.provideTestTemplate("test template: " + i);
|
||||
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
package com.iqser.red.service.peristence.v1.server.integration.tests;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.DictionaryClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider;
|
||||
@ -8,12 +15,6 @@ import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPers
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.configuration.Colors;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.type.DictionaryEntryType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.type.Type;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TypeTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
|
||||
@ -1,23 +1,13 @@
|
||||
package com.iqser.red.service.peristence.v1.server.integration.utils;
|
||||
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.ByteContentDocument;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.DocumentRequest;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.UntouchedDocumentResponse;
|
||||
import com.iqser.red.service.peristence.v1.server.Application;
|
||||
import com.iqser.red.service.peristence.v1.server.client.RedactionClient;
|
||||
import com.iqser.red.service.peristence.v1.server.client.SearchClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.ApplicationConfigClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.FileClient;
|
||||
import com.iqser.red.service.peristence.v1.server.utils.MetricsPrinterService;
|
||||
import com.iqser.red.service.peristence.v1.server.utils.StorageIdUtils;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.client.PDFTronRedactionClient;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.*;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.configuration.ApplicationConfig;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileType;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLog;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionResult;
|
||||
import com.iqser.red.storage.commons.StorageAutoConfiguration;
|
||||
import com.iqser.red.storage.commons.service.StorageService;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@ -34,20 +24,77 @@ import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.StatementCallback;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.testcontainers.shaded.org.apache.commons.io.IOUtils;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.ByteContentDocument;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.DocumentRequest;
|
||||
import com.iqser.red.service.peristence.v1.server.Application;
|
||||
import com.iqser.red.service.peristence.v1.server.client.RedactionClient;
|
||||
import com.iqser.red.service.peristence.v1.server.client.SearchClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.ApplicationConfigClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.FileClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.TenantsClient;
|
||||
import com.iqser.red.service.peristence.v1.server.utils.MetricsPrinterService;
|
||||
import com.iqser.red.service.peristence.v1.server.utils.StorageIdUtils;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.client.PDFTronRedactionClient;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.mulitenancy.repository.TenantRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ApplicationConfigRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.AuditRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DigitalSignatureRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierAttributeConfigRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierAttributeRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierStatusRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DownloadStatusRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.EntryRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FalsePositiveEntryRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FalseRecommendationEntryRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileAttributeConfigRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileAttributesGeneralConfigurationRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileAttributesRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ForceRedactionRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ImageRecategorizationRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.IndexInformationRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.LegalBasisChangeRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.LegalBasisMappingRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ManualRedactionRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationPreferencesRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.RemoveRedactionRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ReportTemplateRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.RuleSetRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.SMTPRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.TypeRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ViewedPagesRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.WatermarkRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.configuration.ApplicationConfig;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.multitenancy.Tenant;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionLog;
|
||||
import com.iqser.red.service.redaction.v1.model.RedactionResult;
|
||||
import com.iqser.red.storage.commons.StorageAutoConfiguration;
|
||||
import com.iqser.red.storage.commons.service.StorageService;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@EnableFeignClients(basePackageClasses = FileClient.class)
|
||||
@Import(AbstractPersistenceServerServiceTest.TestConfiguration.class)
|
||||
@ContextConfiguration(initializers = {AbstractPersistenceServerServiceTest.Initializer.class})
|
||||
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
|
||||
properties = "spring-hibernate-query-utils.n-plus-one-queries-detection.error-level=INFO")
|
||||
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = "spring-hibernate-query-utils.n-plus-one-queries-detection.error-level=INFO")
|
||||
public abstract class AbstractPersistenceServerServiceTest {
|
||||
|
||||
@MockBean
|
||||
@ -132,11 +179,26 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
@Autowired
|
||||
protected ApplicationConfigRepository applicationConfigRepository;
|
||||
|
||||
@Autowired
|
||||
protected TenantsClient tenantsClient;
|
||||
|
||||
@Autowired
|
||||
protected TenantRepository tenantRepository;
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
|
||||
@Before
|
||||
public void setupOptimize() {
|
||||
|
||||
createDefaultTenant();
|
||||
|
||||
ApplicationConfig appConfig = new ApplicationConfig().builder()
|
||||
.downloadCleanupDownloadFilesHours(8).downloadCleanupNotDownloadFilesHours(72).softDeleteCleanupTime(96).build();
|
||||
.downloadCleanupDownloadFilesHours(8)
|
||||
.downloadCleanupNotDownloadFilesHours(72)
|
||||
.softDeleteCleanupTime(96)
|
||||
.build();
|
||||
appConfigClient.createOrUpdateAppConfig(appConfig);
|
||||
|
||||
// when(appConfigClient.getCurrentApplicationConfig()).thenReturn(ApplicationConfig.builder()
|
||||
@ -153,94 +215,144 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
DocumentRequest d = (DocumentRequest) args[0];
|
||||
var untouchedObjectId = StorageIdUtils.getStorageId(d.getDossierId(), d.getFileId(), FileType.ORIGIN);
|
||||
|
||||
return new ByteContentDocument(IOUtils.toByteArray(storageService.getObject(untouchedObjectId).getInputStream()));
|
||||
return new ByteContentDocument(IOUtils.toByteArray(storageService.getObject(untouchedObjectId)
|
||||
.getInputStream()));
|
||||
});
|
||||
when(pdfTronRedactionClient.redactionPreview(Mockito.any())).thenAnswer((answer) -> {
|
||||
Object[] args = answer.getArguments();
|
||||
DocumentRequest d = (DocumentRequest) args[0];
|
||||
var untouchedObjectId = StorageIdUtils.getStorageId(d.getDossierId(), d.getFileId(), FileType.ORIGIN);
|
||||
|
||||
return new ByteContentDocument(IOUtils.toByteArray(storageService.getObject(untouchedObjectId).getInputStream()));
|
||||
return new ByteContentDocument(IOUtils.toByteArray(storageService.getObject(untouchedObjectId)
|
||||
.getInputStream()));
|
||||
});
|
||||
when(pdfTronRedactionClient.redactionPreviewDiff(Mockito.any())).thenAnswer((answer) -> {
|
||||
Object[] args = answer.getArguments();
|
||||
DocumentRequest d = (DocumentRequest) args[0];
|
||||
var untouchedObjectId = StorageIdUtils.getStorageId(d.getDossierId(), d.getFileId(), FileType.ORIGIN);
|
||||
|
||||
return new ByteContentDocument(IOUtils.toByteArray(storageService.getObject(untouchedObjectId).getInputStream()));
|
||||
return new ByteContentDocument(IOUtils.toByteArray(storageService.getObject(untouchedObjectId)
|
||||
.getInputStream()));
|
||||
});
|
||||
|
||||
|
||||
when(redactionClient.sections(Mockito.any())).thenReturn(new RedactionResult());
|
||||
when(redactionClient.getRedactionLog(Mockito.any())).thenReturn(new RedactionLog(1, 1,
|
||||
Lists.newArrayList(), null, 0, 0, 0, 0));
|
||||
when(redactionClient.getRedactionLog(Mockito.any())).thenReturn(new RedactionLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
|
||||
private void createDefaultTenant() {
|
||||
|
||||
if(!tenantRepository.findById("redaction").isPresent()) {
|
||||
var postgreSQLContainerMaster = SpringPostgreSQLTestContainer.getInstance()
|
||||
.withDatabaseName("integration-tests-db-master")
|
||||
.withUsername("sa")
|
||||
.withPassword("sa");
|
||||
|
||||
var jdbcUrl = postgreSQLContainerMaster.getJdbcUrl().substring(0, postgreSQLContainerMaster.getJdbcUrl().lastIndexOf('/') + 1) + "redaction?currentSchema=myschema";
|
||||
|
||||
createDatabase("redaction", "redaction");
|
||||
createSchema(jdbcUrl, "redaction", "redaction");
|
||||
|
||||
tenantsClient.createTenant(new Tenant("redaction", jdbcUrl, "redaction", "redaction"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void createDatabase(String db, String password) {
|
||||
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE DATABASE " + db));
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE USER " + db + " WITH ENCRYPTED PASSWORD '" + password + "'"));
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("GRANT ALL PRIVILEGES ON DATABASE " + db + " TO " + db));
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public void createSchema(String jdbcUrl, String username, String password) {
|
||||
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password)) {
|
||||
DataSource tenantDataSource = new SingleConnectionDataSource(connection, false);
|
||||
JdbcTemplate insert = new JdbcTemplate(tenantDataSource);
|
||||
insert.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE SCHEMA myschema"));
|
||||
insert.execute((StatementCallback<Boolean>) stmt -> stmt.execute("GRANT USAGE ON SCHEMA myschema TO " + username));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void cleanupStorage() {
|
||||
|
||||
((FileSystemBackedStorageService) this.storageService).clearStorage();
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void printMetrics() {
|
||||
|
||||
this.metricsPrinterService.printMetrics();
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void afterTests() {
|
||||
falsePositiveEntryRepository.deleteAll();
|
||||
falseRecommendationEntryRepository.deleteAll();
|
||||
entryRepository.deleteAll();
|
||||
dossierAttributeRepository.deleteAll();
|
||||
dossierAttributeConfigRepository.deleteAll();
|
||||
downloadStatusRepository.deleteAll();
|
||||
fileAttributesRepository.deleteAll();
|
||||
smtpRepository.deleteAll();
|
||||
digitalSignatureRepository.deleteAll();
|
||||
fileAttributesGeneralConfigurationRepository.deleteAll();
|
||||
fileAttributeConfigRepository.deleteAll();
|
||||
reportTemplateRepository.deleteAll();
|
||||
typeRepository.deleteAll();
|
||||
viewedPagesRepository.deleteAll();
|
||||
notificationRepository.deleteAll();
|
||||
auditRepository.deleteAll();
|
||||
manualRedactionRepository.deleteAll();
|
||||
forceRedactionRepository.deleteAll();
|
||||
removeRedactionRepository.deleteAll();
|
||||
legalBasisChangeRepository.deleteAll();
|
||||
imageRecategorizationRepository.deleteAll();
|
||||
legalBasisMappingRepository.deleteAll();
|
||||
ruleSetRepository.deleteAll();
|
||||
smtpRepository.deleteAll();
|
||||
fileRepository.deleteAll();
|
||||
dossierRepository.deleteAll();
|
||||
dossierStatusRepository.deleteAll();
|
||||
watermarkRepository.deleteAll();
|
||||
dossierTemplateRepository.deleteAll();
|
||||
notificationPreferencesRepository.deleteAll();
|
||||
indexInformationRepository.deleteAll();
|
||||
applicationConfigRepository.deleteAll();
|
||||
|
||||
tenantRepository.findAll().forEach(tenant -> {
|
||||
|
||||
TenantContext.setTenantId(tenant.getTenantId());
|
||||
|
||||
falsePositiveEntryRepository.deleteAll();
|
||||
falseRecommendationEntryRepository.deleteAll();
|
||||
entryRepository.deleteAll();
|
||||
dossierAttributeRepository.deleteAll();
|
||||
dossierAttributeConfigRepository.deleteAll();
|
||||
downloadStatusRepository.deleteAll();
|
||||
fileAttributesRepository.deleteAll();
|
||||
smtpRepository.deleteAll();
|
||||
digitalSignatureRepository.deleteAll();
|
||||
fileAttributesGeneralConfigurationRepository.deleteAll();
|
||||
fileAttributeConfigRepository.deleteAll();
|
||||
reportTemplateRepository.deleteAll();
|
||||
typeRepository.deleteAll();
|
||||
viewedPagesRepository.deleteAll();
|
||||
notificationRepository.deleteAll();
|
||||
auditRepository.deleteAll();
|
||||
manualRedactionRepository.deleteAll();
|
||||
forceRedactionRepository.deleteAll();
|
||||
removeRedactionRepository.deleteAll();
|
||||
legalBasisChangeRepository.deleteAll();
|
||||
imageRecategorizationRepository.deleteAll();
|
||||
legalBasisMappingRepository.deleteAll();
|
||||
ruleSetRepository.deleteAll();
|
||||
smtpRepository.deleteAll();
|
||||
fileRepository.deleteAll();
|
||||
dossierRepository.deleteAll();
|
||||
dossierStatusRepository.deleteAll();
|
||||
watermarkRepository.deleteAll();
|
||||
dossierTemplateRepository.deleteAll();
|
||||
notificationPreferencesRepository.deleteAll();
|
||||
indexInformationRepository.deleteAll();
|
||||
applicationConfigRepository.deleteAll();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
|
||||
|
||||
var postgreSQLContainer = SpringPostgreSQLTestContainer.getInstance()
|
||||
.withDatabaseName("integration-tests-db")
|
||||
var postgreSQLContainerMaster = SpringPostgreSQLTestContainer.getInstance()
|
||||
.withDatabaseName("integration-tests-db-master")
|
||||
.withUsername("sa")
|
||||
.withPassword("sa");
|
||||
|
||||
postgreSQLContainer.start();
|
||||
postgreSQLContainerMaster.start();
|
||||
|
||||
var connectionStringDetails = "?serverTimezone=UTC&cachePrepStmts=true&useServerPrepStmts=true&rewriteBatchedStatements=true";
|
||||
|
||||
TestPropertyValues.of(
|
||||
"spring.datasource.url=" + postgreSQLContainer.getJdbcUrl() + connectionStringDetails,
|
||||
"spring.datasource.username=" + postgreSQLContainer.getUsername(),
|
||||
"spring.datasource.password=" + postgreSQLContainer.getPassword()
|
||||
).applyTo(configurableApplicationContext.getEnvironment());
|
||||
TestPropertyValues.of("multitenancy.master.datasource.url=" + postgreSQLContainerMaster.getJdbcUrl() + connectionStringDetails, "multitenancy.master.datasource.username=" + postgreSQLContainerMaster.getUsername(), "multitenancy.master.datasource.password=" + postgreSQLContainerMaster.getPassword())
|
||||
.applyTo(configurableApplicationContext.getEnvironment());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ -251,10 +363,10 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
@Bean
|
||||
@Primary
|
||||
public StorageService inmemoryStorage() {
|
||||
|
||||
return new FileSystemBackedStorageService();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,14 +3,6 @@ monitoring.enabled: true
|
||||
spring:
|
||||
main:
|
||||
allow-circular-references: true # FIXME
|
||||
datasource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
platform: org.hibernate.dialect.PostgreSQL95Dialect
|
||||
hikari:
|
||||
data-source-properties:
|
||||
cachePrepStmts: true
|
||||
prepStmtCacheSize: 1000
|
||||
prepStmtCacheSqlLimit: 2048
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.PostgreSQL95Dialect
|
||||
hibernate:
|
||||
@ -79,3 +71,30 @@ management:
|
||||
endpoints.web.exposure.include: prometheus, health, metrics
|
||||
|
||||
logging.level.root: info
|
||||
|
||||
multitenancy:
|
||||
datasource-cache:
|
||||
maximumSize: 100
|
||||
expireAfterAccess: 1
|
||||
master:
|
||||
datasource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
platform: org.hibernate.dialect.PostgreSQL95Dialect
|
||||
hikari:
|
||||
data-source-properties:
|
||||
cachePrepStmts: true
|
||||
prepStmtCacheSize: 1000
|
||||
prepStmtCacheSqlLimit: 2048
|
||||
liquibase:
|
||||
changeLog: classpath:db/changelog/db.changelog-master.yaml
|
||||
tenant:
|
||||
datasource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
platform: org.hibernate.dialect.PostgreSQL95Dialect
|
||||
hikari:
|
||||
data-source-properties:
|
||||
cachePrepStmts: true
|
||||
prepStmtCacheSize: 1000
|
||||
prepStmtCacheSqlLimit: 2048
|
||||
liquibase:
|
||||
changeLog: classpath:db/changelog/db.changelog-tenant.yaml
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user