package org.dayatang.datasource4saas.dscreator;
import org.apache.commons.beanutils.BeanUtils;
import org.dayatang.configuration.Configuration;
import org.dayatang.configuration.ConfigurationFactory;
import org.dayatang.datasource4saas.Constants;
import org.dayatang.datasource4saas.dsregistry.DataSourceCreator;
import javax.sql.DataSource;
import java.lang.reflect.InvocationTargetException;
import java.util.Map.Entry;
import java.util.Properties;
/**
* 抽象数据源创建器实现
* @author yyang (<a href="mailto:gdyangyu@gmail.com">gdyangyu@gmail.com</a>)
*
*/
public abstract class AbstractDataSourceCreator implements DataSourceCreator {
private Configuration dsConfiguration; //数据源配置
private Configuration tenantDbMapping; //租户到数据库链接参数的映射
private DbType dbType;
private TenantDbMappingStrategy mappingStrategy;
/**
* 获取数据源配置
* @return
*/
private Configuration getDsConfiguration() {
if (dsConfiguration == null) {
dsConfiguration = new ConfigurationFactory().fromClasspath(Constants.DB_CONF_FILE);
}
return dsConfiguration;
}
/**
* 设置数据源配置
* @param dsConfiguration
*/
public void setDsConfiguration(Configuration dsConfiguration) {
this.dsConfiguration = dsConfiguration;
}
private Configuration getTenantDbMapping() {
if (tenantDbMapping == null) {
tenantDbMapping = new ConfigurationFactory().fromClasspath(Constants.DB_MAPPING_FILE);
}
return tenantDbMapping;
}
/**
* 设置租户数据源映射
* @param tenantDbMapping
*/
public void setTenantDbMapping(Configuration tenantDbMapping) {
this.tenantDbMapping = tenantDbMapping;
}
private TenantDbMappingStrategy getMappingStrategy() {
if (mappingStrategy == null) {
mappingStrategy = TenantDbMappingStrategy.of(getDsConfiguration().getString(Constants.TENANT_MAPPING_STRATEGY));
}
return mappingStrategy;
}
public void setMappingStrategy(TenantDbMappingStrategy mappingStrategy) {
this.mappingStrategy = mappingStrategy;
}
private DbType getDbType() {
if (dbType == null) {
dbType = DbType.of(getDsConfiguration().getString(Constants.DB_TYPE));
}
return dbType;
}
public void setDbType(DbType dbType) {
this.dbType = dbType;
}
@Override
public DataSource createDataSourceForTenant(String tenant) {
DataSource result = createDataSource();
fillProperties(result);
DbInfo dbInfo = getDbInfo(tenant);
setProperty(result, getDriverClassPropName(), getDbType().getDriverClassName());
setProperty(result, getUrlPropName(), getDbType().getUrl(dbInfo));
setProperty(result, getUsernamePropName(), dbInfo.getUsername());
setProperty(result, getPasswordPropName(), dbInfo.getPassword());
return result;
}
private DbInfo getDbInfo(String tenant) {
DbInfo dbInfo = new DbInfo(getDsConfiguration());
getMappingStrategy().process(dbInfo, tenant, getTenantDbMapping());
return dbInfo;
}
protected abstract DataSource createDataSource();
protected abstract String getDriverClassPropName();
protected abstract String getUrlPropName();
protected abstract String getUsernamePropName();
protected abstract String getPasswordPropName();
/**
* 填充数据库连接池特定的数据源配置。
* @param dataSource
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private void fillProperties(DataSource dataSource) {
Properties dsProperties = getDsConfiguration().getProperties();
for (Entry<Object, Object> entry : dsProperties.entrySet()) {
setProperty(dataSource, entry.getKey().toString(), entry.getValue());
}
}
private void setProperty(Object obj, String propName, Object propValue) {
try {
BeanUtils.setProperty(obj, propName, propValue);
} catch (IllegalAccessException e) {
throw new DataSourceCreationException("Datasource property setting failed", e);
} catch (InvocationTargetException e) {
throw new DataSourceCreationException("Datasource property setting failed", e);
}
}
}