From f072de8d2cf73150ed90a5cac649e2ea6307c90f Mon Sep 17 00:00:00 2001 From: DarioGii Date: Wed, 18 Dec 2024 13:21:33 +0000 Subject: [PATCH] #2270: wip - settings.yml not being read for some classes? --- .../security/database/DatabaseConfig.java | 106 ++++++++++-------- .../security/database/DatabaseService.java | 7 +- .../SPDF/model/ApplicationProperties.java | 23 ++-- src/main/resources/application.properties | 2 +- src/main/resources/settings.yml.template | 14 +-- .../security/database/DatabaseConfigTest.java | 77 +++++++++++++ 6 files changed, 165 insertions(+), 64 deletions(-) create mode 100644 src/test/java/stirling/software/SPDF/config/security/database/DatabaseConfigTest.java diff --git a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseConfig.java b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseConfig.java index 1a82a4632e1..eab29f3e38c 100644 --- a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseConfig.java +++ b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseConfig.java @@ -13,16 +13,14 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.model.provider.UnsupportedProviderException; @Getter @Slf4j @Configuration public class DatabaseConfig { - public static final String DOCKER_HOST = "://db:"; - public static final String LOCALHOST = "://localhost:"; - public static final String POSTGRES = "postgres"; - public static final String DATASOURCE_PREFIX = "jdbc"; + public static final String DATASOURCE_URL_TEMPLATE = "jdbc:%s://%s:%4d/%s"; private final ApplicationProperties applicationProperties; @@ -31,12 +29,15 @@ public DatabaseConfig(@Autowired ApplicationProperties applicationProperties) { } /** - * Creates the DataSource for the connection to the DB. If the active profile is - * set to 'default' it will use local configiration, namely using localhost as the host - * for the connection. If set to 'docker' it will use the Dokcer server configuration. + * Creates the DataSource for the connection to the DB. If useDefault + * is set to true, it will use the default H2 DB. If it is set to false + * , it will use the user's custom configuration set in the settings.yml. + * + * @return a DataSource using the configuration settings in the settings.yml + * @throws UnsupportedProviderException if the type of database selected is not supported */ @Bean - public DataSource dataSource() { + public DataSource dataSource() throws UnsupportedProviderException { ApplicationProperties.System system = applicationProperties.getSystem(); ApplicationProperties.Datasource datasource = system.getDatasource(); DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); @@ -51,57 +52,72 @@ public DataSource dataSource() { return dataSourceBuilder.build(); } - dataSourceBuilder.driverClassName( - getDriverClassName( - ApplicationProperties.Driver.valueOf(datasource.getType().toUpperCase()))); - dataSourceBuilder.url(getDataSourceUrl(datasource)); + dataSourceBuilder.driverClassName(getDriverClassName(datasource.getType())); + dataSourceBuilder.url( + getDataSourceUrl( + datasource.getType(), + datasource.getHostName(), + datasource.getPort(), + datasource.getName())); dataSourceBuilder.username(datasource.getUsername()); dataSourceBuilder.password(datasource.getPassword()); return dataSourceBuilder.build(); } - private String getDataSourceUrl(ApplicationProperties.Datasource datasource) { - return DATASOURCE_PREFIX - + ":" - + datasource.getType() - + "://" - + datasource.getHostName() - + ":" - + datasource.getPort() - + "/" - + datasource.getName(); + /** + * Generate the URL the DataSource will use to connect to the database + * + * @param dataSourceType the type of the database + * @param hostname the host name + * @param port the port number to use for the database + * @param dataSourceName the name the database to connect to + * @return the DataSource URL + */ + private String getDataSourceUrl( + String dataSourceType, String hostname, Integer port, String dataSourceName) { + return DATASOURCE_URL_TEMPLATE.formatted(dataSourceType, hostname, port, dataSourceName); } - public Connection connection() throws SQLException { + /** + * @return a Connection using the configured DataSource + * @throws SQLException if a database access error occurs + * @throws UnsupportedProviderException when an unsupported database is selected + */ + public Connection connection() throws SQLException, UnsupportedProviderException { return dataSource().getConnection(); } /** - * Selects the DB driver based on the stirling.software.SPDF.model.Driver chosen. + * Selects the database driver based on the type of database chosen. + * + * @param driverName the type of the driver (e.g. 'h2', 'postgresql') + * @return the fully qualified driver for the database chosen + * @throws UnsupportedProviderException when an unsupported database is selected */ - private String getDriverClassName(ApplicationProperties.Driver driverName) { - switch (driverName) { - case H2 -> { - log.debug("H2 driver selected"); - return "org.h2.Driver"; - } - case POSTGRESQL -> { - log.debug("Postgres driver selected"); - return "org.postgresql.Driver"; - } - case ORACLE -> { - log.debug("Oracle driver selected"); - return "oracle.jdbc.OracleDriver"; - } - case MY_SQL -> { - log.debug("MySQL driver selected"); - return "com.mysql.cj.jdbc.Driver"; - } - default -> { - log.debug("Defaulting to H2 driver"); - return "org.h2.Driver"; + private String getDriverClassName(String driverName) throws UnsupportedProviderException { + try { + ApplicationProperties.Driver driver = + ApplicationProperties.Driver.valueOf(driverName.toUpperCase()); + + switch (driver) { + case H2 -> { + log.debug("H2 driver selected"); + return "org.h2.Driver"; + } + case POSTGRESQL -> { + log.debug("Postgres driver selected"); + return "org.postgresql.Driver"; + } + default -> { + log.warn("{} driver selected", driverName); + throw new UnsupportedProviderException( + driverName + " is not currently supported"); + } } + } catch (IllegalArgumentException e) { + log.warn("Unknown driver: {}", driverName); + throw new UnsupportedProviderException(driverName + " is not currently supported"); } } } diff --git a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseService.java b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseService.java index 20f7400879d..9e22a1cf807 100644 --- a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseService.java +++ b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseService.java @@ -27,6 +27,7 @@ import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.config.interfaces.DatabaseInterface; +import stirling.software.SPDF.model.provider.UnsupportedProviderException; import stirling.software.SPDF.utils.FileInfo; @Slf4j @@ -124,7 +125,7 @@ public void exportDatabase() { conn, new EncodedResource(new PathResource(insertOutputFilePath))); log.info("Database export completed: {}", insertOutputFilePath); - } catch (SQLException e) { + } catch (SQLException | UnsupportedProviderException e) { log.error("Error during database export: {}", e.getMessage(), e); } catch (ScriptException e) { log.error("Error during database export: File {} not found", insertOutputFilePath); @@ -156,7 +157,7 @@ public String getH2Version() { log.info("H2 Database Version: {}", version); } } - } catch (SQLException e) { + } catch (SQLException | UnsupportedProviderException e) { log.error("Error retrieving H2 version: {}", e.getMessage(), e); } return version; @@ -192,7 +193,7 @@ private void executeDatabaseScript(Path scriptPath) { ScriptUtils.executeSqlScript(conn, new EncodedResource(new PathResource(scriptPath))); log.info("Database import completed: {}", scriptPath); - } catch (SQLException e) { + } catch (SQLException | UnsupportedProviderException e) { log.error("Error during database import: {}", e.getMessage(), e); } catch (ScriptException e) { log.error("Error: File {} not found", scriptPath.toString(), e); diff --git a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java index 5b030f44174..ab1c51dfc0d 100644 --- a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java +++ b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java @@ -6,7 +6,6 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.sql.Driver; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -240,7 +239,6 @@ public Provider get(String registrationId) throws UnsupportedProviderException { @Data public static class System { - private Boolean localEnv; private String defaultLocale; private Boolean googlevisibility; private boolean showUpdate; @@ -249,33 +247,42 @@ public static class System { private String tessdataDir; private Boolean enableAlphaFunctionality; private String enableAnalytics; - private String environmentName; private Datasource datasource; } @Data public static class Datasource { - private boolean useDefault; - private String name; private String type; private String hostName; - private String port; - private String defaultUrl; + private Integer port; + private String name; private String username; @ToString.Exclude private String password; + private boolean useDefault; + private final String defaultUrl; } public enum Driver { H2("h2"), POSTGRESQL("postgresql"), ORACLE("oracle"), - MY_SQL("mysql"); + MYSQL("mysql"); private final String driverName; Driver(String driverName) { this.driverName = driverName; } + + @Override + public String toString() { + return """ + Driver { + driverName='%s' + } + """ + .formatted(driverName); + } } @Data diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 15dcedafb56..46a970ba6f8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -45,7 +45,7 @@ spring.datasource.username=sa spring.datasource.password= spring.h2.console.enabled=false spring.jpa.hibernate.ddl-auto=update -#spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +#spring.jpa.database-platform=org.hibernate.dialect.H2Dialect todo: check if needed server.servlet.session.timeout=30m # Change the default URL path for OpenAPI JSON springdoc.api-docs.path=/v1/api-docs diff --git a/src/main/resources/settings.yml.template b/src/main/resources/settings.yml.template index ff007d2099c..79fe150cd02 100644 --- a/src/main/resources/settings.yml.template +++ b/src/main/resources/settings.yml.template @@ -86,14 +86,14 @@ system: tessdataDir: /usr/share/tessdata # path to the directory containing the Tessdata files. This setting is relevant for Windows systems. For Windows users, this path should be adjusted to point to the appropriate directory where the Tessdata files are stored. enableAnalytics: undefined # set to 'true' to enable analytics, set to 'false' to disable analytics; for enterprise users, this is set to true datasource: - type: postgresql - hostName: localhost - port: 5432 - name: postgres - useDefault: false + type: 'postgresql' # the type of the database to set (e.g. 'h2', 'postgresql') + hostName: 'localhost' # the host name to use for the database url. Set to 'localhost' when running the app locally. Set to match the name of the container name of your database container when running the app on a server (Docker configuration) + port: 5432 # set the port number of the database. Ensure this matches the port the database is listening to + name: 'postgres' # set the name of your database. Should match the name of the database you create + username: 'postgres' # set the database username + password: 'postgres' # set the database password + useDefault: 'false' # set this property to 'true' if you would like to use the default database configuration defaultUrl: jdbc:h2:file:./configs/stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE - username: postgres - password: postgres ui: appName: '' # application's visible name diff --git a/src/test/java/stirling/software/SPDF/config/security/database/DatabaseConfigTest.java b/src/test/java/stirling/software/SPDF/config/security/database/DatabaseConfigTest.java new file mode 100644 index 00000000000..74ac58c0af3 --- /dev/null +++ b/src/test/java/stirling/software/SPDF/config/security/database/DatabaseConfigTest.java @@ -0,0 +1,77 @@ +package stirling.software.SPDF.config.security.database; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.model.provider.UnsupportedProviderException; + +import javax.sql.DataSource; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class DatabaseConfigTest { + + @Mock + private ApplicationProperties applicationProperties; + + @InjectMocks + private DatabaseConfig databaseConfig; + + @Test + void testDefaultConfigurationForDataSource() throws UnsupportedProviderException { + var system = mock(ApplicationProperties.System.class); + var datasource = mock(ApplicationProperties.Datasource.class); + var testUrl = "jdbc:h2:mem:test"; + + when(applicationProperties.getSystem()).thenReturn(system); + when(system.getDatasource()).thenReturn(datasource); + when(datasource.isUseDefault()).thenReturn(true); + when(datasource.getDefaultUrl()).thenReturn(testUrl); + + var result = databaseConfig.dataSource(); + + assertInstanceOf(DataSource.class, result); + } + + @Test + void testCustomConfigurationForDataSource() throws UnsupportedProviderException { + var system = mock(ApplicationProperties.System.class); + var datasource = mock(ApplicationProperties.Datasource.class); + + when(applicationProperties.getSystem()).thenReturn(system); + when(system.getDatasource()).thenReturn(datasource); + when(datasource.isUseDefault()).thenReturn(false); + when(datasource.getType()).thenReturn("postgresql"); + when(datasource.getHostName()).thenReturn("localhost"); + when(datasource.getPort()).thenReturn(5432); + when(datasource.getName()).thenReturn("postgres"); + when(datasource.getUsername()).thenReturn("postgres"); + when(datasource.getPassword()).thenReturn("postgres"); + + var result = databaseConfig.dataSource(); + + assertInstanceOf(DataSource.class, result); + } + + @ParameterizedTest(name = "Exception thrown when the DB type [{arguments}] is not supported") + @ValueSource(strings = {"oracle", "mysql", "mongoDb"}) + void exceptionThrownWhenDBTypeIsUnsupported(String datasourceType) { + var system = mock(ApplicationProperties.System.class); + var datasource = mock(ApplicationProperties.Datasource.class); + + when(applicationProperties.getSystem()).thenReturn(system); + when(system.getDatasource()).thenReturn(datasource); + when(datasource.isUseDefault()).thenReturn(false); + when(datasource.getType()).thenReturn(datasourceType); + + assertThrows(UnsupportedProviderException.class, () -> databaseConfig.dataSource()); + } +} \ No newline at end of file