From d006fdd19cd2cca11a28f62bf904fb68715c61e1 Mon Sep 17 00:00:00 2001 From: sergiyvamz <75754709+sergiyvamz@users.noreply.github.com> Date: Fri, 2 Jun 2023 17:28:24 -0700 Subject: [PATCH] fix failing HikariCP integration test (#468) Co-authored-by: sergiyv-bitquill Co-authored-by: Karen <64801825+karenc-bq@users.noreply.github.com> --- docs/using-the-jdbc-driver/DataSource.md | 47 ++--- .../software/amazon/DatasourceExample.java | 7 +- ...iteSplittingSpringJdbcTemplateExample.java | 19 +- .../java/software/amazon/HikariExample.java | 17 +- .../amazon/HikariFailoverExample.java | 13 +- .../jdbc/DataSourceConnectionProvider.java | 40 +--- .../amazon/jdbc/PropertyDefinition.java | 26 ++- .../amazon/jdbc/ds/AwsWrapperDataSource.java | 183 +++++++++--------- .../jdbc/ds/AwsWrapperDataSourceFactory.java | 7 +- .../efm/HostMonitoringConnectionPlugin.java | 1 + .../GenericTargetDriverDialect.java | 54 ++---- .../MariadbDataSourceHelper.java | 8 +- .../MariadbTargetDriverDialect.java | 15 +- .../MysqlConnectorJDataSourceHelper.java | 5 + .../MysqlConnectorJTargetDriverDialect.java | 7 +- .../PgDataSourceHelper.java | 5 + .../PgTargetDriverDialect.java | 7 +- .../TargetDriverDialect.java | 7 +- .../jdbc/util/ConnectionUrlBuilder.java | 86 ++++---- .../src/main/resources/messages.properties | 4 +- .../container/ConnectionStringHelper.java | 41 ++-- .../refactored/container/ProxyHelper.java | 19 +- .../container/TestDriverProvider.java | 9 +- .../tests/AdvancedPerformanceTest.java | 2 +- .../container/tests/AuroraFailoverTest.java | 12 +- .../tests/AwsIamIntegrationTest.java | 11 +- .../tests/BasicConnectivityTests.java | 4 +- .../container/tests/DataSourceTests.java | 24 +-- .../container/tests/HikariTests.java | 68 ++++--- .../integration/util/AuroraTestUtility.java | 2 +- .../jdbc/ds/AwsWrapperDataSourceTest.java | 51 ++--- .../jdbc/util/ConnectionUrlBuilderTest.java | 33 +--- .../amazon/logging/ExtendedFormatter.java | 4 +- .../test/resources/simplelogger.properties | 4 +- 34 files changed, 353 insertions(+), 489 deletions(-) diff --git a/docs/using-the-jdbc-driver/DataSource.md b/docs/using-the-jdbc-driver/DataSource.md index b847d906a..4d0f8237d 100644 --- a/docs/using-the-jdbc-driver/DataSource.md +++ b/docs/using-the-jdbc-driver/DataSource.md @@ -11,22 +11,18 @@ To establish a connection with the AwsWrapperDataSource, you must: ### Configurable DataSource Properties -To allow the AWS Advanced JDBC Driver to work with multiple driver-specific datasources, -you need to specify what property names the underlying datasource uses. -For example, one datasource implementation could use the method `setUser` to set the datasource username, -while another might use the method `setUsername` for the same task. See the table below for a list of configurable property names. - -> **:warning: Note:** If the same connection property is provided both explicitly in the connection URL and in the datasource properties, the value set in the connection URL will take precedence. - -| Property | Configuration Method | Description | Type | Required | Example | -|-----------------------------|--------------------------------|---------------------------------------------------------------------------------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------| -| Server name | `setServerPropertyName` | The name of the server or host property. | `String` | Yes, if no URL is provided. | `serverName` | -| Database name | `setDatabasePropertyName` | The name of the database property. | `String` | No | `databaseName` | -| Port name | `setPortPropertyName` | The name of the port property. | `String` | No | `port` | -| URL name | `setUrlPropertyName` | The name of the URL property. | `String` | No, but some drivers, such as MariaDb, require some parameters to be included in the URL so it is recommended to provide this parameter. | `url` | -| JDBC URL | `setJdbcUrl` | The URL to connect with. | `String` | No, if there is enough information provided by the other properties that can be used to create a URL. | `jdbc:postgresql://localhost/postgres` | -| JDBC protocol | `setJdbcProtocol` | The JDBC protocol that will be used. | `String` | Yes, if the JDBC URL has not been set. | `jdbc:postgresql:` | -| Underlying DataSource class | `setTargetDataSourceClassName` | The fully qualified class name of the underlying DataSource class the AWS JDBC Driver should use. | `String` | Yes, if the JDBC URL has not been set. | `org.postgresql.ds.PGSimpleDataSource` | +See the table below for a list of configurable properties. + +> **:warning: Note:** If the same connection property is provided both explicitly in the connection URL and in the datasource properties, the value set in the datasource properties will take precedence. + +| Property | Configuration Method | Description | Type | Required | Example | +|-----------------------------|--------------------------------|---------------------------------------------------------------------------------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------| +| Server name | `setServerName` | The name of the server. | `String` | Yes, if no URL is provided. | `db-server.mydomain.com` | +| Server port | `setServerPort` | The server port. | `String` | No | `5432` | +| Database name | `setDatabase` | The name of the database. | `String` | No | `testDatabase` | +| JDBC URL | `setJdbcUrl` | The URL to connect with. | `String` | No. Either URL or server name should be set. If both URL and server name have been set, URL will take precedence. Please note that some drivers, such as MariaDb, require some parameters to be included particularly in the URL. | `jdbc:postgresql://localhost/postgres` | +| JDBC protocol | `setJdbcProtocol` | The JDBC protocol that will be used. | `String` | Yes, if the JDBC URL has not been set. | `jdbc:postgresql:` | +| Underlying DataSource class | `setTargetDataSourceClassName` | The fully qualified class name of the underlying DataSource class the AWS JDBC Driver should use. | `String` | Yes, if the JDBC URL has not been set. | `org.postgresql.ds.PGSimpleDataSource` | ## Using the AwsWrapperDataSource with Connection Pooling Frameworks @@ -63,21 +59,20 @@ To use the AWS JDBC Driver with a connection pool, you must: ```java // Note: jdbcProtocol is required when connecting via server name ds.addDataSourceProperty("jdbcProtocol", "jdbc:postgresql:"); - ds.addDataSourceProperty("serverPropertyName", "serverName"); - - ds.addDataSourceProperty("databasePropertyName", "databaseName"); - ds.addDataSourceProperty("portPropertyName", "port"); + ds.addDataSourceProperty("serverName", "db-identifier.cluster-XYZ.us-east-2.rds.amazonaws.com"); + ds.addDataSourceProperty("serverPort", "5432"); + ds.addDataSourceProperty("database", "postgres"); ``` -4. Configure the driver-specific datasource: +4. Set the driver-specific datasource: ```java ds.addDataSourceProperty("targetDataSourceClassName", "org.postgresql.ds.PGSimpleDataSource"); - + ``` + +5. Configure the driver-specific datasource, if needed. This step is optional: + ```java Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty("serverName", "db-identifier.cluster-XYZ.us-east-2.rds.amazonaws.com"); - targetDataSourceProps.setProperty("databaseName", "postgres"); - targetDataSourceProps.setProperty("port", "5432"); - + targetDataSourceProps.setProperty("socketTimeout", "10"); ds.addDataSourceProperty("targetDataSourceProperties", targetDataSourceProps); ``` diff --git a/examples/AWSDriverExample/src/main/java/software/amazon/DatasourceExample.java b/examples/AWSDriverExample/src/main/java/software/amazon/DatasourceExample.java index bd3945fe3..e0cbd137a 100644 --- a/examples/AWSDriverExample/src/main/java/software/amazon/DatasourceExample.java +++ b/examples/AWSDriverExample/src/main/java/software/amazon/DatasourceExample.java @@ -32,9 +32,6 @@ public static void main(String[] args) throws SQLException { // Configure the property names for the underlying driver-specific data source: ds.setJdbcProtocol("jdbc:postgresql:"); - ds.setDatabasePropertyName("databaseName"); - ds.setServerPropertyName("serverName"); - ds.setPortPropertyName("port"); // Specify the driver-specific data source: ds.setTargetDataSourceClassName("org.postgresql.ds.PGSimpleDataSource"); @@ -42,8 +39,8 @@ public static void main(String[] args) throws SQLException { // Configure the driver-specific data source: Properties targetDataSourceProps = new Properties(); targetDataSourceProps.setProperty("serverName", "db-identifier.cluster-XYZ.us-east-2.rds.amazonaws.com"); - targetDataSourceProps.setProperty("databaseName", "employees"); - targetDataSourceProps.setProperty("port", "5432"); + targetDataSourceProps.setProperty("database", "employees"); + targetDataSourceProps.setProperty("serverPort", "5432"); ds.setTargetDataSourceProperties(targetDataSourceProps); // Try and make a connection: diff --git a/examples/AWSDriverExample/src/main/java/software/amazon/ReadWriteSplittingSpringJdbcTemplateExample.java b/examples/AWSDriverExample/src/main/java/software/amazon/ReadWriteSplittingSpringJdbcTemplateExample.java index 8ed560567..e5f5f6890 100644 --- a/examples/AWSDriverExample/src/main/java/software/amazon/ReadWriteSplittingSpringJdbcTemplateExample.java +++ b/examples/AWSDriverExample/src/main/java/software/amazon/ReadWriteSplittingSpringJdbcTemplateExample.java @@ -79,18 +79,15 @@ private static void scenario3() throws SQLException { private static DataSource getSimplePostgresDataSource() { AwsWrapperDataSource ds = new AwsWrapperDataSource(); ds.setJdbcProtocol("jdbc:postgresql:"); - ds.setDatabasePropertyName("databaseName"); - ds.setServerPropertyName("serverName"); - ds.setPortPropertyName("port"); + ds.setServerName(DATABASE_URL); + ds.setDatabase(DATABASE_NAME); + ds.setServerPort("5432"); ds.setTargetDataSourceClassName("org.postgresql.ds.PGSimpleDataSource"); Properties targetDataSourceProps = new Properties(); targetDataSourceProps.setProperty( PropertyDefinition.PLUGINS.name, "readWriteSplitting,failover,efm"); - targetDataSourceProps.setProperty("serverName", DATABASE_URL); - targetDataSourceProps.setProperty("databaseName", DATABASE_NAME); - targetDataSourceProps.setProperty("port", "5432"); ds.setUser(USERNAME); ds.setPassword(PASSWORD); @@ -112,19 +109,15 @@ private static DataSource getHikariCPDataSource() { ds.setDataSourceClassName(AwsWrapperDataSource.class.getName()); ds.addDataSourceProperty("jdbcProtocol", "jdbc:postgresql:"); - ds.addDataSourceProperty("serverPropertyName", "serverName"); - - ds.addDataSourceProperty("databasePropertyName", "databaseName"); - ds.addDataSourceProperty("portPropertyName", "port"); + ds.addDataSourceProperty("serverName", DATABASE_URL); + ds.addDataSourceProperty("serverPort", "5432"); + ds.addDataSourceProperty("database", DATABASE_NAME); ds.addDataSourceProperty("targetDataSourceClassName", "org.postgresql.ds.PGSimpleDataSource"); Properties targetDataSourceProps = new Properties(); targetDataSourceProps.setProperty(PropertyDefinition.PLUGINS.name, "readWriteSplitting,failover,efm"); - targetDataSourceProps.setProperty("serverName", DATABASE_URL); - targetDataSourceProps.setProperty("databaseName", DATABASE_NAME); - targetDataSourceProps.setProperty("port", "5432"); ds.addDataSourceProperty("targetDataSourceProperties", targetDataSourceProps); diff --git a/examples/HikariExample/src/main/java/software/amazon/HikariExample.java b/examples/HikariExample/src/main/java/software/amazon/HikariExample.java index 81a668cc2..44799ef11 100644 --- a/examples/HikariExample/src/main/java/software/amazon/HikariExample.java +++ b/examples/HikariExample/src/main/java/software/amazon/HikariExample.java @@ -43,20 +43,17 @@ public static void main(String[] args) throws SQLException { // Configure AwsWrapperDataSource: ds.addDataSourceProperty("jdbcProtocol", "jdbc:postgresql:"); - ds.addDataSourceProperty("databasePropertyName", "databaseName"); - ds.addDataSourceProperty("portPropertyName", "portNumber"); - ds.addDataSourceProperty("serverPropertyName", "serverName"); + ds.addDataSourceProperty("database", DATABASE_NAME); + ds.addDataSourceProperty("serverPort", "5432"); + ds.addDataSourceProperty("serverName", ENDPOINT); // Specify the driver-specific data source for AwsWrapperDataSource: ds.addDataSourceProperty("targetDataSourceClassName", "org.postgresql.ds.PGSimpleDataSource"); - // Configuring PGSimpleDataSource: - Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty("serverName", ENDPOINT); - targetDataSourceProps.setProperty("databaseName", DATABASE_NAME); - targetDataSourceProps.setProperty("portNumber", "5432"); - - ds.addDataSourceProperty("targetDataSourceProperties", targetDataSourceProps); + // Configuring PGSimpleDataSource (optional): + // Properties targetDataSourceProps = new Properties(); + // targetDataSourceProps.setProperty("socketTimeout", "10"); + // ds.addDataSourceProperty("targetDataSourceProperties", targetDataSourceProps); // Attempt a connection: try (final Connection conn = ds.getConnection(); diff --git a/examples/HikariExample/src/main/java/software/amazon/HikariFailoverExample.java b/examples/HikariExample/src/main/java/software/amazon/HikariFailoverExample.java index 6dce1bbd8..3d6d141dc 100644 --- a/examples/HikariExample/src/main/java/software/amazon/HikariFailoverExample.java +++ b/examples/HikariExample/src/main/java/software/amazon/HikariFailoverExample.java @@ -46,9 +46,9 @@ public static void main(String[] args) throws SQLException { // Configure AwsWrapperDataSource: ds.addDataSourceProperty("jdbcProtocol", "jdbc:postgresql:"); - ds.addDataSourceProperty("databasePropertyName", "databaseName"); - ds.addDataSourceProperty("portPropertyName", "portNumber"); - ds.addDataSourceProperty("serverPropertyName", "serverName"); + ds.addDataSourceProperty("serverName", ENDPOINT); + ds.addDataSourceProperty("portNumber", "5432"); + ds.addDataSourceProperty("database", DATABASE_NAME); // The failover plugin throws failover-related exceptions that need to be handled explicitly by HikariCP, // otherwise connections will be closed immediately after failover. Set `ExceptionOverrideClassName` to provide @@ -58,11 +58,10 @@ public static void main(String[] args) throws SQLException { // Specify the driver-specific data source for AwsWrapperDataSource: ds.addDataSourceProperty("targetDataSourceClassName", "org.postgresql.ds.PGSimpleDataSource"); - // Configuring PGSimpleDataSource: Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty("serverName", ENDPOINT); - targetDataSourceProps.setProperty("databaseName", DATABASE_NAME); - targetDataSourceProps.setProperty("portNumber", "5432"); + + // Configuring PGSimpleDataSource if needed: + // targetDataSourceProps.setProperty("ssl", "true"); // Enable the failover and host monitoring connection plugins. targetDataSourceProps.setProperty("wrapperPlugins", "failover,efm"); diff --git a/wrapper/src/main/java/software/amazon/jdbc/DataSourceConnectionProvider.java b/wrapper/src/main/java/software/amazon/jdbc/DataSourceConnectionProvider.java index d2dd33b8a..76ed24ba3 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/DataSourceConnectionProvider.java +++ b/wrapper/src/main/java/software/amazon/jdbc/DataSourceConnectionProvider.java @@ -16,8 +16,6 @@ package software.amazon.jdbc; -import static software.amazon.jdbc.util.StringUtils.isNullOrEmpty; - import java.sql.Connection; import java.sql.SQLException; import java.util.Collections; @@ -29,7 +27,6 @@ import java.util.logging.Logger; import javax.sql.DataSource; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import software.amazon.jdbc.dialect.Dialect; import software.amazon.jdbc.exceptions.SQLLoginException; import software.amazon.jdbc.targetdriverdialect.TargetDriverDialect; @@ -53,10 +50,6 @@ public class DataSourceConnectionProvider implements ConnectionProvider { } }); private final @NonNull DataSource dataSource; - private final @Nullable String serverPropertyName; - private final @Nullable String portPropertyName; - private final @Nullable String urlPropertyName; - private final @Nullable String databasePropertyName; private final @NonNull TargetDriverDialect targetDriverDialect; @@ -64,17 +57,9 @@ public class DataSourceConnectionProvider implements ConnectionProvider { public DataSourceConnectionProvider( final @NonNull DataSource dataSource, - final @NonNull TargetDriverDialect targetDriverDialect, - final @Nullable String serverPropertyName, - final @Nullable String portPropertyName, - final @Nullable String urlPropertyName, - final @Nullable String databasePropertyName) { + final @NonNull TargetDriverDialect targetDriverDialect) { this.dataSource = dataSource; this.targetDriverDialect = targetDriverDialect; - this.serverPropertyName = serverPropertyName; - this.portPropertyName = portPropertyName; - this.urlPropertyName = urlPropertyName; - this.databasePropertyName = databasePropertyName; } /** @@ -143,11 +128,7 @@ public Connection connect( ds, protocol, hostSpec, - copy, - this.serverPropertyName, - this.portPropertyName, - this.urlPropertyName, - this.databasePropertyName); + copy); conn = ds.getConnection(); } else { @@ -161,11 +142,7 @@ public Connection connect( this.dataSource, protocol, hostSpec, - copy, - this.serverPropertyName, - this.portPropertyName, - this.urlPropertyName, - this.databasePropertyName); + copy); conn = this.dataSource.getConnection(); } finally { this.lock.unlock(); @@ -191,16 +168,7 @@ public Connection connect( @Deprecated public Connection connect(final @NonNull String url, final @NonNull Properties props) throws SQLException { final Properties copy = PropertyUtils.copyProperties(props); - - if (!isNullOrEmpty(this.urlPropertyName)) { - copy.setProperty(this.urlPropertyName, url); - } - - if (!isNullOrEmpty(this.databasePropertyName) - && !isNullOrEmpty(PropertyDefinition.DATABASE.getString(props))) { - copy.put(this.databasePropertyName, PropertyDefinition.DATABASE.getString(props)); - } - + copy.setProperty("url", url); PropertyDefinition.removeAllExceptCredentials(copy); PropertyUtils.applyProperties(this.dataSource, copy); return this.dataSource.getConnection(); diff --git a/wrapper/src/main/java/software/amazon/jdbc/PropertyDefinition.java b/wrapper/src/main/java/software/amazon/jdbc/PropertyDefinition.java index 4fc83557e..19b5d91e8 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/PropertyDefinition.java +++ b/wrapper/src/main/java/software/amazon/jdbc/PropertyDefinition.java @@ -19,10 +19,12 @@ import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; public class PropertyDefinition { @@ -63,10 +65,10 @@ public class PropertyDefinition { "database", null, "Driver database name"); private static final Map PROPS_BY_NAME = - new HashMap<>(); + new ConcurrentHashMap<>(); + private static final Set KNOWN_PROPS_BY_PREFIX = ConcurrentHashMap.newKeySet(); static { - PROPS_BY_NAME.clear(); registerProperties(PropertyDefinition.class); } @@ -82,21 +84,35 @@ public static void registerPluginProperties(final Class pluginClass) { registerProperties(pluginClass); } + public static void registerPluginProperties(final @NonNull String propertyNamePrefix) { + KNOWN_PROPS_BY_PREFIX.add(propertyNamePrefix); + } + public static void removeAll(final Properties props) { PROPS_BY_NAME.keySet().forEach(props::remove); + + props.stringPropertyNames().stream() + .filter(propertyName -> KNOWN_PROPS_BY_PREFIX.stream() + .anyMatch(propertyName::startsWith)) + .forEach(props::remove); } public static void removeAllExcept(final Properties props, String... propNames) { - Set propsToDelete = PROPS_BY_NAME.keySet(); + Set propsToDelete = new HashSet<>(PROPS_BY_NAME.keySet()); Arrays.asList(propNames).forEach(propsToDelete::remove); propsToDelete.forEach(props::remove); + + props.stringPropertyNames().stream() + .filter(propertyName -> KNOWN_PROPS_BY_PREFIX.stream() + .anyMatch(propertyName::startsWith)) + .forEach(props::remove); } public static void removeAllExceptCredentials(final Properties props) { final String user = props.getProperty(PropertyDefinition.USER.name, null); final String password = props.getProperty(PropertyDefinition.PASSWORD.name, null); - PROPS_BY_NAME.keySet().forEach(props::remove); + removeAll(props); if (user != null) { props.setProperty(PropertyDefinition.USER.name, user); diff --git a/wrapper/src/main/java/software/amazon/jdbc/ds/AwsWrapperDataSource.java b/wrapper/src/main/java/software/amazon/jdbc/ds/AwsWrapperDataSource.java index d13e37b0f..359b52ed3 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/ds/AwsWrapperDataSource.java +++ b/wrapper/src/main/java/software/amazon/jdbc/ds/AwsWrapperDataSource.java @@ -39,6 +39,7 @@ import software.amazon.jdbc.DataSourceConnectionProvider; import software.amazon.jdbc.Driver; import software.amazon.jdbc.DriverConnectionProvider; +import software.amazon.jdbc.HostSpec; import software.amazon.jdbc.PropertyDefinition; import software.amazon.jdbc.targetdriverdialect.TargetDriverDialect; import software.amazon.jdbc.targetdriverdialect.TargetDriverDialectManager; @@ -54,6 +55,9 @@ public class AwsWrapperDataSource implements DataSource, Referenceable, Serializ private static final Logger LOGGER = Logger.getLogger(AwsWrapperDataSource.class.getName()); + private static final String SERVER_NAME = "serverName"; + private static final String SERVER_PORT = "serverPort"; + static { try { if (!Driver.isRegistered()) { @@ -71,13 +75,13 @@ public class AwsWrapperDataSource implements DataSource, Referenceable, Serializ protected @Nullable String targetDataSourceClassName; protected @Nullable Properties targetDataSourceProperties; protected @Nullable String jdbcProtocol; - protected @Nullable String serverPropertyName; - protected @Nullable String portPropertyName; - protected @Nullable String urlPropertyName; - protected @Nullable String databasePropertyName; + protected @Nullable String serverName; + protected @Nullable String serverPort; + protected @Nullable String database; @Override public Connection getConnection() throws SQLException { + setCredentialPropertiesFromUrl(this.jdbcUrl); return getConnection(this.user, this.password); } @@ -86,86 +90,95 @@ public Connection getConnection(final String username, final String password) th this.user = username; this.password = password; - if (StringUtils.isNullOrEmpty(this.targetDataSourceClassName) && StringUtils.isNullOrEmpty(this.jdbcUrl)) { - throw new SQLException(Messages.get("AwsWrapperDataSource.missingTarget")); - } - final Properties props = PropertyUtils.copyProperties(this.targetDataSourceProperties); - setCredentialProperties(props); + String finalUrl; - if (!StringUtils.isNullOrEmpty(this.targetDataSourceClassName)) { - final DataSource targetDataSource = createTargetDataSource(); + // Identify the URL for connection. + if (!StringUtils.isNullOrEmpty(this.jdbcUrl)) { + + finalUrl = this.jdbcUrl; + parsePropertiesFromUrl(this.jdbcUrl, props); + setDatabasePropertyFromUrl(props); + + // Override credentials with the ones provided through the data source property. + setCredentialProperties(props); - if (!StringUtils.isNullOrEmpty(this.databasePropertyName) - && !StringUtils.isNullOrEmpty(props.getProperty(this.databasePropertyName))) { - PropertyDefinition.DATABASE.set(props, props.getProperty(this.databasePropertyName)); + // Override database with the one provided through the data source property. + if (!StringUtils.isNullOrEmpty(this.database)) { + PropertyDefinition.DATABASE.set(props, this.database); } - // If the url is set explicitly through setJdbcUrl or the connection properties. - if (!StringUtils.isNullOrEmpty(this.jdbcUrl) - || (!StringUtils.isNullOrEmpty(this.urlPropertyName) - && !StringUtils.isNullOrEmpty(props.getProperty(this.urlPropertyName)))) { - final Properties parsedProperties = new Properties(); - if (!StringUtils.isNullOrEmpty(this.jdbcUrl)) { - parsePropertiesFromUrl(this.jdbcUrl, parsedProperties); - } else { - parsePropertiesFromUrl(props.getProperty(this.urlPropertyName), parsedProperties); + } else { + String serverName = !StringUtils.isNullOrEmpty(this.serverName) + ? this.serverName + : props.getProperty(SERVER_NAME); + String serverPort = !StringUtils.isNullOrEmpty(this.serverPort) + ? this.serverPort + : props.getProperty(SERVER_PORT); + String databaseName = !StringUtils.isNullOrEmpty(this.database) + ? this.database + : PropertyDefinition.DATABASE.getString(props); + + if (!StringUtils.isNullOrEmpty(serverName)) { + + if (StringUtils.isNullOrEmpty(this.jdbcProtocol)) { + throw new SQLException(Messages.get("AwsWrapperDataSource.missingJdbcProtocol")); } - parsedProperties.forEach(props::putIfAbsent); - setJdbcUrlOrUrlProperty(props); - setDatabasePropertyFromUrl(props); - if (StringUtils.isNullOrEmpty(this.user) || StringUtils.isNullOrEmpty(this.password)) { - setCredentialPropertiesFromUrl(props); + + int port = HostSpec.NO_PORT; + if (!StringUtils.isNullOrEmpty(serverPort)) { + port = Integer.parseInt(serverPort); } - } else { - this.jdbcUrl = buildUrl( + finalUrl = buildUrl( this.jdbcProtocol, - null, - this.serverPropertyName, - this.portPropertyName, - this.databasePropertyName, - props); - } + serverName, + port, + databaseName); - if (StringUtils.isNullOrEmpty(this.jdbcUrl)) { - throw new SQLException(Messages.get("AwsWrapperDataSource.missingUrl")); + // Override credentials with the ones provided through the data source property. + setCredentialProperties(props); + + // Override database with the one provided through the data source property. + if (!StringUtils.isNullOrEmpty(databaseName)) { + PropertyDefinition.DATABASE.set(props, databaseName); + } + + } else { + throw new SQLException(Messages.get("AwsWrapperDataSource.missingTarget")); } + } + + // Identify what connection provider to use. + if (!StringUtils.isNullOrEmpty(this.targetDataSourceClassName)) { + final DataSource targetDataSource = createTargetDataSource(); final TargetDriverDialectManager targetDriverDialectManager = new TargetDriverDialectManager(); final TargetDriverDialect targetDriverDialect = targetDriverDialectManager.getDialect(this.targetDataSourceClassName, props); return createConnectionWrapper( props, - this.jdbcUrl, + finalUrl, new DataSourceConnectionProvider( targetDataSource, - targetDriverDialect, - this.serverPropertyName, - this.portPropertyName, - this.urlPropertyName, - this.databasePropertyName)); - + targetDriverDialect)); } else { - final java.sql.Driver targetDriver = DriverManager.getDriver(this.jdbcUrl); + final java.sql.Driver targetDriver = DriverManager.getDriver(finalUrl); if (targetDriver == null) { - throw new SQLException(Messages.get("AwsWrapperDataSource.missingDriver", new Object[] {this.jdbcUrl})); + throw new SQLException(Messages.get("AwsWrapperDataSource.missingDriver", + new Object[] {finalUrl})); } - parsePropertiesFromUrl(this.jdbcUrl, props); - setCredentialProperties(props); - setDatabasePropertyFromUrl(props); - final TargetDriverDialectManager targetDriverDialectManager = new TargetDriverDialectManager(); final TargetDriverDialect targetDriverDialect = targetDriverDialectManager.getDialect(targetDriver, props); return createConnectionWrapper( props, - this.jdbcUrl, + finalUrl, new DriverConnectionProvider(targetDriver, targetDriverDialect)); } } @@ -185,36 +198,28 @@ public void setTargetDataSourceClassName(@Nullable final String dataSourceClassN return this.targetDataSourceClassName; } - public void setServerPropertyName(@NonNull final String serverPropertyName) { - this.serverPropertyName = serverPropertyName; + public void setServerName(@NonNull final String serverName) { + this.serverName = serverName; } - public @Nullable String getServerPropertyName() { - return this.serverPropertyName; + public @Nullable String getServerName() { + return this.serverName; } - public void setPortPropertyName(@NonNull final String portPropertyName) { - this.portPropertyName = portPropertyName; + public void setServerPort(@NonNull final String serverPort) { + this.serverPort = serverPort; } - public @Nullable String getPortPropertyName() { - return this.portPropertyName; + public @Nullable String getServerPort() { + return this.serverPort; } - public void setUrlPropertyName(@NonNull final String urlPropertyName) { - this.urlPropertyName = urlPropertyName; + public void setDatabase(@NonNull final String database) { + this.database = database; } - public @Nullable String getUrlPropertyName() { - return this.urlPropertyName; - } - - public void setDatabasePropertyName(@NonNull final String databasePropertyName) { - this.databasePropertyName = databasePropertyName; - } - - public @Nullable String getDatabasePropertyName() { - return this.databasePropertyName; + public @Nullable String getDatabase() { + return this.database; } public void setJdbcUrl(@Nullable final String url) { @@ -301,10 +306,9 @@ public Reference getReference() throws NamingException { reference.add(new StringRefAddr("jdbcUrl", getJdbcUrl())); reference.add(new StringRefAddr("targetDataSourceClassName", getTargetDataSourceClassName())); reference.add(new StringRefAddr("jdbcProtocol", getJdbcProtocol())); - reference.add(new StringRefAddr("serverPropertyName", getServerPropertyName())); - reference.add(new StringRefAddr("portPropertyName", getPortPropertyName())); - reference.add(new StringRefAddr("urlPropertyName", getUrlPropertyName())); - reference.add(new StringRefAddr("databasePropertyName", getDatabasePropertyName())); + reference.add(new StringRefAddr("serverName", getServerName())); + reference.add(new StringRefAddr("serverPort", getServerPort())); + reference.add(new StringRefAddr("database", getDatabase())); if (this.targetDataSourceProperties != null) { for (final Map.Entry entry : this.targetDataSourceProperties.entrySet()) { @@ -341,30 +345,17 @@ private void setDatabasePropertyFromUrl(final Properties props) { } } - private void setCredentialPropertiesFromUrl(final Properties props) { - final String userFromUrl = ConnectionUrlParser.parseUserFromUrl(this.jdbcUrl); - if (StringUtils.isNullOrEmpty(this.user) && !StringUtils.isNullOrEmpty(userFromUrl)) { - this.user = userFromUrl; - PropertyDefinition.USER.set(props, this.user); + private void setCredentialPropertiesFromUrl(final String jdbcUrl) { + if (StringUtils.isNullOrEmpty(jdbcUrl)) { + return; } - final String passwordFromUrl = ConnectionUrlParser.parsePasswordFromUrl(this.jdbcUrl); - if (StringUtils.isNullOrEmpty(this.password) && !StringUtils.isNullOrEmpty(passwordFromUrl)) { - this.password = passwordFromUrl; - PropertyDefinition.PASSWORD.set(props, this.password); + if (StringUtils.isNullOrEmpty(this.user)) { + this.user = ConnectionUrlParser.parseUserFromUrl(jdbcUrl); } - } - private void setJdbcUrlOrUrlProperty(final Properties props) { - // If the jdbc url wasn't set, use the url property if it exists. - if (StringUtils.isNullOrEmpty(this.jdbcUrl) - && (!StringUtils.isNullOrEmpty(this.urlPropertyName) - && !StringUtils.isNullOrEmpty(props.getProperty(this.urlPropertyName)))) { - this.jdbcUrl = props.getProperty(this.urlPropertyName); - - // If the url property wasn't set, use the provided jdbc url. - } else if (!StringUtils.isNullOrEmpty(this.urlPropertyName)) { - props.setProperty(this.urlPropertyName, this.jdbcUrl); + if (!StringUtils.isNullOrEmpty(this.password)) { + this.password = ConnectionUrlParser.parsePasswordFromUrl(jdbcUrl); } } } diff --git a/wrapper/src/main/java/software/amazon/jdbc/ds/AwsWrapperDataSourceFactory.java b/wrapper/src/main/java/software/amazon/jdbc/ds/AwsWrapperDataSourceFactory.java index bf4781c90..8bbe4ad6d 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/ds/AwsWrapperDataSourceFactory.java +++ b/wrapper/src/main/java/software/amazon/jdbc/ds/AwsWrapperDataSourceFactory.java @@ -45,10 +45,9 @@ public Object getObjectInstance( "jdbcUrl", "targetDataSourceClassName", "jdbcProtocol", - "serverPropertyName", - "portPropertyName", - "urlPropertyName", - "databasePropertyName"); + "serverName", + "serverPort", + "database"); final Reference reference = (Reference) obj; diff --git a/wrapper/src/main/java/software/amazon/jdbc/plugin/efm/HostMonitoringConnectionPlugin.java b/wrapper/src/main/java/software/amazon/jdbc/plugin/efm/HostMonitoringConnectionPlugin.java index 3ca51bb12..ae004dd95 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/plugin/efm/HostMonitoringConnectionPlugin.java +++ b/wrapper/src/main/java/software/amazon/jdbc/plugin/efm/HostMonitoringConnectionPlugin.java @@ -87,6 +87,7 @@ public class HostMonitoringConnectionPlugin extends AbstractConnectionPlugin static { PropertyDefinition.registerPluginProperties(HostMonitoringConnectionPlugin.class); + PropertyDefinition.registerPluginProperties("monitoring-"); } /** diff --git a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/GenericTargetDriverDialect.java b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/GenericTargetDriverDialect.java index 8c4c56125..5e84c2590 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/GenericTargetDriverDialect.java +++ b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/GenericTargetDriverDialect.java @@ -17,7 +17,6 @@ package software.amazon.jdbc.targetdriverdialect; import static software.amazon.jdbc.util.ConnectionUrlBuilder.buildUrl; -import static software.amazon.jdbc.util.StringUtils.isNullOrEmpty; import java.sql.Driver; import java.sql.SQLException; @@ -25,7 +24,6 @@ import java.util.logging.Logger; import javax.sql.DataSource; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import software.amazon.jdbc.HostSpec; import software.amazon.jdbc.PropertyDefinition; import software.amazon.jdbc.util.PropertyUtils; @@ -59,6 +57,7 @@ public ConnectInfo prepareConnectInfo(final @NonNull String protocol, // keep unknown properties (the ones that don't belong to AWS Wrapper Driver) // and use them to make a connection PropertyDefinition.removeAllExceptCredentials(props); + return new ConnectInfo(urlBuilder, props); } @@ -67,50 +66,23 @@ public void prepareDataSource( final @NonNull DataSource dataSource, final @NonNull String protocol, final @NonNull HostSpec hostSpec, - final @NonNull Properties props, - final @Nullable String serverPropertyName, - final @Nullable String portPropertyName, - final @Nullable String urlPropertyName, - final @Nullable String databasePropertyName) throws SQLException { + final @NonNull Properties props) throws SQLException { - final Properties customProps = new Properties(); + String finalUrl = buildUrl( + protocol, + hostSpec.getHost(), + hostSpec.getPort(), + PropertyDefinition.DATABASE.getString(props)); - if (!isNullOrEmpty(serverPropertyName)) { - customProps.setProperty(serverPropertyName, hostSpec.getHost()); - } - - if (hostSpec.isPortSpecified() && !isNullOrEmpty(portPropertyName)) { - customProps.put(portPropertyName, hostSpec.getPort()); - } + LOGGER.finest(() -> "Connecting to " + finalUrl); + props.setProperty("url", finalUrl); - if (!isNullOrEmpty(databasePropertyName) - && !isNullOrEmpty(PropertyDefinition.DATABASE.getString(props))) { - customProps.setProperty(databasePropertyName, PropertyDefinition.DATABASE.getString(props)); - } - - if (!isNullOrEmpty(urlPropertyName)) { - final Properties urlProperties = PropertyUtils.copyProperties(customProps); - - if (!isNullOrEmpty(props.getProperty(urlPropertyName))) { - // Remove the current url property to replace with a new url built from updated HostSpec and properties - urlProperties.remove(urlPropertyName); - } - - String finalUrl = buildUrl( - protocol, - hostSpec, - serverPropertyName, - portPropertyName, - databasePropertyName, - urlProperties); - LOGGER.finest(() -> "Connecting to " + finalUrl); - customProps.setProperty(urlPropertyName, finalUrl); - } + PropertyDefinition.removeAllExceptCredentials(props); - LOGGER.finest(() -> PropertyUtils.logProperties(customProps, "Connecting with properties: \n")); + LOGGER.finest(() -> PropertyUtils.logProperties(props, "Connecting with properties: \n")); - if (!customProps.isEmpty()) { - PropertyUtils.applyProperties(dataSource, customProps); + if (!props.isEmpty()) { + PropertyUtils.applyProperties(dataSource, props); } } diff --git a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MariadbDataSourceHelper.java b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MariadbDataSourceHelper.java index 3dfacfd25..c01dbaef9 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MariadbDataSourceHelper.java +++ b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MariadbDataSourceHelper.java @@ -63,13 +63,7 @@ public void prepareDataSource( // and include them to connect URL. PropertyDefinition.removeAllExcept(props, PropertyDefinition.DATABASE.name); - String finalUrl = buildUrl( - protocol, - hostSpec, - null, - null, - null, - props); + String finalUrl = buildUrl(protocol, hostSpec, props); LOGGER.finest(() -> "Connecting to " + finalUrl); mariaDbDataSource.setUrl(finalUrl); } diff --git a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MariadbTargetDriverDialect.java b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MariadbTargetDriverDialect.java index f3d280b3e..c380c99f3 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MariadbTargetDriverDialect.java +++ b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MariadbTargetDriverDialect.java @@ -21,7 +21,6 @@ import java.util.Properties; import javax.sql.DataSource; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import software.amazon.jdbc.HostSpec; import software.amazon.jdbc.PropertyDefinition; @@ -54,15 +53,15 @@ public ConnectInfo prepareConnectInfo(final @NonNull String protocol, : ""; final boolean permitMysqlSchemeFlag = props.containsKey(PERMIT_MYSQL_SCHEME); - // "permitMysqlScheme" should be in Url rather than in properties. - String urlBuilder = protocol + hostSpec.getUrl() + databaseName - + (permitMysqlSchemeFlag ? "?" + PERMIT_MYSQL_SCHEME : ""); - // keep unknown properties (the ones that don't belong to AWS Wrapper Driver) // and use them to make a connection props.remove(PERMIT_MYSQL_SCHEME); PropertyDefinition.removeAllExceptCredentials(props); + // "permitMysqlScheme" should be in Url rather than in properties. + String urlBuilder = protocol + hostSpec.getUrl() + databaseName + + (permitMysqlSchemeFlag ? "?" + PERMIT_MYSQL_SCHEME : ""); + return new ConnectInfo(urlBuilder, props); } @@ -71,11 +70,7 @@ public void prepareDataSource( final @NonNull DataSource dataSource, final @NonNull String protocol, final @NonNull HostSpec hostSpec, - final @NonNull Properties props, - final @Nullable String serverPropertyName, - final @Nullable String portPropertyName, - final @Nullable String urlPropertyName, - final @Nullable String databasePropertyName) throws SQLException { + final @NonNull Properties props) throws SQLException { // The logic is isolated to a separated class since it uses // direct reference to org.mariadb.jdbc.MariaDbDataSource diff --git a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MysqlConnectorJDataSourceHelper.java b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MysqlConnectorJDataSourceHelper.java index 069d9c677..be281830e 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MysqlConnectorJDataSourceHelper.java +++ b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MysqlConnectorJDataSourceHelper.java @@ -19,6 +19,7 @@ import com.mysql.cj.jdbc.MysqlDataSource; import java.sql.SQLException; import java.util.Properties; +import java.util.logging.Logger; import javax.sql.DataSource; import org.checkerframework.checker.nullness.qual.NonNull; import software.amazon.jdbc.HostSpec; @@ -28,6 +29,9 @@ public class MysqlConnectorJDataSourceHelper { + private static final Logger LOGGER = + Logger.getLogger(MysqlConnectorJDataSourceHelper.class.getName()); + public void prepareDataSource( final @NonNull DataSource dataSource, final @NonNull HostSpec hostSpec, @@ -53,6 +57,7 @@ public void prepareDataSource( // keep unknown properties (the ones that don't belong to AWS Wrapper Driver) // and try to apply them to data source PropertyDefinition.removeAll(props); + PropertyUtils.applyProperties(dataSource, props); } } diff --git a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MysqlConnectorJTargetDriverDialect.java b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MysqlConnectorJTargetDriverDialect.java index c1d4ad7e4..7dd971a92 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MysqlConnectorJTargetDriverDialect.java +++ b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/MysqlConnectorJTargetDriverDialect.java @@ -21,7 +21,6 @@ import java.util.Properties; import javax.sql.DataSource; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import software.amazon.jdbc.HostSpec; public class MysqlConnectorJTargetDriverDialect extends GenericTargetDriverDialect { @@ -46,11 +45,7 @@ public void prepareDataSource( final @NonNull DataSource dataSource, final @NonNull String protocol, final @NonNull HostSpec hostSpec, - final @NonNull Properties props, - final @Nullable String serverPropertyName, - final @Nullable String portPropertyName, - final @Nullable String urlPropertyName, - final @Nullable String databasePropertyName) throws SQLException { + final @NonNull Properties props) throws SQLException { // The logic is isolated to a separated class since it uses // direct reference to com.mysql.cj.jdbc.MysqlDataSource diff --git a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/PgDataSourceHelper.java b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/PgDataSourceHelper.java index c413e81f7..94a262d38 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/PgDataSourceHelper.java +++ b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/PgDataSourceHelper.java @@ -18,6 +18,7 @@ import java.sql.SQLException; import java.util.Properties; +import java.util.logging.Logger; import javax.sql.DataSource; import org.checkerframework.checker.nullness.qual.NonNull; import org.postgresql.ds.common.BaseDataSource; @@ -28,6 +29,9 @@ public class PgDataSourceHelper { + private static final Logger LOGGER = + Logger.getLogger(PgDataSourceHelper.class.getName()); + private static final String BASE_DS_CLASS_NAME = org.postgresql.ds.common.BaseDataSource.class.getName(); @@ -56,6 +60,7 @@ public void prepareDataSource( // keep unknown properties (the ones that don't belong to AWS Wrapper Driver) // and try to apply them to data source PropertyDefinition.removeAll(props); + PropertyUtils.applyProperties(dataSource, props); } } diff --git a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/PgTargetDriverDialect.java b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/PgTargetDriverDialect.java index cfee8a8b2..2862aa80a 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/PgTargetDriverDialect.java +++ b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/PgTargetDriverDialect.java @@ -24,7 +24,6 @@ import java.util.Set; import javax.sql.DataSource; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import software.amazon.jdbc.HostSpec; public class PgTargetDriverDialect extends GenericTargetDriverDialect { @@ -54,11 +53,7 @@ public void prepareDataSource( final @NonNull DataSource dataSource, final @NonNull String protocol, final @NonNull HostSpec hostSpec, - final @NonNull Properties props, - final @Nullable String serverPropertyName, - final @Nullable String portPropertyName, - final @Nullable String urlPropertyName, - final @Nullable String databasePropertyName) throws SQLException { + final @NonNull Properties props) throws SQLException { // The logic is isolated to a separated class since it uses // direct reference to org.postgresql.ds.common.BaseDataSource diff --git a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/TargetDriverDialect.java b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/TargetDriverDialect.java index 7d4beb8ae..06381992f 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/TargetDriverDialect.java +++ b/wrapper/src/main/java/software/amazon/jdbc/targetdriverdialect/TargetDriverDialect.java @@ -20,7 +20,6 @@ import java.util.Properties; import javax.sql.DataSource; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import software.amazon.jdbc.HostSpec; public interface TargetDriverDialect { @@ -37,9 +36,5 @@ void prepareDataSource( final @NonNull DataSource dataSource, final @NonNull String protocol, final @NonNull HostSpec hostSpec, - final @NonNull Properties props, - final @Nullable String serverPropertyName, - final @Nullable String portPropertyName, - final @Nullable String urlPropertyName, - final @Nullable String databasePropertyName) throws SQLException; + final @NonNull Properties props) throws SQLException; } diff --git a/wrapper/src/main/java/software/amazon/jdbc/util/ConnectionUrlBuilder.java b/wrapper/src/main/java/software/amazon/jdbc/util/ConnectionUrlBuilder.java index 89e013755..083379c42 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/util/ConnectionUrlBuilder.java +++ b/wrapper/src/main/java/software/amazon/jdbc/util/ConnectionUrlBuilder.java @@ -22,20 +22,52 @@ import java.sql.SQLException; import java.util.Enumeration; import java.util.Properties; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import software.amazon.jdbc.HostSpec; import software.amazon.jdbc.PropertyDefinition; public class ConnectionUrlBuilder { + // Builds a connection URL of the generic format: "protocol//[hosts][:port]/[database]" + public static String buildUrl( + final @NonNull String jdbcProtocol, + final @NonNull String serverName, + final int port, + final @Nullable String databaseName) throws SQLException { + + if (StringUtils.isNullOrEmpty(jdbcProtocol) || StringUtils.isNullOrEmpty(serverName)) { + throw new SQLException(Messages.get("ConnectionUrlBuilder.missingJdbcProtocol")); + } + + final StringBuilder urlBuilder = new StringBuilder(); + urlBuilder.append(jdbcProtocol); + + if (!jdbcProtocol.endsWith("//")) { + urlBuilder.append("//"); + } + + urlBuilder.append(serverName); + + if (port > 0) { + urlBuilder.append(":").append(port); + } + + urlBuilder.append("/"); + + if (!StringUtils.isNullOrEmpty(databaseName)) { + urlBuilder.append(databaseName); + } + + return urlBuilder.toString(); + } + // Builds a connection URL of the generic format: "protocol//[hosts][/database][?properties]" public static String buildUrl(final String jdbcProtocol, final HostSpec hostSpec, - final String serverPropertyName, - final String portPropertyName, - final String databasePropertyName, final Properties props) throws SQLException { - if (StringUtils.isNullOrEmpty(jdbcProtocol)) { + if (StringUtils.isNullOrEmpty(jdbcProtocol) || hostSpec == null) { throw new SQLException(Messages.get("ConnectionUrlBuilder.missingJdbcProtocol")); } @@ -43,52 +75,25 @@ public static String buildUrl(final String jdbcProtocol, final StringBuilder urlBuilder = new StringBuilder(); urlBuilder.append(jdbcProtocol); - if (!jdbcProtocol.contains("//")) { + if (!jdbcProtocol.endsWith("//")) { urlBuilder.append("//"); } - if (hostSpec != null) { - urlBuilder.append(hostSpec.getUrl()); - } else { - if (StringUtils.isNullOrEmpty(serverPropertyName) - || StringUtils.isNullOrEmpty(props.getProperty(serverPropertyName))) { - throw new SQLException(Messages.get("ConnectionUrlBuilder.missingJdbcProtocol")); - } - - urlBuilder.append(copy.get(serverPropertyName)); - - if (!StringUtils.isNullOrEmpty(portPropertyName) && !StringUtils.isNullOrEmpty( - copy.getProperty(portPropertyName))) { - urlBuilder.append(":").append(copy.get(portPropertyName)); - } - - urlBuilder.append("/"); - } + urlBuilder.append(hostSpec.getUrl()); if (!StringUtils.isNullOrEmpty(PropertyDefinition.DATABASE.getString(copy))) { urlBuilder.append(PropertyDefinition.DATABASE.getString(copy)); copy.remove(PropertyDefinition.DATABASE.name); } - if (!StringUtils.isNullOrEmpty(serverPropertyName)) { - removeProperty(serverPropertyName, copy); - } - if (!StringUtils.isNullOrEmpty(portPropertyName)) { - removeProperty(portPropertyName, copy); - } - if (!StringUtils.isNullOrEmpty(databasePropertyName)) { - removeProperty(databasePropertyName, copy); - } - final StringBuilder queryBuilder = new StringBuilder(); final Enumeration propertyNames = copy.propertyNames(); while (propertyNames.hasMoreElements()) { final String propertyName = propertyNames.nextElement().toString(); - if (queryBuilder.length() != 0) { - queryBuilder.append("&"); - } - - if (!StringUtils.isNullOrEmpty(propertyName)) { + if (propertyName != null && !propertyName.trim().equals("")) { + if (queryBuilder.length() != 0) { + queryBuilder.append("&"); + } final String propertyValue = copy.getProperty(propertyName); try { queryBuilder @@ -109,11 +114,4 @@ public static String buildUrl(final String jdbcProtocol, return urlBuilder.toString(); } - - private static void removeProperty(final String propertyKey, final Properties props) { - if (!StringUtils.isNullOrEmpty(propertyKey) - && !StringUtils.isNullOrEmpty(props.getProperty(propertyKey))) { - props.remove(propertyKey); - } - } } diff --git a/wrapper/src/main/resources/messages.properties b/wrapper/src/main/resources/messages.properties index 4a002248f..768b98d6c 100644 --- a/wrapper/src/main/resources/messages.properties +++ b/wrapper/src/main/resources/messages.properties @@ -47,8 +47,8 @@ AwsSecretsManagerConnectionPlugin.failedLogin=Login failed. SQLState=''{0}'' AwsSecretsManagerConnectionPlugin.unhandledException=Unhandled exception: ''{0}'' # AWS Wrapper Data Source -AwsWrapperDataSource.missingTarget=Target data source class name or JDBC url is required. -AwsWrapperDataSource.missingUrl=No JDBC URL was provided, or a JDBC URL couldn't be built from the provided information. +AwsWrapperDataSource.missingJdbcProtocol=Missing JDBC protocol. Could not construct URL. +AwsWrapperDataSource.missingTarget=JDBC url or Server name is required. AwsWrapperDataSource.missingDriver=Can't find a suitable driver for ''{0}'' # Cluster Aware Reader Failover Handler diff --git a/wrapper/src/test/java/integration/refactored/container/ConnectionStringHelper.java b/wrapper/src/test/java/integration/refactored/container/ConnectionStringHelper.java index 4dcf52886..c7e5fb668 100644 --- a/wrapper/src/test/java/integration/refactored/container/ConnectionStringHelper.java +++ b/wrapper/src/test/java/integration/refactored/container/ConnectionStringHelper.java @@ -26,10 +26,6 @@ public class ConnectionStringHelper { public static String getUrl() { - return getUrl(null); - } - - public static String getUrl(final String wrapperPlugins) { return getUrl( TestEnvironment.getCurrent().getCurrentDriver(), TestEnvironment.getCurrent() @@ -44,20 +40,18 @@ public static String getUrl(final String wrapperPlugins) { .getInstances() .get(0) .getPort(), - TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getDefaultDbName(), - wrapperPlugins); + TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getDefaultDbName()); } - public static String getUrl(String host, int port, String databaseName, String wrapperPlugins) { - return getUrl(TestEnvironment.getCurrent().getCurrentDriver(), host, port, databaseName, wrapperPlugins); + public static String getUrl(String host, int port, String databaseName) { + return getUrl(TestEnvironment.getCurrent().getCurrentDriver(), host, port, databaseName); } public static String getUrl( TestDriver testDriver, String host, int port, - String databaseName, - String wrapperPlugins) { + String databaseName) { final DatabaseEngine databaseEngine = TestEnvironment.getCurrent().getInfo().getRequest().getDatabaseEngine(); final String requiredParameters = DriverHelper.getDriverRequiredParameters(databaseEngine, testDriver); final String url = DriverHelper.getDriverProtocol(databaseEngine, testDriver) @@ -66,10 +60,29 @@ public static String getUrl( + port + "/" + databaseName - + requiredParameters - + (requiredParameters.startsWith("?") ? "&" : "?") - + "wrapperPlugins="; - return wrapperPlugins != null ? url + wrapperPlugins : url; + + requiredParameters; + return url; + } + + public static String getUrlWithPlugins(String host, int port, String databaseName, String wrapperPlugins) { + final String url = getUrl(TestEnvironment.getCurrent().getCurrentDriver(), host, port, databaseName); + return url + + (url.contains("?") ? "&" : "?") + + "wrapperPlugins=" + + wrapperPlugins; + } + + public static String getUrlWithPlugins( + TestDriver testDriver, + String host, + int port, + String databaseName, + String wrapperPlugins) { + final String url = getUrl(testDriver, host, port, databaseName); + return url + + (url.contains("?") ? "&" : "?") + + "wrapperPlugins=" + + wrapperPlugins; } /** diff --git a/wrapper/src/test/java/integration/refactored/container/ProxyHelper.java b/wrapper/src/test/java/integration/refactored/container/ProxyHelper.java index 321dcc652..aa030e4c3 100644 --- a/wrapper/src/test/java/integration/refactored/container/ProxyHelper.java +++ b/wrapper/src/test/java/integration/refactored/container/ProxyHelper.java @@ -17,11 +17,12 @@ package integration.refactored.container; import eu.rekawek.toxiproxy.Proxy; +import eu.rekawek.toxiproxy.model.Toxic; import eu.rekawek.toxiproxy.model.ToxicDirection; -import integration.refactored.TestInstanceInfo; import java.io.IOException; import java.util.List; import java.util.logging.Logger; +import java.util.stream.Collectors; public class ProxyHelper { @@ -84,13 +85,15 @@ public static void enableConnectivity(String instanceName) { /** Allow traffic to and from server. */ private static void enableConnectivity(Proxy proxy) { try { - proxy.toxics().get("DOWN-STREAM").remove(); - } catch (IOException ex) { - // ignore - } - - try { - proxy.toxics().get("UP-STREAM").remove(); + proxy.toxics().getAll().stream() + .filter(t -> "DOWN-STREAM".equals(t.getName()) || "UP-STREAM".equals(t.getName())) + .forEach(toxic1 -> { + try { + toxic1.remove(); + } catch (IOException e) { + // ignore + } + }); } catch (IOException ex) { // ignore } diff --git a/wrapper/src/test/java/integration/refactored/container/TestDriverProvider.java b/wrapper/src/test/java/integration/refactored/container/TestDriverProvider.java index 0bc81bd11..4a97b244a 100644 --- a/wrapper/src/test/java/integration/refactored/container/TestDriverProvider.java +++ b/wrapper/src/test/java/integration/refactored/container/TestDriverProvider.java @@ -34,7 +34,6 @@ import integration.refactored.container.condition.EnableBasedOnTestDriverExtension; import integration.refactored.container.condition.MakeSureFirstInstanceWriter; import integration.util.AuroraTestUtility; -import java.net.InetAddress; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; @@ -48,6 +47,8 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestTemplateInvocationContext; import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; +import software.amazon.jdbc.dialect.DialectManager; +import software.amazon.jdbc.targetdriverdialect.TargetDriverDialectManager; public class TestDriverProvider implements TestTemplateInvocationContextProvider { private static final Logger LOGGER = Logger.getLogger(TestDriverProvider.class.getName()); @@ -122,8 +123,8 @@ public void beforeEach(ExtensionContext context) throws Exception { // Need to ensure that cluster details through API matches topology fetched through SQL // Wait up to 5min long startTimeNano = System.nanoTime(); - while ((instanceIDs.size() - != testRequest.getNumOfInstances() + while ((instanceIDs.size() != testRequest.getNumOfInstances() + || instanceIDs.size() == 0 || !auroraUtil.isDBInstanceWriter(instanceIDs.get(0))) && TimeUnit.NANOSECONDS.toMinutes(System.nanoTime() - startTimeNano) < 5) { @@ -170,6 +171,8 @@ public void beforeEach(ExtensionContext context) throws Exception { auroraUtil.makeSureInstancesUp(instanceIDs); TestAuroraHostListProvider.clearCache(); TestPluginServiceImpl.clearHostAvailabilityCache(); + DialectManager.resetEndpointCache(); + TargetDriverDialectManager.resetCustomDialect(); } } }); diff --git a/wrapper/src/test/java/integration/refactored/container/tests/AdvancedPerformanceTest.java b/wrapper/src/test/java/integration/refactored/container/tests/AdvancedPerformanceTest.java index 12999354e..28fcbb2a6 100644 --- a/wrapper/src/test/java/integration/refactored/container/tests/AdvancedPerformanceTest.java +++ b/wrapper/src/test/java/integration/refactored/container/tests/AdvancedPerformanceTest.java @@ -310,7 +310,7 @@ private Thread getThread_DirectDriver( final Properties props = ConnectionStringHelper.getDefaultProperties(); final Connection conn = openConnectionWithRetry( - ConnectionStringHelper.getUrl( + ConnectionStringHelper.getUrlWithPlugins( TestEnvironment.getCurrent() .getInfo() .getDatabaseInfo() diff --git a/wrapper/src/test/java/integration/refactored/container/tests/AuroraFailoverTest.java b/wrapper/src/test/java/integration/refactored/container/tests/AuroraFailoverTest.java index 7c77b63ba..d056f9495 100644 --- a/wrapper/src/test/java/integration/refactored/container/tests/AuroraFailoverTest.java +++ b/wrapper/src/test/java/integration/refactored/container/tests/AuroraFailoverTest.java @@ -49,7 +49,6 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestTemplate; @@ -374,7 +373,6 @@ public void testServerFailoverWithIdleConnections() throws SQLException, Interru } @TestTemplate - @Disabled public void test_DataSourceWriterConnection_BasicFailover() throws SQLException, InterruptedException { @@ -489,20 +487,14 @@ protected Connection createDataSourceConnectionWithFailoverUsingInstanceId( // Configure the property names for the underlying driver-specific data source: ds.setJdbcProtocol(DriverHelper.getDriverProtocol()); - ds.setDatabasePropertyName("databaseName"); - ds.setServerPropertyName("serverName"); - ds.setPortPropertyName("port"); - ds.setUrlPropertyName("url"); + ds.setServerName(instanceEndpoint); + ds.setDatabase(TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getDefaultDbName()); // Specify the driver-specific data source: ds.setTargetDataSourceClassName(DriverHelper.getDataSourceClassname()); // Configure the driver-specific data source: Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty("serverName", instanceEndpoint); - targetDataSourceProps.setProperty( - "databaseName", - TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getDefaultDbName()); targetDataSourceProps.setProperty("wrapperPlugins", "failover"); if (TestEnvironment.getCurrent().getCurrentDriver() == TestDriver.MARIADB diff --git a/wrapper/src/test/java/integration/refactored/container/tests/AwsIamIntegrationTest.java b/wrapper/src/test/java/integration/refactored/container/tests/AwsIamIntegrationTest.java index cc6541625..5916b9479 100644 --- a/wrapper/src/test/java/integration/refactored/container/tests/AwsIamIntegrationTest.java +++ b/wrapper/src/test/java/integration/refactored/container/tests/AwsIamIntegrationTest.java @@ -223,19 +223,12 @@ void test_AwsIam_UserInConnStr() throws SQLException { void test_AwsIam_UserAndPasswordPropertiesArePreserved() throws SQLException { final AwsWrapperDataSource ds = new AwsWrapperDataSource(); ds.setJdbcProtocol(DriverHelper.getDriverProtocol()); - ds.setServerPropertyName("serverName"); - ds.setDatabasePropertyName("databaseName"); - + ds.setServerName(TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getClusterEndpoint()); + ds.setDatabase(TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getDefaultDbName()); ds.setTargetDataSourceClassName(DriverHelper.getDataSourceClassname()); final Properties props = initAwsIamProps(TestEnvironment.getCurrent().getInfo().getIamUsername(), ""); - props.setProperty( - "serverName", - TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getClusterEndpoint()); - props.setProperty( - "databaseName", - TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getDefaultDbName()); ds.setTargetDataSourceProperties(props); try (final Connection conn = ds.getConnection()) { diff --git a/wrapper/src/test/java/integration/refactored/container/tests/BasicConnectivityTests.java b/wrapper/src/test/java/integration/refactored/container/tests/BasicConnectivityTests.java index 9b2227f1c..f6929177f 100644 --- a/wrapper/src/test/java/integration/refactored/container/tests/BasicConnectivityTests.java +++ b/wrapper/src/test/java/integration/refactored/container/tests/BasicConnectivityTests.java @@ -73,7 +73,7 @@ public void test_DirectConnection(TestDriver testDriver) throws SQLException { DriverHelper.setSocketTimeout(testDriver, props, 10, TimeUnit.SECONDS); String url = - ConnectionStringHelper.getUrl( + ConnectionStringHelper.getUrlWithPlugins( testDriver, TestEnvironment.getCurrent() .getInfo() @@ -169,7 +169,7 @@ public void test_ProxiedDirectConnection(TestDriver testDriver) throws SQLExcept TestEnvironment.getCurrent().getInfo().getProxyDatabaseInfo().getInstances().get(0); String url = - ConnectionStringHelper.getUrl( + ConnectionStringHelper.getUrlWithPlugins( testDriver, instanceInfo.getHost(), instanceInfo.getPort(), diff --git a/wrapper/src/test/java/integration/refactored/container/tests/DataSourceTests.java b/wrapper/src/test/java/integration/refactored/container/tests/DataSourceTests.java index a1239ec9b..4c580cc5e 100644 --- a/wrapper/src/test/java/integration/refactored/container/tests/DataSourceTests.java +++ b/wrapper/src/test/java/integration/refactored/container/tests/DataSourceTests.java @@ -63,23 +63,16 @@ public void testConnectionWithDataSourceClassNameAndServerNameFromJndiLookup() throws SQLException, NamingException, IllegalAccessException { final AwsWrapperDataSource ds = new AwsWrapperDataSource(); ds.setJdbcProtocol(DriverHelper.getDriverProtocol()); - ds.setServerPropertyName("serverName"); - ds.setDatabasePropertyName("databaseName"); - + ds.setServerName(TestEnvironment.getCurrent() + .getInfo() + .getDatabaseInfo() + .getInstances() + .get(0) + .getHost()); + ds.setDatabase(TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getDefaultDbName()); ds.setTargetDataSourceClassName(DriverHelper.getDataSourceClassname()); final Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty( - "serverName", - TestEnvironment.getCurrent() - .getInfo() - .getDatabaseInfo() - .getInstances() - .get(0) - .getHost()); - targetDataSourceProps.setProperty( - "databaseName", - TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getDefaultDbName()); targetDataSourceProps.setProperty(PropertyDefinition.PLUGINS.name, ""); ds.setTargetDataSourceProperties(targetDataSourceProps); @@ -120,10 +113,9 @@ public void testConnectionWithDataSourceClassNameAndUrlFromJndiLookup() ds.setTargetDataSourceClassName(DriverHelper.getDataSourceClassname()); ds.setJdbcProtocol(DriverHelper.getDriverProtocol()); - ds.setUrlPropertyName("url"); + ds.setJdbcUrl(ConnectionStringHelper.getUrl()); final Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty("url", ConnectionStringHelper.getUrl()); ds.setTargetDataSourceProperties(targetDataSourceProps); final Hashtable env = new Hashtable<>(); diff --git a/wrapper/src/test/java/integration/refactored/container/tests/HikariTests.java b/wrapper/src/test/java/integration/refactored/container/tests/HikariTests.java index 0e6cae8f5..4d8e1b109 100644 --- a/wrapper/src/test/java/integration/refactored/container/tests/HikariTests.java +++ b/wrapper/src/test/java/integration/refactored/container/tests/HikariTests.java @@ -79,7 +79,7 @@ public class HikariTests { public void testOpenConnectionWithUrl() throws SQLException { final HikariDataSource dataSource = new HikariDataSource(); final String url = ConnectionStringHelper.getWrapperUrl(); - dataSource.setJdbcUrl(url + (url.contains("?") ? "&" : "?") + "wrapperPlugins=\"\""); + dataSource.setJdbcUrl(url); dataSource.setUsername(TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getUsername()); dataSource.setPassword(TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getPassword()); dataSource.addDataSourceProperty(PropertyDefinition.PLUGINS.name, ""); @@ -104,36 +104,37 @@ public void testOpenConnectionWithDataSourceClassName() throws SQLException { dataSource.setDataSourceClassName(AwsWrapperDataSource.class.getName()); // Configure the connection pool: - dataSource.setJdbcUrl(ConnectionStringHelper.getWrapperUrl()); dataSource.setUsername(TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getUsername()); dataSource.setPassword(TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getPassword()); // Configure AwsWrapperDataSource: dataSource.addDataSourceProperty("jdbcProtocol", DriverHelper.getDriverProtocol()); - dataSource.addDataSourceProperty("databasePropertyName", "databaseName"); - dataSource.addDataSourceProperty("portPropertyName", "port"); - dataSource.addDataSourceProperty("serverPropertyName", "serverName"); - - // Specify the driver-specific DataSource for AwsWrapperDataSource: - dataSource.addDataSourceProperty("targetDataSourceClassName", - DriverHelper.getDataSourceClassname()); - - // Configuring driver-specific DataSource: - final Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty( - "serverName", + dataSource.addDataSourceProperty("serverName", TestEnvironment.getCurrent() .getInfo() .getDatabaseInfo() .getInstances() .get(0) .getHost()); - targetDataSourceProps.setProperty( - "databaseName", + dataSource.addDataSourceProperty(PropertyDefinition.DATABASE.name, TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getDefaultDbName()); + + // Specify the driver-specific DataSource for AwsWrapperDataSource: + dataSource.addDataSourceProperty("targetDataSourceClassName", + DriverHelper.getDataSourceClassname()); + + // Configuring driver-specific DataSource: + final Properties targetDataSourceProps = new Properties(); targetDataSourceProps.setProperty(PropertyDefinition.PLUGINS.name, ""); - // For MariaDB tests, MariaDbDataSource only accepts the url parameter. - targetDataSourceProps.setProperty("url", ConnectionStringHelper.getUrl()); + + if (TestEnvironment.getCurrent().getCurrentDriver() == TestDriver.MARIADB + && TestEnvironment.getCurrent().getInfo().getRequest().getDatabaseEngine() + == DatabaseEngine.MYSQL) { + // Connecting to Mysql database with MariaDb driver requires a configuration parameter + // "permitMysqlScheme" + targetDataSourceProps.setProperty("permitMysqlScheme", "1"); + } + dataSource.addDataSourceProperty("targetDataSourceProperties", targetDataSourceProps); final Connection conn = dataSource.getConnection(); @@ -225,6 +226,7 @@ public void testEFMFailover() throws SQLException { } ProxyHelper.enableAllConnectivity(); + dataSource.close(); } private HikariDataSource createDataSource(final Properties customProps) { @@ -245,7 +247,15 @@ private HikariConfig getConfig(final Properties customProps) { TestEnvironment.getCurrent().getInfo().getProxyDatabaseInfo(); config.setUsername(proxyDatabaseInfo.getUsername()); config.setPassword(proxyDatabaseInfo.getPassword()); - config.setMaximumPoolSize(3); + + /* + It should be 1 max connection. Otherwise, HikariCP will start adding more connections in + background. Taking into account that tests intensively enable/disable connectivity to + configured host (provider with "serverName" property), these attempts may fail. + That makes test logs less readable but causes no functional failures to the test itself. + */ + config.setMaximumPoolSize(1); + config.setExceptionOverrideClassName(HikariCPSQLException.class.getName()); config.setInitializationFailTimeout(75000); config.setConnectionTimeout(1000); @@ -254,28 +264,21 @@ private HikariConfig getConfig(final Properties customProps) { config.addDataSourceProperty("targetDataSourceClassName", DriverHelper.getDataSourceClassname()); config.addDataSourceProperty("jdbcProtocol", DriverHelper.getDriverProtocol()); - config.addDataSourceProperty("portPropertyName", "portNumber"); - config.addDataSourceProperty("serverPropertyName", "serverName"); - config.addDataSourceProperty("databasePropertyName", "databaseName"); - config.addDataSourceProperty("urlPropertyName", "url"); - - final Properties targetDataSourceProps = new Properties(); - - targetDataSourceProps.setProperty( - "serverName", + config.addDataSourceProperty("serverName", TestEnvironment.getCurrent() .getInfo() .getProxyDatabaseInfo() .getInstances() .get(0) .getHost()); - targetDataSourceProps.setProperty( - "databaseName", + config.addDataSourceProperty("database", TestEnvironment.getCurrent().getInfo().getProxyDatabaseInfo().getDefaultDbName()); - - targetDataSourceProps.setProperty("portNumber", + config.addDataSourceProperty("serverPort", Integer.toString(TestEnvironment.getCurrent().getInfo().getProxyDatabaseInfo() .getClusterEndpointPort())); + + final Properties targetDataSourceProps = new Properties(); + targetDataSourceProps.setProperty(PropertyDefinition.PLUGINS.name, "failover,efm"); targetDataSourceProps.setProperty( "clusterInstanceHostPattern", @@ -293,6 +296,7 @@ private HikariConfig getConfig(final Properties customProps) { HostMonitoringConnectionPlugin.FAILURE_DETECTION_INTERVAL.name, "1000"); targetDataSourceProps.setProperty( HostMonitoringConnectionPlugin.FAILURE_DETECTION_COUNT.name, "1"); + if (TestEnvironment.getCurrent().getCurrentDriver() == TestDriver.MARIADB && TestEnvironment.getCurrent().getInfo().getRequest().getDatabaseEngine() == DatabaseEngine.MYSQL) { // Connecting to Mysql database with MariaDb driver requires a configuration parameter diff --git a/wrapper/src/test/java/integration/util/AuroraTestUtility.java b/wrapper/src/test/java/integration/util/AuroraTestUtility.java index 1f1bbd196..8f3a52b38 100644 --- a/wrapper/src/test/java/integration/util/AuroraTestUtility.java +++ b/wrapper/src/test/java/integration/util/AuroraTestUtility.java @@ -639,7 +639,7 @@ protected void makeSureInstancesUp(List instances, boolean finalCheck) TestEnvironment.getCurrent().getInfo().getDatabaseInfo().getInstance(id); try (final Connection conn = DriverManager.getConnection( - ConnectionStringHelper.getUrl( + ConnectionStringHelper.getUrlWithPlugins( instanceInfo.getHost(), instanceInfo.getPort(), TestEnvironment.getCurrent() diff --git a/wrapper/src/test/java/software/amazon/jdbc/ds/AwsWrapperDataSourceTest.java b/wrapper/src/test/java/software/amazon/jdbc/ds/AwsWrapperDataSourceTest.java index 15372a538..65c9ec8b5 100644 --- a/wrapper/src/test/java/software/amazon/jdbc/ds/AwsWrapperDataSourceTest.java +++ b/wrapper/src/test/java/software/amazon/jdbc/ds/AwsWrapperDataSourceTest.java @@ -63,23 +63,17 @@ void tearDown() throws Exception { @Test public void testGetConnectionWithNewCredentialsWithDataSource() throws SQLException { - final String expectedUrl1 = "protocol//testserver/?user=user1&password=pass1"; + final String expectedUrl1 = "protocol//testserver/"; final Properties expectedProperties1 = new Properties(); expectedProperties1.setProperty("user", "user1"); expectedProperties1.setProperty("password", "pass1"); - expectedProperties1.setProperty("serverName", "testserver"); final Properties expectedProperties2 = new Properties(); expectedProperties2.setProperty("user", "user2"); expectedProperties2.setProperty("password", "pass2"); - expectedProperties2.setProperty("serverName", "testserver"); ds.setJdbcProtocol("protocol"); - ds.setServerPropertyName("serverName"); - - Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty("serverName", "testserver"); - ds.setTargetDataSourceProperties(targetDataSourceProps); + ds.setServerName("testserver"); ds.getConnection("user1", "pass1"); ds.getConnection("user2", "pass2"); @@ -89,7 +83,7 @@ public void testGetConnectionWithNewCredentialsWithDataSource() throws SQLExcept assertEquals(2, urls.size()); assertEquals(2, properties.size()); assertEquals(expectedUrl1, urls.get(0)); - assertEquals(expectedUrl1, urls.get(1)); // JDBC Url doesn't get updated when we are reusing the connection. + assertEquals(expectedUrl1, urls.get(1)); // JDBC Url doesn't get updated when we are reusing the data source. assertEquals(expectedProperties1, properties.get(0)); assertEquals(expectedProperties2, properties.get(1)); } @@ -123,11 +117,7 @@ public void testGetConnectionWithNewCredentialsWithDriverManager() throws SQLExc @Test public void testConnectionWithDataSourceClassNameAndUrl() throws SQLException { final String expectedUrl = "jdbc:postgresql://testserver/db"; - ds.setUrlPropertyName("url"); - - final Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty("url", "jdbc:postgresql://testserver/db"); - ds.setTargetDataSourceProperties(targetDataSourceProps); + ds.setJdbcUrl(expectedUrl); try (final Connection conn = ds.getConnection("user", "pass")) { final List urls = urlArgumentCaptor.getAllValues(); @@ -156,20 +146,11 @@ public void testConnectionWithUrl() throws SQLException { @Test public void testConnectionWithDataSourceClassNameAndServerName() throws SQLException { - final String expectedUrl = "protocol//testServer/db?user=user&password=pass"; + final String expectedUrl = "protocol//testServer/db"; ds.setJdbcProtocol("protocol"); - ds.setServerPropertyName("serverName"); - ds.setDatabasePropertyName("databaseName"); - - final Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty( - "serverName", - "testServer"); - targetDataSourceProps.setProperty( - "databaseName", - "db"); - ds.setTargetDataSourceProperties(targetDataSourceProps); + ds.setServerName("testServer"); + ds.setDatabase("db"); try (final Connection conn = ds.getConnection("user", "pass")) { final List urls = urlArgumentCaptor.getAllValues(); @@ -184,14 +165,12 @@ public void testConnectionWithDataSourceClassNameAndServerName() throws SQLExcep @Test @DisableOnTestDriver(TestDriver.MARIADB) public void testConnectionWithDataSourceClassNameAndCredentialProperties() throws SQLException { - final String expectedUrl = "protocol//testServer/db?user=user&password=pass"; + final String expectedUrl = "protocol//testServer/db"; ds.setJdbcProtocol("protocol"); - ds.setServerPropertyName("serverName"); - ds.setDatabasePropertyName("databaseName"); final Properties targetDataSourceProps = new Properties(); targetDataSourceProps.setProperty("serverName", "testServer"); - targetDataSourceProps.setProperty("databaseName", "db"); + targetDataSourceProps.setProperty("database", "db"); targetDataSourceProps.setProperty("user", "user"); targetDataSourceProps.setProperty("password", "pass"); ds.setTargetDataSourceProperties(targetDataSourceProps); @@ -209,12 +188,10 @@ public void testConnectionWithDataSourceClassNameAndCredentialProperties() throw @Test public void testConnectionWithDataSourceClassNameMissingProtocol() { ds = new AwsWrapperDataSource(); - ds.setServerPropertyName("serverName"); - ds.setDatabasePropertyName("databaseName"); final Properties targetDataSourceProps = new Properties(); targetDataSourceProps.setProperty("serverName", "testServer"); - targetDataSourceProps.setProperty("databaseName", "db"); + targetDataSourceProps.setProperty("database", "db"); ds.setTargetDataSourceProperties(targetDataSourceProps); assertThrows(SQLException.class, () -> ds.getConnection("user", "pass")); @@ -224,11 +201,7 @@ public void testConnectionWithDataSourceClassNameMissingProtocol() { public void testConnectionWithDataSourceClassNameMissingServer() { ds = new AwsWrapperDataSource(); ds.setJdbcProtocol("protocol"); - ds.setDatabasePropertyName("databaseName"); - - final Properties targetDataSourceProps = new Properties(); - targetDataSourceProps.setProperty("databaseName", "db"); - ds.setTargetDataSourceProperties(targetDataSourceProps); + ds.setDatabase("db"); assertThrows(SQLException.class, () -> ds.getConnection("user", "pass")); } @@ -237,7 +210,6 @@ public void testConnectionWithDataSourceClassNameMissingServer() { public void testConnectionWithDataSourceClassNameMissingDatabase() { ds = new AwsWrapperDataSource(); ds.setJdbcProtocol("protocol"); - ds.setServerPropertyName("serverName"); final Properties targetDataSourceProps = new Properties(); targetDataSourceProps.setProperty("serverName", "testServer"); @@ -249,7 +221,6 @@ public void testConnectionWithDataSourceClassNameMissingDatabase() { @Test public void testConnectionWithUrlMissingPassword() { ds = new AwsWrapperDataSource(); - ds.setUrlPropertyName("url"); ds.setJdbcUrl("protocol://testserver/"); assertThrows(SQLException.class, () -> ds.getConnection("user", "")); diff --git a/wrapper/src/test/java/software/amazon/jdbc/util/ConnectionUrlBuilderTest.java b/wrapper/src/test/java/software/amazon/jdbc/util/ConnectionUrlBuilderTest.java index 04761983f..e687e9e46 100644 --- a/wrapper/src/test/java/software/amazon/jdbc/util/ConnectionUrlBuilderTest.java +++ b/wrapper/src/test/java/software/amazon/jdbc/util/ConnectionUrlBuilderTest.java @@ -39,7 +39,8 @@ void test_buildUrl( final String db, final String expected, final Properties props) throws SQLException { - Properties properties = new Properties(props); + Properties properties = new Properties(); + properties.putAll(props); properties.setProperty(server, server); properties.setProperty(port, "1234"); properties.setProperty(db, db); @@ -47,9 +48,6 @@ void test_buildUrl( final String actual = ConnectionUrlBuilder.buildUrl( jdbcProtocol, host, - server, - port, - db, properties); assertEquals(expected, actual); } @@ -70,9 +68,6 @@ void test_buildUrl_throwsSQLException( assertThrows(SQLException.class, () -> ConnectionUrlBuilder.buildUrl( jdbcProtocol, host, - server, - port, - db, properties)); } @@ -87,7 +82,7 @@ static Stream urlArguments() { "", "port", "database", - "protocol//fooUrl/database", + "protocol//fooUrl/database?port=1234&bar=baz", properties), Arguments.of( "protocol//", @@ -95,7 +90,7 @@ static Stream urlArguments() { " ", "port", "database", - "protocol//fooUrl/database", + "protocol//fooUrl/database?port=1234&bar=baz", properties), Arguments.of( "protocol", @@ -103,24 +98,8 @@ static Stream urlArguments() { "server", "port", "database", - "protocol//fooUrl/database", - properties), - Arguments.of( - "protocol", - null, - "server", - "port", - "database", - "protocol//server:1234/database", - null), - Arguments.of( - "protocol", - null, - "server", - "port", - "db", - "protocol//server:1234/", - null) + "protocol//fooUrl/database?port=1234&bar=baz&server=server", + properties) ); } diff --git a/wrapper/src/test/java/software/amazon/logging/ExtendedFormatter.java b/wrapper/src/test/java/software/amazon/logging/ExtendedFormatter.java index e819d58f1..7a228cd07 100644 --- a/wrapper/src/test/java/software/amazon/logging/ExtendedFormatter.java +++ b/wrapper/src/test/java/software/amazon/logging/ExtendedFormatter.java @@ -42,6 +42,7 @@ public class ExtendedFormatter extends SimpleFormatter { * - ( 5$) the log message * - ( 6$) the throwable and its backtrace, if any * - ( 7$) the thread name + * - ( 8$) the thread ID */ private static final String format = LogManager.getLogManager() .getProperty(ExtendedFormatter.class.getName() + ".format"); @@ -92,7 +93,8 @@ public synchronized String format(LogRecord record) { record.getLevel().getLocalizedName(), message, throwable, - threadName); + threadName, + record.getThreadID()); } private static String getThreadName(int logRecordThreadId) { diff --git a/wrapper/src/test/resources/simplelogger.properties b/wrapper/src/test/resources/simplelogger.properties index 30fd2f992..21e3e39ec 100644 --- a/wrapper/src/test/resources/simplelogger.properties +++ b/wrapper/src/test/resources/simplelogger.properties @@ -21,4 +21,6 @@ org.slf4j.simpleLogger.defaultLogLevel=warn org.slf4j.simpleLogger.log.org.testcontainers=warn org.slf4j.simpleLogger.log.com.github.dockerjava=info -org.slf4j.simpleLogger.log.integration.container=debug \ No newline at end of file +org.slf4j.simpleLogger.log.integration.container=debug + +org.slf4j.simpleLogger.log.com.zaxxer.hikari=trace