Add support for Oracle UCP

See gh-23403
This commit is contained in:
Fabio Grassi 2020-09-17 23:00:16 +02:00 committed by Stephane Nicoll
parent a19a565410
commit a21ab392b6
10 changed files with 355 additions and 14 deletions

View File

@ -64,6 +64,7 @@ dependencies {
optional("org.codehaus.groovy:groovy-templates") optional("org.codehaus.groovy:groovy-templates")
optional("com.github.ben-manes.caffeine:caffeine") optional("com.github.ben-manes.caffeine:caffeine")
optional("com.github.mxab.thymeleaf.extras:thymeleaf-extras-data-attribute") optional("com.github.mxab.thymeleaf.extras:thymeleaf-extras-data-attribute")
optional("com.oracle.database.jdbc:ucp")
optional("com.sendgrid:sendgrid-java") optional("com.sendgrid:sendgrid-java")
optional("com.unboundid:unboundid-ldapsdk") optional("com.unboundid:unboundid-ldapsdk")
optional("com.zaxxer:HikariCP") optional("com.zaxxer:HikariCP")

View File

@ -48,6 +48,7 @@ import org.springframework.util.StringUtils;
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Kazuki Shimizu * @author Kazuki Shimizu
* @author Fabio Grassi
* @since 1.0.0 * @since 1.0.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ -69,8 +70,8 @@ public class DataSourceAutoConfiguration {
@Conditional(PooledDataSourceCondition.class) @Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class, @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class, DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Ucp.class,
DataSourceJmxConfiguration.class }) DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration { protected static class PooledDataSourceConfiguration {
} }

View File

@ -16,9 +16,13 @@
package org.springframework.boot.autoconfigure.jdbc; package org.springframework.boot.autoconfigure.jdbc;
import java.sql.SQLException;
import javax.sql.DataSource; import javax.sql.DataSource;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -27,6 +31,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -35,6 +40,7 @@ import org.springframework.util.StringUtils;
* @author Dave Syer * @author Dave Syer
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Fabio Grassi
*/ */
abstract class DataSourceConfiguration { abstract class DataSourceConfiguration {
@ -109,6 +115,33 @@ abstract class DataSourceConfiguration {
} }
/**
* UCP DataSource configuration.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(PoolDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "oracle.ucp.jdbc.PoolDataSource",
matchIfMissing = true)
static class Ucp {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.ucp")
PoolDataSource dataSource(DataSourceProperties properties) {
PoolDataSource dataSource = createDataSource(properties, PoolDataSourceImpl.class);
if (StringUtils.hasText(properties.getName())) {
try {
dataSource.setConnectionPoolName(properties.getName());
}
catch (SQLException se) {
throw new InvalidDataAccessApiUsageException("Error setting property connectionPoolName", se);
}
}
return dataSource;
}
}
/** /**
* Generic DataSource configuration. * Generic DataSource configuration.
*/ */

View File

@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.jdbc.metadata; package org.springframework.boot.autoconfigure.jdbc.metadata;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import oracle.ucp.jdbc.PoolDataSource;
import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -25,6 +26,7 @@ import org.springframework.boot.jdbc.metadata.CommonsDbcp2DataSourcePoolMetadata
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider; import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
import org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata; import org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata;
import org.springframework.boot.jdbc.metadata.TomcatDataSourcePoolMetadata; import org.springframework.boot.jdbc.metadata.TomcatDataSourcePoolMetadata;
import org.springframework.boot.jdbc.metadata.UcpDataSourcePoolMetadata;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -33,6 +35,7 @@ import org.springframework.context.annotation.Configuration;
* sources. * sources.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Fabio Grassi
* @since 1.2.0 * @since 1.2.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ -90,4 +93,21 @@ public class DataSourcePoolMetadataProvidersConfiguration {
} }
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(PoolDataSource.class)
static class UcpPoolDataSourceMetadataProviderConfiguration {
@Bean
DataSourcePoolMetadataProvider UcpPoolDataSourceMetadataProvider() {
return (dataSource) -> {
PoolDataSource ucpDataSource = DataSourceUnwrapper.unwrap(dataSource, PoolDataSource.class);
if (ucpDataSource != null) {
return new UcpDataSourcePoolMetadata(ucpDataSource);
}
return null;
};
}
}
} }

View File

@ -0,0 +1,105 @@
/*
* 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 static org.assertj.core.api.Assertions.assertThat;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceImpl;
/**
* Tests for {@link DataSourceAutoConfiguration} with Oracle UCP.
*
* @author Fabio Grassi
*/
class UcpDataSourceConfigurationTests {
private static final String PREFIX = "spring.datasource.ucp.";
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);
});
}
@Test
void testDataSourcePropertiesOverridden() {
this.contextRunner.withPropertyValues(PREFIX + "URL=jdbc:foo//bar/spam", PREFIX + "maxIdleTime=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(PREFIX + "connectionProperties.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 connectionPoolNameTakesPrecedenceOverName() {
this.contextRunner.withPropertyValues("spring.datasource.name=myDS", PREFIX + "connectionPoolName=myUcpDS")
.run((context) -> {
PoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);
assertThat(ds.getConnectionPoolName()).isEqualTo("myUcpDS");
});
}
}

View File

@ -21,6 +21,7 @@ dependencies {
optional("com.atomikos:transactions-jta") optional("com.atomikos:transactions-jta")
optional("com.fasterxml.jackson.core:jackson-databind") optional("com.fasterxml.jackson.core:jackson-databind")
optional("com.google.code.gson:gson") optional("com.google.code.gson:gson")
optional("com.oracle.database.jdbc:ucp")
optional("com.samskivert:jmustache") optional("com.samskivert:jmustache")
optional("com.zaxxer:HikariCP") optional("com.zaxxer:HikariCP")
optional("io.netty:netty-tcnative-boringssl-static") optional("io.netty:netty-tcnative-boringssl-static")
@ -77,7 +78,7 @@ dependencies {
testImplementation("com.ibm.db2:jcc") testImplementation("com.ibm.db2:jcc")
testImplementation("com.jayway.jsonpath:json-path") testImplementation("com.jayway.jsonpath:json-path")
testImplementation("com.microsoft.sqlserver:mssql-jdbc") testImplementation("com.microsoft.sqlserver:mssql-jdbc")
testImplementation("com.oracle.ojdbc:ojdbc8") testImplementation("com.oracle.database.jdbc:ojdbc8")
testImplementation("com.squareup.okhttp3:okhttp") testImplementation("com.squareup.okhttp3:okhttp")
testImplementation("com.sun.xml.messaging.saaj:saaj-impl") testImplementation("com.sun.xml.messaging.saaj:saaj-impl")
testImplementation("io.projectreactor:reactor-test") testImplementation("io.projectreactor:reactor-test")

View File

@ -37,16 +37,17 @@ import org.springframework.util.ClassUtils;
/** /**
* Convenience class for building a {@link DataSource} with common implementations and * 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 * properties. If HikariCP, Tomcat, Commons DBCP or Oracle UCP are on the classpath one of
* be selected (in that order with Hikari first). In the interest of a uniform interface, * them will be selected (in that order with Hikari first). In the interest of a uniform
* and so that there can be a fallback to an embedded database if one can be detected on * interface, and so that there can be a fallback to an embedded database if one can be
* the classpath, only a small set of common configuration properties are supported. To * detected on the classpath, only a small set of common configuration properties are
* inject additional properties into the result you can downcast it, or use * supported. To inject additional properties into the result you can downcast it, or use
* {@code @ConfigurationProperties}. * {@code @ConfigurationProperties}.
* *
* @param <T> type of DataSource produced by the builder * @param <T> type of DataSource produced by the builder
* @author Dave Syer * @author Dave Syer
* @author Madhura Bhave * @author Madhura Bhave
* @author Fabio Grassi
* @since 2.0.0 * @since 2.0.0
*/ */
public final class DataSourceBuilder<T extends DataSource> { 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")); super(type, (aliases) -> aliases.addAliases("username", "user"));
} }
@ -194,7 +195,7 @@ public final class DataSourceBuilder<T extends DataSource> {
(type) -> new DataSourceSettings(type, (type) -> new DataSourceSettings(type,
(aliases) -> aliases.addAliases("driver-class-name", "driver-class")))); (aliases) -> aliases.addAliases("driver-class-name", "driver-class"))));
addIfAvailable(this.allDataSourceSettings, create(classLoader, addIfAvailable(this.allDataSourceSettings, create(classLoader,
"oracle.jdbc.datasource.OracleCommonDataSource", OracleDataSourceSettings::new)); "oracle.jdbc.datasource.OracleCommonDataSource", OracleCommonDataSourceSettings::new));
} }
private static List<DataSourceSettings> resolveAvailableDataSourceSettings(ClassLoader classLoader) { private static List<DataSourceSettings> resolveAvailableDataSourceSettings(ClassLoader classLoader) {
@ -205,6 +206,8 @@ public final class DataSourceBuilder<T extends DataSource> {
create(classLoader, "org.apache.tomcat.jdbc.pool.DataSource", DataSourceSettings::new)); create(classLoader, "org.apache.tomcat.jdbc.pool.DataSource", DataSourceSettings::new));
addIfAvailable(providers, addIfAvailable(providers,
create(classLoader, "org.apache.commons.dbcp2.BasicDataSource", DataSourceSettings::new)); create(classLoader, "org.apache.commons.dbcp2.BasicDataSource", DataSourceSettings::new));
addIfAvailable(providers,
create(classLoader, "oracle.ucp.jdbc.PoolDataSourceImpl", DataSourceSettings::new));
return providers; return providers;
} }

View File

@ -0,0 +1,81 @@
/*
* Copyright 2012-2019 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 org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.util.StringUtils;
import oracle.ucp.jdbc.PoolDataSource;
/**
* {@link DataSourcePoolMetadata} for a Oracle UCP {@link DataSource}.
*
* @author Fabio Grassi
* @since 2.3.4
*/
public class UcpDataSourcePoolMetadata extends AbstractDataSourcePoolMetadata<PoolDataSource> {
public UcpDataSourcePoolMetadata(PoolDataSource dataSource) {
super(dataSource);
}
@Override
public Integer getActive() {
try {
return getDataSource().getBorrowedConnectionsCount();
}
catch (SQLException se) {
throw new InvalidDataAccessApiUsageException("Error while reading property borrowedConnectionsCount", se);
}
}
@Override
public Integer getIdle() {
try {
return getDataSource().getAvailableConnectionsCount();
}
catch (SQLException se) {
throw new InvalidDataAccessApiUsageException("Error while reading property availableConnectionsCount", se);
}
}
@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 ac = getDataSource().getConnectionProperty("autoCommit");
return StringUtils.hasText(ac) ? Boolean.valueOf(ac) : null;
}
}

View File

@ -16,6 +16,8 @@
package org.springframework.boot.jdbc; package org.springframework.boot.jdbc;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
@ -31,15 +33,17 @@ import org.apache.commons.dbcp2.BasicDataSource;
import org.h2.Driver; import org.h2.Driver;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.jdbc.datasource.SimpleDriverDataSource; import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import static org.assertj.core.api.Assertions.assertThat; import com.zaxxer.hikari.HikariDataSource;
import oracle.ucp.jdbc.PoolDataSourceImpl;
/** /**
* Tests for {@link DataSourceBuilder}. * Tests for {@link DataSourceBuilder}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Fabio Grassi
*/ */
class DataSourceBuilderTests { class DataSourceBuilderTests {
@ -68,13 +72,20 @@ class DataSourceBuilderTests {
} }
@Test @Test
void defaultToCommonsDbcp2AsLastResort() { void defaultToCommonsDbcp2IfNeitherHikariNorTomcatIsNotAvailable() {
this.dataSource = DataSourceBuilder this.dataSource = DataSourceBuilder
.create(new HidePackagesClassLoader("com.zaxxer.hikari", "org.apache.tomcat.jdbc.pool")) .create(new HidePackagesClassLoader("com.zaxxer.hikari", "org.apache.tomcat.jdbc.pool"))
.url("jdbc:h2:test").build(); .url("jdbc:h2:test").build();
assertThat(this.dataSource).isInstanceOf(BasicDataSource.class); assertThat(this.dataSource).isInstanceOf(BasicDataSource.class);
} }
@Test
void defaultToUcpAsLastResort() {
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 @Test
void specificTypeOfDataSource() { void specificTypeOfDataSource() {
HikariDataSource hikariDataSource = DataSourceBuilder.create().type(HikariDataSource.class).build(); HikariDataSource hikariDataSource = DataSourceBuilder.create().type(HikariDataSource.class).build();
@ -114,6 +125,15 @@ class DataSourceBuilderTests {
assertThat(testDataSource.getDriverClass()).isNull(); assertThat(testDataSource.getDriverClass()).isNull();
} }
@Test
void UcpCanBeCreatedByDriverClassNamee() {
this.dataSource = DataSourceBuilder.create().driverClassName("org.hsqldb.jdbc.JDBCDriver")
.type(PoolDataSourceImpl.class).build();
assertThat(this.dataSource).isInstanceOf(PoolDataSourceImpl.class);
assertThat(((PoolDataSourceImpl) this.dataSource).getConnectionFactoryClassName())
.isEqualTo("org.hsqldb.jdbc.JDBCDriver");
}
final class HidePackagesClassLoader extends URLClassLoader { final class HidePackagesClassLoader extends URLClassLoader {
private final String[] hiddenPackages; private final String[] hiddenPackages;

View File

@ -0,0 +1,76 @@
/*
* Copyright 2012-2019 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 static org.assertj.core.api.Assertions.assertThat;
import java.sql.SQLException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceImpl;
/**
* Tests for {@link UcpDataSourcePoolMetadata}.
*
* @author Fabio Grassi
*/
public class UcpDataSourcePoolMetadataTests extends AbstractDataSourcePoolMetadataTests<UcpDataSourcePoolMetadata> {
private final UcpDataSourcePoolMetadata dataSourceMetadata = new UcpDataSourcePoolMetadata(createDataSource(0, 2));
@Override
protected UcpDataSourcePoolMetadata getDataSourceMetadata() {
return this.dataSourceMetadata;
}
@Override
public void getValidationQuery() {
PoolDataSource dataSource = createDataSource(0, 4);
try {
dataSource.setSQLForValidateConnection("SELECT NULL FROM DUAL");
} catch (SQLException se) {
throw new InvalidDataAccessApiUsageException("Error while setting property SQLForValidateConnection", se);
}
assertThat(new UcpDataSourcePoolMetadata(dataSource).getValidationQuery()).isEqualTo("SELECT NULL FROM DUAL");
}
@Override
public void getDefaultAutoCommit() {
PoolDataSource dataSource = createDataSource(0, 4);
try {
dataSource.setConnectionProperty("autoCommit", "false");
} catch (SQLException se) {
throw new InvalidDataAccessApiUsageException("Error while setting property connectionProperties.autoCommit", se);
}
assertThat(new UcpDataSourcePoolMetadata(dataSource).getDefaultAutoCommit()).isFalse();
}
private PoolDataSource createDataSource(int minSize, int maxSize) {
PoolDataSource dataSource = initializeBuilder().type(PoolDataSourceImpl.class).build();
try {
dataSource.setInitialPoolSize(minSize);
dataSource.setMinPoolSize(minSize);
dataSource.setMaxPoolSize(maxSize);
} catch (SQLException se) {
throw new InvalidDataAccessApiUsageException("Error while setting a property", se);
}
return dataSource;
}
}