diff --git a/persistence-service-v1/persistence-service-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/model/multitenancy/TenantRequest.java b/persistence-service-v1/persistence-service-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/model/multitenancy/TenantRequest.java index 8b3a1c525..c903032b8 100644 --- a/persistence-service-v1/persistence-service-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/model/multitenancy/TenantRequest.java +++ b/persistence-service-v1/persistence-service-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/model/multitenancy/TenantRequest.java @@ -14,11 +14,12 @@ import lombok.NoArgsConstructor; @NoArgsConstructor public class TenantRequest { - @NotNull + @NotBlank private String tenantId; @NotBlank private String displayName; private String guid; + @NotBlank private String jdbcUrl; @NotBlank private String user; diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/controller/ControllerAdvice.java b/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/controller/ControllerAdvice.java index 0a8515b48..36adba632 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/controller/ControllerAdvice.java +++ b/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/controller/ControllerAdvice.java @@ -1,8 +1,10 @@ package com.iqser.red.service.peristence.v1.server.controller; +import java.sql.SQLException; import java.time.OffsetDateTime; +import java.util.List; +import java.util.stream.Collectors; -import org.postgresql.util.PSQLException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -83,8 +85,8 @@ public class ControllerAdvice { @ResponseBody - @ExceptionHandler(value = PSQLException.class) - public ResponseEntity handleSQLException(PSQLException e) { + @ExceptionHandler(value = SQLException.class) + public ResponseEntity handleSQLException(SQLException e) { if (e.getMessage().contains("violates unique constraint")) { return new ResponseEntity<>(new ErrorMessage(OffsetDateTime.now(), "Unique constraint violation"), HttpStatus.CONFLICT); @@ -99,8 +101,9 @@ public class ControllerAdvice { @ResponseStatus(value = HttpStatus.BAD_REQUEST) @ExceptionHandler(value = MethodArgumentNotValidException.class) public ErrorMessage handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { - - return new ErrorMessage(OffsetDateTime.now(), e.getMessage()); + var errorList = e.getFieldErrors(); + String errorListAsString = errorList.stream().map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage()).collect(Collectors.joining(", ")); + return new ErrorMessage(OffsetDateTime.now(), String.format("You have empty/wrong formatted parameters: %s", errorListAsString)); } } diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/service/TenantManagementService.java b/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/service/TenantManagementService.java index a47fcedbc..ab713f923 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/service/TenantManagementService.java +++ b/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/service/TenantManagementService.java @@ -1,8 +1,10 @@ package com.iqser.red.service.peristence.v1.server.service; +import java.net.URI; import java.sql.Connection; import java.sql.DriverManager; import java.util.List; +import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -16,7 +18,6 @@ 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.exception.BadRequestException; import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.multitenancy.entity.TenantEntity; @@ -28,11 +29,15 @@ import com.iqser.red.service.persistence.service.v1.api.model.multitenancy.Tenan import liquibase.exception.LiquibaseException; import liquibase.integration.spring.SpringLiquibase; import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +@Slf4j @Service @EnableConfigurationProperties(LiquibaseProperties.class) public class TenantManagementService { + private static final Set SQL_CONNECTION_ERROR_CODES = Set.of("08000", "08003", "08006"); + private final EncryptionDecryptionService encryptionService; private final LiquibaseProperties liquibaseProperties; @@ -58,11 +63,16 @@ public class TenantManagementService { if (tenantRepository.findById(tenantRequest.getTenantId()).isEmpty()) { + validateJdbcUrl(tenantRequest.getJdbcUrl()); + String encryptedPassword = encryptionService.encrypt(tenantRequest.getPassword()); try (Connection connection = DriverManager.getConnection(tenantRequest.getJdbcUrl(), tenantRequest.getUser(), tenantRequest.getPassword())) { DataSource tenantDataSource = new SingleConnectionDataSource(connection, false); runLiquibase(tenantDataSource); + } catch (PSQLException e) { + handleClientException(e); + handleInternalException(e); } TenantEntity tenantEntity = TenantEntity.builder() @@ -80,6 +90,25 @@ public class TenantManagementService { } + private void handleClientException(PSQLException e) { + + if (e.getSQLState().equals("28000") || e.getSQLState().equals("28P01")) { + throw new IllegalArgumentException("Database credentials are not correct. Please check them."); + } + if (SQL_CONNECTION_ERROR_CODES.contains(e.getSQLState())) { + throw new IllegalArgumentException("Error when connecting to tenant database. Please check the jdbcUrl parameter."); + } + } + + + private void handleInternalException(PSQLException e) { + + log.error(String.format("Connection to tenant DB failed with SQL state %s. Please check if the tenant DB is still running. " + // + "If yes please check the connection configuration.", e.getSQLState()), e); + throw new RuntimeException("Could not connect to the tenant DB. This is an internal error.", e); + } + + public List getTenants() { return tenantRepository.findAll().stream().map(this::convert).collect(Collectors.toList()); @@ -92,6 +121,14 @@ public class TenantManagementService { } + @SneakyThrows + private void validateJdbcUrl(String jdbcUrl) { + // just create a URI object to check if the string is a valid URI + new URI(jdbcUrl); + + } + + private TenantResponse convert(TenantEntity entity) { return TenantResponse.builder()