package org.springframework.cloud.service.relational;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.springframework.cloud.CloudException;
import org.springframework.cloud.service.AbstractServiceConnectorCreator;
import org.springframework.cloud.service.ServiceConnectorConfig;
import org.springframework.cloud.service.ServiceConnectorCreationException;
import org.springframework.cloud.service.common.RelationalServiceInfo;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
/**
*
* @author Ramnivas Laddad
*
* @param <SI> the {@link RelationalServiceInfo} for the backing database service
*/
public abstract class DataSourceCreator<SI extends RelationalServiceInfo> extends AbstractServiceConnectorCreator<DataSource, SI> {
protected static Logger logger = Logger.getLogger(DataSourceCreator.class.getName());
private String driverSystemPropKey;
private String[] driverClasses;
private String validationQuery;
private Map<String, PooledDataSourceCreator<SI>> pooledDataSourceCreators =
new LinkedHashMap<String, PooledDataSourceCreator<SI>>();
public DataSourceCreator(String driverSystemPropKey, String[] driverClasses, String validationQuery) {
this.driverSystemPropKey = driverSystemPropKey;
this.driverClasses = driverClasses;
this.validationQuery = validationQuery;
if (pooledDataSourceCreators.size() == 0) {
putPooledDataSourceCreator(new TomcatJdbcPooledDataSourceCreator<SI>());
putPooledDataSourceCreator(new HikariCpPooledDataSourceCreator<SI>());
putPooledDataSourceCreator(new TomcatDbcpPooledDataSourceCreator<SI>());
putPooledDataSourceCreator(new BasicDbcpPooledDataSourceCreator<SI>());
}
}
private void putPooledDataSourceCreator(PooledDataSourceCreator<SI> pooledDataSourceCreator) {
pooledDataSourceCreators.put(pooledDataSourceCreator.getClass().getSimpleName(), pooledDataSourceCreator);
}
@Override
public DataSource create(SI serviceInfo, ServiceConnectorConfig serviceConnectorConfig) {
try {
DataSource ds = createPooledDataSource(serviceInfo, serviceConnectorConfig);
if (ds != null) {
return ds;
}
// Only for testing outside Tomcat/CloudFoundry
logger.warning("No connection pooling DataSource implementation found on the classpath - no pooling is in effect.");
return new SimpleDriverDataSource(DriverManager.getDriver(serviceInfo.getJdbcUrl()), serviceInfo.getJdbcUrl());
} catch (Exception e) {
throw new ServiceConnectorCreationException(
"Failed to created cloud datasource for " + serviceInfo.getId() + " service", e);
}
}
private DataSource createPooledDataSource(SI serviceInfo, ServiceConnectorConfig serviceConnectorConfig) {
Collection<PooledDataSourceCreator<SI>> delegates = filterPooledDataSourceCreators(serviceConnectorConfig);
for (PooledDataSourceCreator<SI> delegate : delegates) {
DataSource ds = delegate.create(serviceInfo, serviceConnectorConfig, getDriverClassName(serviceInfo), validationQuery);
if (ds != null) {
return ds;
}
}
return null;
}
private Collection<PooledDataSourceCreator<SI>> filterPooledDataSourceCreators(ServiceConnectorConfig serviceConnectorConfig) {
if (serviceConnectorConfig != null) {
List<String> pooledDataSourceNames = ((DataSourceConfig) serviceConnectorConfig).getPooledDataSourceNames();
if (pooledDataSourceNames != null) {
List<PooledDataSourceCreator<SI>> filtered = new ArrayList<PooledDataSourceCreator<SI>>();
for (String name : pooledDataSourceNames) {
for (String key : pooledDataSourceCreators.keySet()) {
if (key.contains(name)) {
filtered.add(pooledDataSourceCreators.get(key));
}
}
}
return filtered;
}
}
return pooledDataSourceCreators.values();
}
public String getDriverClassName(SI serviceInfo) {
String userSpecifiedDriver = System.getProperty(driverSystemPropKey);
if (userSpecifiedDriver != null && !userSpecifiedDriver.isEmpty()) {
return userSpecifiedDriver;
} else {
for (String driver : driverClasses) {
try {
Class.forName(driver);
return driver;
} catch (ClassNotFoundException ex) {
// continue...
}
}
}
throw new CloudException("No suitable database driver found for " + serviceInfo.getId() + " service ");
}
}