package org.dayatang.dsrouter.datasource;
import org.apache.commons.lang.StringUtils;
import org.dayatang.dsrouter.builder.DataSourceBuilder;
import org.dayatang.dsrouter.builder.mysql.C3P0MySQLDataSourceBuilder;
import org.dayatang.dsrouter.context.DataSourceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.HashMap;
import java.util.Map;
public class DynamicRoutingDataSource extends AbstractDataSource {
private static final Logger LOGGER = LoggerFactory.getLogger(DynamicRoutingDataSource.class);
private DataSourceContext dataSourceContext;
private DataSourceBuilder dataSourceBuilder;
private DataSource defaultDataSource;
private String defaultDataSourceKey;
private Map<String, DataSource> dataSourceMapping = new HashMap<String, DataSource>();
public DataSourceContext getDataSourceContext() {
return dataSourceContext;
}
public void setDataSourceContext(DataSourceContext dataSourceContext) {
this.dataSourceContext = dataSourceContext;
}
public DataSource getDefaultDataSource() {
return defaultDataSource;
}
public void setDefaultDataSource(DataSource defaultDataSource) {
this.defaultDataSource = defaultDataSource;
}
public DataSourceBuilder getDataSourceBuilder() {
if (dataSourceBuilder == null) {
info("没有指定dataSourceBuilder属性,采用默认的数据源构造器:{}", C3P0MySQLDataSourceBuilder.class.getName());
this.dataSourceBuilder = new C3P0MySQLDataSourceBuilder();
}
return dataSourceBuilder;
}
public void setDataSourceBuilder(DataSourceBuilder dataSourceBuilder) {
this.dataSourceBuilder = dataSourceBuilder;
}
public String getDefaultDataSourceKey() {
return defaultDataSourceKey;
}
public void setDefaultDataSourceKey(String defaultDataSourceKey) {
this.defaultDataSourceKey = defaultDataSourceKey;
}
public Map<String, DataSource> getDataSourceMapping() {
return dataSourceMapping;
}
public void setDataSourceMapping(Map<String, DataSource> dataSourceMapping) {
this.dataSourceMapping = dataSourceMapping;
}
// @Override
public void afterPropertiesSet() throws Exception {
if (defaultDataSource == null) {
return;
}
if (StringUtils.isNotBlank(defaultDataSourceKey)) {
dataSourceMapping.put(defaultDataSourceKey, defaultDataSource);
debug("设置默认数据源的key为:【{}】", defaultDataSourceKey);
return;
}
debug("设置默认数据源【{}】", defaultDataSource);
}
protected DataSource determineTargetDataSource() {
try {
DataSource ds = getDataSource();
return ds == null ? defaultDataSource : ds;
} catch (Exception ex) {
warn("获取数据源发生异常,使用默认数据源【{}】", defaultDataSource);
warn("异常为:" + ex);
return defaultDataSource;
}
}
protected DataSource getDataSource() {
String url = dataSourceContext.getUrl();
if (url == null) {
// throw new RuntimeException("数据库URL不能为空。");
return null;
}
DataSource dataSource = dataSourceMapping.get(url);
if (dataSource != null) {
debug("系统中已存在【{}】对应的数据源【{}】。", dataSourceContext.getUrl(), dataSource);
return dataSource;
}
debug("系统中不存在【{}】对应的数据源,需要重新构建。", dataSourceContext.getUrl());
dataSource = getDataSourceBuilder().buildDataSource(dataSourceContext.getUrl(), dataSourceContext.getUsername(),
dataSourceContext.getPassword(), dataSourceContext.getProperties());
dataSourceMapping.put(dataSourceContext.getUrl(), dataSource);
return dataSource;
}
public Connection getConnection() throws SQLException {
DataSource ds = (DataSource) determineTargetDataSource();
Connection connection = ds.getConnection();
// 注意:当使用c3p0的时候 不能在此处调用conn.getMetaData()方法 否则读写分离失效
// debug("获取的连接对象为【{}】", connection.getMetaData().getURL());
return buildCatalog(connection);
}
public Connection getConnection(String username, String password) throws SQLException {
Connection connection = determineTargetDataSource().getConnection(username, password);
return buildCatalog(connection);
}
protected Connection buildCatalog(Connection connection) throws SQLException {
if (connection == null) {
return null;
}
if (StringUtils.isNotBlank(dataSourceContext.getSchema())) {
debug("设置连接对象的catalog为【{}】。", dataSourceContext.getSchema());
connection.setCatalog(dataSourceContext.getSchema());
}
return connection;
}
private void debug(String message, Object... params) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(message, params);
}
}
private void info(String message, Object... params) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(message, params);
}
}
private void warn(String message, Object... params) {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn(message, params);
}
}
//For JDK 7 compatability
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}