Merge pull request #23403 from fabio-grassi-gbs
* pr/23403: Polish "Add support for Oracle UCP" Add support for Oracle UCP Closes gh-23403
This commit is contained in:
commit
a983fb9559
|
@ -82,6 +82,8 @@ public class DocumentConfigurationProperties extends DefaultTask {
|
|||
.withKeyPrefixes("spring.couchbase", "spring.elasticsearch", "spring.h2", "spring.influx",
|
||||
"spring.mongodb", "spring.neo4j", "spring.redis", "spring.dao", "spring.data",
|
||||
"spring.datasource", "spring.jooq", "spring.jdbc", "spring.jpa", "spring.r2dbc")
|
||||
.addOverride("spring.datasource.oracleucp",
|
||||
"Oracle UCP specific settings bound to an instance of Oracle UCP's PoolDataSource")
|
||||
.addOverride("spring.datasource.dbcp2",
|
||||
"Commons DBCP2 specific settings bound to an instance of DBCP2's BasicDataSource")
|
||||
.addOverride("spring.datasource.tomcat",
|
||||
|
|
|
@ -24,6 +24,8 @@ dependencies {
|
|||
optional("com.hazelcast:hazelcast-spring")
|
||||
optional("com.h2database:h2")
|
||||
optional("com.nimbusds:oauth2-oidc-sdk")
|
||||
optional("com.oracle.database.jdbc:ojdbc8")
|
||||
optional("com.oracle.database.jdbc:ucp")
|
||||
optional("com.samskivert:jmustache")
|
||||
optional("com.sun.mail:jakarta.mail")
|
||||
optional("de.flapdoodle.embed:de.flapdoodle.embed.mongo")
|
||||
|
|
|
@ -69,8 +69,8 @@ public class DataSourceAutoConfiguration {
|
|||
@Conditional(PooledDataSourceCondition.class)
|
||||
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
|
||||
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
|
||||
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
|
||||
DataSourceJmxConfiguration.class })
|
||||
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
|
||||
DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
|
||||
protected static class PooledDataSourceConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,9 +16,13 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import oracle.jdbc.OracleConnection;
|
||||
import oracle.ucp.jdbc.PoolDataSourceImpl;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
@ -35,6 +39,7 @@ import org.springframework.util.StringUtils;
|
|||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @author Fabio Grassi
|
||||
*/
|
||||
abstract class DataSourceConfiguration {
|
||||
|
||||
|
@ -109,6 +114,29 @@ abstract class DataSourceConfiguration {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Oracle UCP DataSource configuration.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ PoolDataSourceImpl.class, OracleConnection.class })
|
||||
@ConditionalOnMissingBean(DataSource.class)
|
||||
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "oracle.ucp.jdbc.PoolDataSource",
|
||||
matchIfMissing = true)
|
||||
static class OracleUcp {
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(prefix = "spring.datasource.oracleucp")
|
||||
PoolDataSourceImpl dataSource(DataSourceProperties properties) throws SQLException {
|
||||
PoolDataSourceImpl dataSource = createDataSource(properties, PoolDataSourceImpl.class);
|
||||
dataSource.setValidateConnectionOnBorrow(true);
|
||||
if (StringUtils.hasText(properties.getName())) {
|
||||
dataSource.setConnectionPoolName(properties.getName());
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic DataSource configuration.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,6 +17,8 @@
|
|||
package org.springframework.boot.autoconfigure.jdbc.metadata;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import oracle.jdbc.OracleConnection;
|
||||
import oracle.ucp.jdbc.PoolDataSource;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
|
@ -24,6 +26,7 @@ import org.springframework.boot.jdbc.DataSourceUnwrapper;
|
|||
import org.springframework.boot.jdbc.metadata.CommonsDbcp2DataSourcePoolMetadata;
|
||||
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
|
||||
import org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata;
|
||||
import org.springframework.boot.jdbc.metadata.OracleUcpDataSourcePoolMetadata;
|
||||
import org.springframework.boot.jdbc.metadata.TomcatDataSourcePoolMetadata;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -33,6 +36,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
* sources.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Fabio Grassi
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
@ -90,4 +94,21 @@ public class DataSourcePoolMetadataProvidersConfiguration {
|
|||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ PoolDataSource.class, OracleConnection.class })
|
||||
static class OracleUcpPoolDataSourceMetadataProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
DataSourcePoolMetadataProvider oracleUcpPoolDataSourceMetadataProvider() {
|
||||
return (dataSource) -> {
|
||||
PoolDataSource ucpDataSource = DataSourceUnwrapper.unwrap(dataSource, PoolDataSource.class);
|
||||
if (ucpDataSource != null) {
|
||||
return new OracleUcpDataSourcePoolMetadata(ucpDataSource);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import javax.sql.DataSource;
|
|||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import oracle.ucp.jdbc.PoolDataSourceImpl;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -135,8 +136,25 @@ class DataSourceAutoConfigurationTests {
|
|||
assertDataSource(org.apache.commons.dbcp2.BasicDataSource.class,
|
||||
Arrays.asList("com.zaxxer.hikari", "org.apache.tomcat"), (dataSource) -> {
|
||||
assertThat(dataSource.getTestOnBorrow()).isTrue();
|
||||
assertThat(dataSource.getValidationQuery()).isNull(); // Use
|
||||
// Connection#isValid()
|
||||
// Use Connection#isValid()
|
||||
assertThat(dataSource.getValidationQuery()).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void oracleUcpIsFallback() {
|
||||
assertDataSource(PoolDataSourceImpl.class,
|
||||
Arrays.asList("com.zaxxer.hikari", "org.apache.tomcat", "org.apache.commons.dbcp2"),
|
||||
(dataSource) -> assertThat(dataSource.getURL()).startsWith("jdbc:hsqldb:mem:testdb"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void oracleUcpValidatesConnectionByDefault() {
|
||||
assertDataSource(PoolDataSourceImpl.class,
|
||||
Arrays.asList("com.zaxxer.hikari", "org.apache.tomcat", "org.apache.commons.dbcp2"), (dataSource) -> {
|
||||
assertThat(dataSource.getValidateConnectionOnBorrow()).isTrue();
|
||||
// Use an internal ping when using an Oracle JDBC driver
|
||||
assertThat(dataSource.getSQLForValidateConnection()).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -225,8 +243,8 @@ class DataSourceAutoConfigurationTests {
|
|||
}
|
||||
|
||||
private static Function<ApplicationContextRunner, ApplicationContextRunner> hideConnectionPools() {
|
||||
return (runner) -> runner.withClassLoader(
|
||||
new FilteredClassLoader("org.apache.tomcat", "com.zaxxer.hikari", "org.apache.commons.dbcp2"));
|
||||
return (runner) -> runner.withClassLoader(new FilteredClassLoader("org.apache.tomcat", "com.zaxxer.hikari",
|
||||
"org.apache.commons.dbcp2", "oracle.ucp.jdbc"));
|
||||
}
|
||||
|
||||
private <T extends DataSource> void assertDataSource(Class<T> expectedType, List<String> hiddenPackages,
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import oracle.ucp.jdbc.PoolDataSource;
|
||||
import oracle.ucp.jdbc.PoolDataSourceImpl;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link DataSourceAutoConfiguration} with Oracle UCP.
|
||||
*
|
||||
* @author Fabio Grassi
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class OracleUcpDataSourceConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.initialization-mode=never",
|
||||
"spring.datasource.type=" + PoolDataSource.class.getName());
|
||||
|
||||
@Test
|
||||
void testDataSourceExists() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context.getBeansOfType(DataSource.class)).hasSize(1);
|
||||
assertThat(context.getBeansOfType(PoolDataSourceImpl.class)).hasSize(1);
|
||||
try (Connection connection = context.getBean(DataSource.class).getConnection()) {
|
||||
assertThat(connection.isValid(1000)).isTrue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDataSourcePropertiesOverridden() {
|
||||
this.contextRunner.withPropertyValues("spring.datasource.oracleucp.url=jdbc:foo//bar/spam",
|
||||
"spring.datasource.oracleucp.max-idle-time=1234").run((context) -> {
|
||||
PoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);
|
||||
assertThat(ds.getURL()).isEqualTo("jdbc:foo//bar/spam");
|
||||
assertThat(ds.getMaxIdleTime()).isEqualTo(1234);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDataSourceConnectionPropertiesOverridden() {
|
||||
this.contextRunner.withPropertyValues("spring.datasource.oracleucp.connection-properties.autoCommit=false")
|
||||
.run((context) -> {
|
||||
PoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);
|
||||
assertThat(ds.getConnectionProperty("autoCommit")).isEqualTo("false");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDataSourceDefaultsPreserved() {
|
||||
this.contextRunner.run((context) -> {
|
||||
PoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);
|
||||
assertThat(ds.getInitialPoolSize()).isEqualTo(0);
|
||||
assertThat(ds.getMinPoolSize()).isEqualTo(0);
|
||||
assertThat(ds.getMaxPoolSize()).isEqualTo(Integer.MAX_VALUE);
|
||||
assertThat(ds.getInactiveConnectionTimeout()).isEqualTo(0);
|
||||
assertThat(ds.getConnectionWaitTimeout()).isEqualTo(3);
|
||||
assertThat(ds.getTimeToLiveConnectionTimeout()).isEqualTo(0);
|
||||
assertThat(ds.getAbandonedConnectionTimeout()).isEqualTo(0);
|
||||
assertThat(ds.getTimeoutCheckInterval()).isEqualTo(30);
|
||||
assertThat(ds.getFastConnectionFailoverEnabled()).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void nameIsAliasedToPoolName() {
|
||||
this.contextRunner.withPropertyValues("spring.datasource.name=myDS").run((context) -> {
|
||||
PoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);
|
||||
assertThat(ds.getConnectionPoolName()).isEqualTo("myDS");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void poolNameTakesPrecedenceOverName() {
|
||||
this.contextRunner.withPropertyValues("spring.datasource.name=myDS",
|
||||
"spring.datasource.oracleucp.connection-pool-name=myOracleUcpDS").run((context) -> {
|
||||
PoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);
|
||||
assertThat(ds.getConnectionPoolName()).isEqualTo("myOracleUcpDS");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -105,8 +105,8 @@ class LiquibaseAutoConfigurationTests {
|
|||
@Test
|
||||
void createsDataSourceWhenSpringJdbcOnlyAvailableWithNoDataSourceBeanAndLiquibaseUrl() {
|
||||
this.contextRunner.withPropertyValues("spring.liquibase.url:jdbc:hsqldb:mem:liquibase")
|
||||
.withClassLoader(
|
||||
new FilteredClassLoader("org.apache.tomcat", "com.zaxxer.hikari", "org.apache.commons.dbcp2"))
|
||||
.withClassLoader(new FilteredClassLoader("org.apache.tomcat", "com.zaxxer.hikari",
|
||||
"org.apache.commons.dbcp2", "oracle.ucp.jdbc"))
|
||||
.run(assertLiquibase((liquibase) -> {
|
||||
DataSource dataSource = liquibase.getDataSource();
|
||||
assertThat(dataSource).isInstanceOf(SimpleDriverDataSource.class);
|
||||
|
|
|
@ -3826,7 +3826,8 @@ Spring Boot uses the following algorithm for choosing a specific implementation:
|
|||
. We prefer https://github.com/brettwooldridge/HikariCP[HikariCP] for its performance and concurrency.
|
||||
If HikariCP is available, we always choose it.
|
||||
. Otherwise, if the Tomcat pooling `DataSource` is available, we use it.
|
||||
. If neither HikariCP nor the Tomcat pooling datasource are available and if https://commons.apache.org/proper/commons-dbcp/[Commons DBCP2] is available, we use it.
|
||||
. Otherwise, if https://commons.apache.org/proper/commons-dbcp/[Commons DBCP2] is available, we use it.
|
||||
. If none of HikariCP, Tomcat, and DBCP2 are available and if Oracle UCP is available, we use it.
|
||||
|
||||
If you use the `spring-boot-starter-jdbc` or `spring-boot-starter-data-jpa` "`starters`", you automatically get a dependency to `HikariCP`.
|
||||
|
||||
|
@ -3857,7 +3858,7 @@ In other words, if you set `spring.datasource.driver-class-name=com.mysql.jdbc.D
|
|||
|
||||
See {spring-boot-autoconfigure-module-code}/jdbc/DataSourceProperties.java[`DataSourceProperties`] for more of the supported options.
|
||||
These are the standard options that work regardless of the actual implementation.
|
||||
It is also possible to fine-tune implementation-specific settings by using their respective prefix (`+spring.datasource.hikari.*+`, `+spring.datasource.tomcat.*+`, and `+spring.datasource.dbcp2.*+`).
|
||||
It is also possible to fine-tune implementation-specific settings by using their respective prefix (`+spring.datasource.hikari.*+`, `+spring.datasource.tomcat.*+`, `+spring.datasource.dbcp2.*+`, and `+spring.datasource.oracleucp.*+`).
|
||||
Refer to the documentation of the connection pool implementation you are using for more details.
|
||||
|
||||
For instance, if you use the {tomcat-docs}/jdbc-pool.html#Common_Attributes[Tomcat connection pool], you could customize many additional settings, as shown in the following example:
|
||||
|
|
|
@ -21,6 +21,7 @@ dependencies {
|
|||
optional("com.atomikos:transactions-jta")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
optional("com.google.code.gson:gson")
|
||||
optional("com.oracle.database.jdbc:ucp")
|
||||
optional("com.samskivert:jmustache")
|
||||
optional("com.zaxxer:HikariCP")
|
||||
optional("io.netty:netty-tcnative-boringssl-static")
|
||||
|
@ -77,7 +78,7 @@ dependencies {
|
|||
testImplementation("com.ibm.db2:jcc")
|
||||
testImplementation("com.jayway.jsonpath:json-path")
|
||||
testImplementation("com.microsoft.sqlserver:mssql-jdbc")
|
||||
testImplementation("com.oracle.ojdbc:ojdbc8")
|
||||
testImplementation("com.oracle.database.jdbc:ojdbc8")
|
||||
testImplementation("com.squareup.okhttp3:okhttp")
|
||||
testImplementation("com.sun.xml.messaging.saaj:saaj-impl")
|
||||
testImplementation("io.projectreactor:reactor-test")
|
||||
|
|
|
@ -37,16 +37,17 @@ import org.springframework.util.ClassUtils;
|
|||
|
||||
/**
|
||||
* Convenience class for building a {@link DataSource} with common implementations and
|
||||
* properties. If HikariCP, Tomcat or Commons DBCP are on the classpath one of them will
|
||||
* be selected (in that order with Hikari first). In the interest of a uniform interface,
|
||||
* and so that there can be a fallback to an embedded database if one can be detected on
|
||||
* the classpath, only a small set of common configuration properties are supported. To
|
||||
* inject additional properties into the result you can downcast it, or use
|
||||
* properties. If HikariCP, Tomcat, Commons DBCP or Oracle UCP are on the classpath one of
|
||||
* them will be selected (in that order with Hikari first). In the interest of a uniform
|
||||
* interface, and so that there can be a fallback to an embedded database if one can be
|
||||
* detected on the classpath, only a small set of common configuration properties are
|
||||
* supported. To inject additional properties into the result you can downcast it, or use
|
||||
* {@code @ConfigurationProperties}.
|
||||
*
|
||||
* @param <T> type of DataSource produced by the builder
|
||||
* @author Dave Syer
|
||||
* @author Madhura Bhave
|
||||
* @author Fabio Grassi
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class DataSourceBuilder<T extends DataSource> {
|
||||
|
@ -166,9 +167,9 @@ public final class DataSourceBuilder<T extends DataSource> {
|
|||
|
||||
}
|
||||
|
||||
private static class OracleDataSourceSettings extends DataSourceSettings {
|
||||
private static class OracleCommonDataSourceSettings extends DataSourceSettings {
|
||||
|
||||
OracleDataSourceSettings(Class<? extends DataSource> type) {
|
||||
OracleCommonDataSourceSettings(Class<? extends DataSource> type) {
|
||||
super(type, (aliases) -> aliases.addAliases("username", "user"));
|
||||
}
|
||||
|
||||
|
@ -194,7 +195,7 @@ public final class DataSourceBuilder<T extends DataSource> {
|
|||
(type) -> new DataSourceSettings(type,
|
||||
(aliases) -> aliases.addAliases("driver-class-name", "driver-class"))));
|
||||
addIfAvailable(this.allDataSourceSettings, create(classLoader,
|
||||
"oracle.jdbc.datasource.OracleCommonDataSource", OracleDataSourceSettings::new));
|
||||
"oracle.jdbc.datasource.OracleCommonDataSource", OracleCommonDataSourceSettings::new));
|
||||
}
|
||||
|
||||
private static List<DataSourceSettings> resolveAvailableDataSourceSettings(ClassLoader classLoader) {
|
||||
|
@ -205,6 +206,16 @@ public final class DataSourceBuilder<T extends DataSource> {
|
|||
create(classLoader, "org.apache.tomcat.jdbc.pool.DataSource", DataSourceSettings::new));
|
||||
addIfAvailable(providers,
|
||||
create(classLoader, "org.apache.commons.dbcp2.BasicDataSource", DataSourceSettings::new));
|
||||
addIfAvailable(providers, create(classLoader, "oracle.ucp.jdbc.PoolDataSourceImpl", (type) -> {
|
||||
// Unfortunately Oracle UCP has an import on the Oracle driver itself
|
||||
if (ClassUtils.isPresent("oracle.jdbc.OracleConnection", classLoader)) {
|
||||
return new DataSourceSettings(type, (aliases) -> {
|
||||
aliases.addAliases("username", "user");
|
||||
aliases.addAliases("driver-class-name", "connection-factory-class-name");
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
return providers;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.jdbc.metadata;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import oracle.ucp.jdbc.PoolDataSource;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link DataSourcePoolMetadata} for an Oracle UCP {@link DataSource}.
|
||||
*
|
||||
* @author Fabio Grassi
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public class OracleUcpDataSourcePoolMetadata extends AbstractDataSourcePoolMetadata<PoolDataSource> {
|
||||
|
||||
public OracleUcpDataSourcePoolMetadata(PoolDataSource dataSource) {
|
||||
super(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getActive() {
|
||||
try {
|
||||
return getDataSource().getBorrowedConnectionsCount();
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getIdle() {
|
||||
try {
|
||||
return getDataSource().getAvailableConnectionsCount();
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMax() {
|
||||
return getDataSource().getMaxPoolSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMin() {
|
||||
return getDataSource().getMinPoolSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValidationQuery() {
|
||||
return getDataSource().getSQLForValidateConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getDefaultAutoCommit() {
|
||||
String autoCommit = getDataSource().getConnectionProperty("autoCommit");
|
||||
return StringUtils.hasText(autoCommit) ? Boolean.valueOf(autoCommit) : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@ import javax.sql.DataSource;
|
|||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import oracle.jdbc.pool.OracleDataSource;
|
||||
import oracle.ucp.jdbc.PoolDataSourceImpl;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.h2.Driver;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -40,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* Tests for {@link DataSourceBuilder}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Fabio Grassi
|
||||
*/
|
||||
class DataSourceBuilderTests {
|
||||
|
||||
|
@ -68,13 +70,20 @@ class DataSourceBuilderTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void defaultToCommonsDbcp2AsLastResort() {
|
||||
void defaultToCommonsDbcp2IfNeitherHikariNorTomcatIsNotAvailable() {
|
||||
this.dataSource = DataSourceBuilder
|
||||
.create(new HidePackagesClassLoader("com.zaxxer.hikari", "org.apache.tomcat.jdbc.pool"))
|
||||
.url("jdbc:h2:test").build();
|
||||
assertThat(this.dataSource).isInstanceOf(BasicDataSource.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultToOracleUcpAsLastResort() {
|
||||
this.dataSource = DataSourceBuilder.create(new HidePackagesClassLoader("com.zaxxer.hikari",
|
||||
"org.apache.tomcat.jdbc.pool", "org.apache.commons.dbcp2")).url("jdbc:h2:test").build();
|
||||
assertThat(this.dataSource).isInstanceOf(PoolDataSourceImpl.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void specificTypeOfDataSource() {
|
||||
HikariDataSource hikariDataSource = DataSourceBuilder.create().type(HikariDataSource.class).build();
|
||||
|
@ -100,6 +109,16 @@ class DataSourceBuilderTests {
|
|||
assertThat(oracleDataSource.getUser()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void dataSourceCanBeCreatedWithOracleUcpDataSource() {
|
||||
this.dataSource = DataSourceBuilder.create().driverClassName("org.hsqldb.jdbc.JDBCDriver")
|
||||
.type(PoolDataSourceImpl.class).username("test").build();
|
||||
assertThat(this.dataSource).isInstanceOf(PoolDataSourceImpl.class);
|
||||
PoolDataSourceImpl upcDataSource = (PoolDataSourceImpl) this.dataSource;
|
||||
assertThat(upcDataSource.getConnectionFactoryClassName()).isEqualTo("org.hsqldb.jdbc.JDBCDriver");
|
||||
assertThat(upcDataSource.getUser()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void dataSourceAliasesAreOnlyAppliedToRelevantDataSource() {
|
||||
this.dataSource = DataSourceBuilder.create().url("jdbc:h2:test").type(TestDataSource.class).username("test")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -90,10 +90,10 @@ abstract class AbstractDataSourcePoolMetadataTests<D extends AbstractDataSourceP
|
|||
}
|
||||
|
||||
@Test
|
||||
abstract void getValidationQuery();
|
||||
abstract void getValidationQuery() throws Exception;
|
||||
|
||||
@Test
|
||||
abstract void getDefaultAutoCommit();
|
||||
abstract void getDefaultAutoCommit() throws Exception;
|
||||
|
||||
protected DataSourceBuilder<?> initializeBuilder() {
|
||||
return DataSourceBuilder.create().driverClassName("org.hsqldb.jdbc.JDBCDriver").url("jdbc:hsqldb:mem:test")
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.jdbc.metadata;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import oracle.ucp.jdbc.PoolDataSource;
|
||||
import oracle.ucp.jdbc.PoolDataSourceImpl;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link OracleUcpDataSourcePoolMetadata}.
|
||||
*
|
||||
* @author Fabio Grassi
|
||||
*/
|
||||
class OracleUcpDataSourcePoolMetadataTests
|
||||
extends AbstractDataSourcePoolMetadataTests<OracleUcpDataSourcePoolMetadata> {
|
||||
|
||||
private final OracleUcpDataSourcePoolMetadata dataSourceMetadata = new OracleUcpDataSourcePoolMetadata(
|
||||
createDataSource(0, 2));
|
||||
|
||||
@Override
|
||||
protected OracleUcpDataSourcePoolMetadata getDataSourceMetadata() {
|
||||
return this.dataSourceMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
void getValidationQuery() throws SQLException {
|
||||
PoolDataSource dataSource = createDataSource(0, 4);
|
||||
dataSource.setSQLForValidateConnection("SELECT NULL FROM DUAL");
|
||||
assertThat(new OracleUcpDataSourcePoolMetadata(dataSource).getValidationQuery())
|
||||
.isEqualTo("SELECT NULL FROM DUAL");
|
||||
}
|
||||
|
||||
@Override
|
||||
void getDefaultAutoCommit() throws SQLException {
|
||||
PoolDataSource dataSource = createDataSource(0, 4);
|
||||
dataSource.setConnectionProperty("autoCommit", "false");
|
||||
assertThat(new OracleUcpDataSourcePoolMetadata(dataSource).getDefaultAutoCommit()).isFalse();
|
||||
}
|
||||
|
||||
private PoolDataSource createDataSource(int minSize, int maxSize) {
|
||||
try {
|
||||
PoolDataSource dataSource = initializeBuilder().type(PoolDataSourceImpl.class).build();
|
||||
dataSource.setInitialPoolSize(minSize);
|
||||
dataSource.setMinPoolSize(minSize);
|
||||
dataSource.setMaxPoolSize(maxSize);
|
||||
return dataSource;
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
throw new IllegalStateException("Error while configuring PoolDataSource", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue