Skip to content

Commit

Permalink
Add the ability to pass a map of connection properties to the DataSou…
Browse files Browse the repository at this point in the history
…rce service connection creator for more control over the created DataSource.
  • Loading branch information
scottfrederick committed Nov 20, 2015
1 parent 05930a4 commit a6d19e8
Show file tree
Hide file tree
Showing 23 changed files with 249 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.w3c.dom.Element;

import java.util.List;
import java.util.Map;

/**
* Parser for the {@code <cloud:data-source>} namespace element
Expand All @@ -23,6 +24,7 @@ public class CloudDataSourceFactoryParser extends AbstractPoolingCloudServiceFac
private static final String ELEMENT_CONNECTION = "connection";
private static final String ELEMENT_POOL = "pool";
private static final String ELEMENT_DATASOURCE_NAMES = "pool-data-sources";
private static final String ELEMENT_CONNECTION_PROPERTIES = "connection-properties";

public CloudDataSourceFactoryParser() {
super(CloudDataSourceFactory.class);
Expand Down Expand Up @@ -54,9 +56,16 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit
parseListElement(dataSourceNamesElement, dataSourceConfigBeanBuilder.getRawBeanDefinition());
}

Map<?, ?> properties = null;
Element propertiesElement = DomUtils.getChildElementByTagName(element, ELEMENT_CONNECTION_PROPERTIES);
if (propertiesElement != null) {
properties = parserContext.getDelegate().parseMapElement(propertiesElement, builder.getRawBeanDefinition());
}

dataSourceConfigBeanBuilder.addConstructorArgValue(cloudPoolConfiguration);
dataSourceConfigBeanBuilder.addConstructorArgValue(cloudConnectionConfiguration);
dataSourceConfigBeanBuilder.addConstructorArgValue(dataSourceNames);
dataSourceConfigBeanBuilder.addConstructorArgValue(properties);

builder.addConstructorArgValue(dataSourceConfigBeanBuilder.getBeanDefinition());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.springframework.cloud.service.relational;

import org.springframework.cloud.service.MapServiceConnectorConfig;
import org.springframework.cloud.service.PooledServiceConnectorConfig;

import java.util.List;
import java.util.Map;

/**
*
Expand All @@ -11,21 +13,37 @@
*/
public class DataSourceConfig extends PooledServiceConnectorConfig {
private final ConnectionConfig connectionConfig;
private final MapServiceConnectorConfig connectionProperties;
private final List<String> pooledDataSourceNames;

public DataSourceConfig(PoolConfig poolConfig, ConnectionConfig connectionConfig) {
this(poolConfig, connectionConfig, null);
this(poolConfig, connectionConfig, null, null);
}

public DataSourceConfig(List<String> pooledDataSourceNames) {
this(null, null, pooledDataSourceNames);
this(null, null, pooledDataSourceNames, null);
}

public DataSourceConfig(Map<String, Object> properties) {
this(null, null, null, properties);
}

public DataSourceConfig(PoolConfig poolConfig, ConnectionConfig connectionConfig,
Map<String, Object> properties) {
this(poolConfig, connectionConfig, null, properties);
}

public DataSourceConfig(PoolConfig poolConfig, ConnectionConfig connectionConfig,
List<String> pooledDataSourceNames) {
this(poolConfig, connectionConfig, pooledDataSourceNames, null);
}

public DataSourceConfig(PoolConfig poolConfig, ConnectionConfig connectionConfig,
List<String> pooledDataSourceNames, Map<String, Object> properties) {
super(poolConfig);
this.connectionConfig = connectionConfig;
this.pooledDataSourceNames = pooledDataSourceNames;
this.connectionProperties = new MapServiceConnectorConfig(properties);
}

public ConnectionConfig getConnectionConfiguration() {
Expand All @@ -36,6 +54,10 @@ public List<String> getPooledDataSourceNames() {
return pooledDataSourceNames;
}

public MapServiceConnectorConfig getConnectionProperties() {
return connectionProperties;
}

public static class ConnectionConfig {
private String prop;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.cloud.service.MapServiceConnectionConfigurer;
import org.springframework.cloud.service.MapServiceConnectorConfig;
import org.springframework.cloud.service.PooledServiceConnectorConfigurer;

/**
Expand All @@ -14,17 +16,30 @@
*
*/
public class DataSourceConfigurer extends PooledServiceConnectorConfigurer<DataSource, DataSourceConfig> {
private MapServiceConnectionConfigurer<DataSource, MapServiceConnectorConfig> mapServiceConnectionConfigurer =
new MapServiceConnectionConfigurer<DataSource, MapServiceConnectorConfig>();

@Override
public DataSource configure(DataSource dataSource, DataSourceConfig config) {
if (config != null) {
BeanWrapper target = new BeanWrapperImpl(dataSource);

if (config.getConnectionConfiguration() != null) {
BeanWrapper connectionSource = new BeanWrapperImpl(config.getConnectionConfiguration());
setCorrespondingProperties(target, connectionSource);
}
configureConnection(dataSource, config);
configureConnectionProperties(dataSource, config);
return super.configure(dataSource, config);
}
return dataSource;
}

private void configureConnection(DataSource dataSource, DataSourceConfig config) {
if (config.getConnectionConfiguration() != null) {
BeanWrapper target = new BeanWrapperImpl(dataSource);
BeanWrapper connectionSource = new BeanWrapperImpl(config.getConnectionConfiguration());
setCorrespondingProperties(target, connectionSource);
}
}

private void configureConnectionProperties(DataSource dataSource, DataSourceConfig config) {
if (config.getConnectionProperties() != null) {
mapServiceConnectionConfigurer.configure(dataSource, config.getConnectionProperties());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
*
*/
public class MysqlDataSourceCreator extends DataSourceCreator<MysqlServiceInfo> {
private static final String[] DRIVERS = new String[]{"org.mariadb.jdbc.Driver", "com.mysql.jdbc.Driver"};
public static final String[] DRIVERS = new String[]{"org.mariadb.jdbc.Driver", "com.mysql.jdbc.Driver"};
/**
* Validation query obtained from the MySQL reference manual:
* http://dev.mysql.com/doc/refman/5.1/en/connector-j-usagenotes-j2ee.html
*/
private static final String VALIDATION_QUERY = "/* ping */ SELECT 1";
public static final String VALIDATION_QUERY = "/* ping */ SELECT 1";

public MysqlDataSourceCreator() {
super("spring-cloud.mysql.driver", DRIVERS, VALIDATION_QUERY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

public class OracleDataSourceCreator extends DataSourceCreator<OracleServiceInfo> {

private static final String[] DRIVERS = new String[]{"oracle.jdbc.OracleDriver"};
private static final String VALIDATION_QUERY = "SELECT 'Y' from dual";
public static final String[] DRIVERS = new String[]{"oracle.jdbc.OracleDriver"};
public static final String VALIDATION_QUERY = "SELECT 'Y' from dual";

public OracleDataSourceCreator() {
super("spring-cloud.oracle.driver", DRIVERS, VALIDATION_QUERY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
*/
public class PostgresqlDataSourceCreator extends DataSourceCreator<PostgresqlServiceInfo> {

private static final String[] DRIVERS = new String[]{"org.postgresql.Driver"};
private static final String VALIDATION_QUERY = "SELECT 1";
public static final String[] DRIVERS = new String[]{"org.postgresql.Driver"};
public static final String VALIDATION_QUERY = "SELECT 1";

public PostgresqlDataSourceCreator() {
super("spring-cloud.postgresql.driver", DRIVERS, VALIDATION_QUERY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<xsd:element name="connection" type="jdbcConnectionType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="pool" type="poolType" minOccurs="0" maxOccurs="1"/>
<xsd:element ref="pool-data-sources" minOccurs="0" maxOccurs="1"/>
<xsd:element ref="connection-properties" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ public static void assertPoolProperties(DataSource dataSource, int maxActive, in
public static void assertConnectionProperties(DataSource dataSource, Properties connectionProp) {
assertEquals(connectionProp, ReflectionUtils.getValue(dataSource, "connectionProperties"));
}

public static void assertConnectionProperty(DataSource dataSource, String key, Object value) {
assertEquals(value, ReflectionUtils.getValue(dataSource, key));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.springframework.cloud.config.java;

import org.springframework.cloud.service.common.MysqlServiceInfo;
import org.springframework.cloud.service.relational.MysqlDataSourceCreator;

/**
*
Expand All @@ -13,6 +14,15 @@ public MysqlServiceInfo createService(String id) {
return createMysqlService(id);
}

@Override
protected String getDriverClassName() {
return MysqlDataSourceCreator.DRIVERS[0];
}

@Override
protected String getValidationQuery() {
return MysqlDataSourceCreator.VALIDATION_QUERY;
}
}


Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.springframework.cloud.config.java;

import org.springframework.cloud.service.common.PostgresqlServiceInfo;
import org.springframework.cloud.service.relational.PostgresqlDataSourceCreator;

/**
*
Expand All @@ -13,6 +14,15 @@ public PostgresqlServiceInfo createService(String id) {
return createPostgresqlService(id);
}

@Override
protected String getDriverClassName() {
return PostgresqlDataSourceCreator.DRIVERS[0];
}

@Override
protected String getValidationQuery() {
return PostgresqlDataSourceCreator.VALIDATION_QUERY;
}
}


Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
package org.springframework.cloud.config.java;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.cloud.config.DataSourceCloudConfigTestHelper;
import org.springframework.cloud.service.PooledServiceConnectorConfig.PoolConfig;
import org.springframework.cloud.service.relational.BasicDbcpPooledDataSourceCreator;
import org.springframework.cloud.service.relational.DataSourceConfig;
import org.springframework.cloud.service.relational.DataSourceConfig.ConnectionConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

import static org.springframework.cloud.config.DataSourceCloudConfigTestHelper.assertConnectionProperties;
import static org.springframework.cloud.config.DataSourceCloudConfigTestHelper.assertConnectionProperty;
import static org.springframework.cloud.config.DataSourceCloudConfigTestHelper.assertPoolProperties;

/**
* Common base class for testing datasource-related Java config
*
* @author Ramnivas Laddad
*
*/
public abstract class DataSourceJavaConfigTest extends AbstractServiceJavaConfigTest<DataSource> {

protected abstract String getDriverClassName();
protected abstract String getValidationQuery();

public DataSourceJavaConfigTest() {
super(DatasourceConfigWithId.class, DatasourceConfigWithoutId.class);
}
Expand All @@ -49,28 +56,50 @@ public void cloudDataSourceWithoutServiceNameSpecified_TwoMixedServiceExist_byId
testContext.getBean(getConnectorType());
}


@Test
public void cloudDataSourceWithMaxPool() {
public void cloudDataSourceWithNoConfig() {
ApplicationContext testContext = getTestApplicationContext(DatasourceConfigWithServiceConfig.class,
createService("my-service"));

DataSource ds = testContext.getBean("dbPool20Wait200", getConnectorType());
DataSourceCloudConfigTestHelper.assertPoolProperties(ds, 20, 0, 200);

DataSource ds = testContext.getBean("dataSourceWithNoConfig", getConnectorType());

assertConnectionProperties(ds, null);
assertConnectionProperty(ds, "driverClassName", getDriverClassName());
assertConnectionProperty(ds, "validationQuery", getValidationQuery());
}

@Test
public void cloudDataSourceWithMaxPool() {
ApplicationContext testContext = getTestApplicationContext(DatasourceConfigWithServiceConfig.class,
createService("my-service"));

DataSource ds = testContext.getBean("dataSourceWithPoolAndConnectionConfig", getConnectorType());
assertPoolProperties(ds, 20, 0, 200);

Properties connectionProp = new Properties();
connectionProp.put("sessionVariables", "sql_mode='ANSI'");
connectionProp.put("characterEncoding", "UTF-8");
DataSourceCloudConfigTestHelper.assertConnectionProperties(ds, connectionProp);
assertConnectionProperties(ds, connectionProp);
}

@Test
public void cloudDataSourceWithMinMaxPool() {
ApplicationContext testContext = getTestApplicationContext(DatasourceConfigWithServiceConfig.class,
createService("my-service"));

DataSource ds = testContext.getBean("dbPool5_20Wait3000", getConnectorType());
DataSourceCloudConfigTestHelper.assertPoolProperties(ds, 30, 5, 3000);
DataSource ds = testContext.getBean("dataSourceWithPoolConfig", getConnectorType());
assertPoolProperties(ds, 30, 5, 3000);
}

@Test
public void cloudDataSourceWithConnectionProperties() {
ApplicationContext testContext = getTestApplicationContext(DatasourceConfigWithServiceConfig.class,
createService("my-service"));

DataSource ds = testContext.getBean("dataSourceWithConnectionPropertiesConfig", getConnectorType());
assertConnectionProperty(ds, "driverClassName", "test.driver");
assertConnectionProperty(ds, "validationQuery", "test validation query");
assertConnectionProperty(ds, "testOnBorrow", false);
}
}

Expand All @@ -90,20 +119,35 @@ public DataSource testDatasource() {

class DatasourceConfigWithServiceConfig extends AbstractCloudConfig {
@Bean
public DataSource dbPool20Wait200() { // use this name so that we have a case with default name
public DataSource dataSourceWithNoConfig() {
return connectionFactory().dataSource("my-service");
}

@Bean
public DataSource dataSourceWithPoolAndConnectionConfig() {
PoolConfig poolConfig = new PoolConfig(20, 200);
ConnectionConfig connectionConfig = new ConnectionConfig("sessionVariables=sql_mode='ANSI';characterEncoding=UTF-8");
DataSourceConfig serviceConfig = new DataSourceConfig(poolConfig, connectionConfig, basicDbcpConnectionPool());
return connectionFactory().dataSource("my-service", serviceConfig);
}

@Bean
public DataSource dbPool5_20Wait3000() { // use this name so that we have a case with default name
public DataSource dataSourceWithPoolConfig() {
PoolConfig poolConfig = new PoolConfig(5, 30, 3000);
DataSourceConfig serviceConfig = new DataSourceConfig(poolConfig, null, basicDbcpConnectionPool());
return connectionFactory().dataSource("my-service", serviceConfig);
}

@Bean
public DataSource dataSourceWithConnectionPropertiesConfig() {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("driverClassName", "test.driver");
properties.put("validationQuery", "test validation query");
properties.put("testOnBorrow", false);
DataSourceConfig serviceConfig = new DataSourceConfig(null, null, basicDbcpConnectionPool(), properties);
return connectionFactory().dataSource("my-service", serviceConfig);
}

private List<String> basicDbcpConnectionPool() {
return Collections.singletonList(BasicDbcpPooledDataSourceCreator.class.getSimpleName());
}
Expand Down
Loading

0 comments on commit a6d19e8

Please sign in to comment.