/*
* Copyright 1999-2015 dangdang.com.
* <p>
* 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
*
* http://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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.rule;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.id.generator.IdGenerator;
import com.google.common.base.Preconditions;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
/**
* 表规则配置对象.
*
* @author zhangliang
*/
@Getter
@ToString
public final class TableRule {
private final String logicTable;
private final boolean dynamic;
private final List<DataNode> actualTables;
private final DatabaseShardingStrategy databaseShardingStrategy;
private final TableShardingStrategy tableShardingStrategy;
@Getter(AccessLevel.PACKAGE)
private final Map<String, IdGenerator> autoIncrementColumnMap = new LinkedHashMap<>();
/**
* 全属性构造器.
*
* <p>用于Spring非命名空间的配置.</p>
*
* <p>未来将改为private权限, 不在对外公开, 不建议使用非Spring命名空间的配置.</p>
*
* @deprecated 未来将改为private权限, 不在对外公开, 不建议使用非Spring命名空间的配置.
*/
@Deprecated
public TableRule(final String logicTable, final boolean dynamic, final List<String> actualTables, final DataSourceRule dataSourceRule, final Collection<String> dataSourceNames,
final DatabaseShardingStrategy databaseShardingStrategy, final TableShardingStrategy tableShardingStrategy) {
Preconditions.checkNotNull(logicTable);
this.logicTable = logicTable;
this.dynamic = dynamic;
this.databaseShardingStrategy = databaseShardingStrategy;
this.tableShardingStrategy = tableShardingStrategy;
if (dynamic) {
Preconditions.checkNotNull(dataSourceRule);
this.actualTables = generateDataNodes(dataSourceRule);
} else if (null == actualTables || actualTables.isEmpty()) {
Preconditions.checkNotNull(dataSourceRule);
this.actualTables = generateDataNodes(Collections.singletonList(logicTable), dataSourceRule, dataSourceNames);
} else {
this.actualTables = generateDataNodes(actualTables, dataSourceRule, dataSourceNames);
}
}
/**
* 获取表规则配置对象构建器.
*
* @param logicTable 逻辑表名称
* @return 表规则配置对象构建器
*/
public static TableRuleBuilder builder(final String logicTable) {
return new TableRuleBuilder(logicTable);
}
private List<DataNode> generateDataNodes(final DataSourceRule dataSourceRule) {
Collection<String> dataSourceNames = dataSourceRule.getDataSourceNames();
List<DataNode> result = new ArrayList<>(dataSourceNames.size());
for (String each : dataSourceNames) {
result.add(new DynamicDataNode(each));
}
return result;
}
private List<DataNode> generateDataNodes(final List<String> actualTables, final DataSourceRule dataSourceRule, final Collection<String> actualDataSourceNames) {
Collection<String> dataSourceNames = getDataSourceNames(dataSourceRule, actualDataSourceNames);
List<DataNode> result = new ArrayList<>(actualTables.size() * (dataSourceNames.isEmpty() ? 1 : dataSourceNames.size()));
for (String actualTable : actualTables) {
if (DataNode.isValidDataNode(actualTable)) {
result.add(new DataNode(actualTable));
} else {
for (String dataSourceName : dataSourceNames) {
result.add(new DataNode(dataSourceName, actualTable));
}
}
}
return result;
}
private Collection<String> getDataSourceNames(final DataSourceRule dataSourceRule, final Collection<String> actualDataSourceNames) {
if (null == dataSourceRule) {
return Collections.emptyList();
}
if (null == actualDataSourceNames || actualDataSourceNames.isEmpty()) {
return dataSourceRule.getDataSourceNames();
}
return actualDataSourceNames;
}
/**
* 根据数据源名称过滤获取真实数据单元.
*
* @param targetDataSources 数据源名称集合
* @param targetTables 真实表名称集合
* @return 真实数据单元
*/
public Collection<DataNode> getActualDataNodes(final Collection<String> targetDataSources, final Collection<String> targetTables) {
return dynamic ? getDynamicDataNodes(targetDataSources, targetTables) : getStaticDataNodes(targetDataSources, targetTables);
}
private Collection<DataNode> getDynamicDataNodes(final Collection<String> targetDataSources, final Collection<String> targetTables) {
Collection<DataNode> result = new LinkedHashSet<>(targetDataSources.size() * targetTables.size());
for (String targetDataSource : targetDataSources) {
for (String targetTable : targetTables) {
result.add(new DataNode(targetDataSource, targetTable));
}
}
return result;
}
private Collection<DataNode> getStaticDataNodes(final Collection<String> targetDataSources, final Collection<String> targetTables) {
Collection<DataNode> result = new LinkedHashSet<>(actualTables.size());
for (DataNode each : actualTables) {
if (targetDataSources.contains(each.getDataSourceName()) && targetTables.contains(each.getTableName())) {
result.add(each);
}
}
return result;
}
/**
* 获取真实数据源.
*
* @return 真实表名称
*/
public Collection<String> getActualDatasourceNames() {
Collection<String> result = new LinkedHashSet<>(actualTables.size());
for (DataNode each : actualTables) {
result.add(each.getDataSourceName());
}
return result;
}
/**
* 根据数据源名称过滤获取真实表名称.
*
* @param targetDataSources 数据源名称
* @return 真实表名称
*/
public Collection<String> getActualTableNames(final Collection<String> targetDataSources) {
Collection<String> result = new LinkedHashSet<>(actualTables.size());
for (DataNode each : actualTables) {
if (targetDataSources.contains(each.getDataSourceName())) {
result.add(each.getTableName());
}
}
return result;
}
int findActualTableIndex(final String dataSourceName, final String actualTableName) {
int result = 0;
for (DataNode each : actualTables) {
if (each.getDataSourceName().equals(dataSourceName) && each.getTableName().equals(actualTableName)) {
return result;
}
result++;
}
return -1;
}
void fillIdGenerator(final Class<? extends IdGenerator> idGeneratorClass) {
for (Map.Entry<String, IdGenerator> each : autoIncrementColumnMap.entrySet()) {
if (null == each.getValue()) {
IdGenerator idGenerator = TableRuleBuilder.instanceIdGenerator(idGeneratorClass);
each.setValue(idGenerator);
}
}
}
/**
* 生成Id.
*
* @param columnName 列名称
* @return 生成的id
*/
public Object generateId(final String columnName) {
Number result = autoIncrementColumnMap.get(columnName).generateId();
Preconditions.checkNotNull(result);
return result;
}
/**
* 表规则配置对象构建器.
*/
@RequiredArgsConstructor
public static class TableRuleBuilder {
private final String logicTable;
private boolean dynamic;
private List<String> actualTables;
private DataSourceRule dataSourceRule;
private Collection<String> dataSourceNames;
private DatabaseShardingStrategy databaseShardingStrategy;
private TableShardingStrategy tableShardingStrategy;
private final Map<String, IdGenerator> autoIncrementColumnMap = new LinkedHashMap<>();
private Class<? extends IdGenerator> tableIdGeneratorClass;
static IdGenerator instanceIdGenerator(final Class<? extends IdGenerator> idGeneratorClass) {
Preconditions.checkNotNull(idGeneratorClass);
try {
return idGeneratorClass.newInstance();
} catch (final InstantiationException | IllegalAccessException e) {
throw new IllegalArgumentException(String.format("Class %s should have public privilege and no argument constructor", idGeneratorClass.getName()));
}
}
/**
* 构建是否为动态表.
*
* @param dynamic 是否为动态表
* @return 真实表集合
*/
public TableRuleBuilder dynamic(final boolean dynamic) {
this.dynamic = dynamic;
return this;
}
/**
* 构建真实表集合.
*
* @param actualTables 真实表集合
* @return 真实表集合
*/
public TableRuleBuilder actualTables(final List<String> actualTables) {
this.actualTables = actualTables;
return this;
}
/**
* 构建数据源分片规则.
*
* @param dataSourceRule 数据源分片规则
* @return 规则配置对象构建器
*/
public TableRuleBuilder dataSourceRule(final DataSourceRule dataSourceRule) {
this.dataSourceRule = dataSourceRule;
return this;
}
/**
* 构建数据源分片规则.
*
* @param dataSourceNames 数据源名称集合
* @return 规则配置对象构建器
*/
public TableRuleBuilder dataSourceNames(final Collection<String> dataSourceNames) {
this.dataSourceNames = dataSourceNames;
return this;
}
/**
* 构建数据库分片策略.
*
* @param databaseShardingStrategy 数据库分片策略
* @return 规则配置对象构建器
*/
public TableRuleBuilder databaseShardingStrategy(final DatabaseShardingStrategy databaseShardingStrategy) {
this.databaseShardingStrategy = databaseShardingStrategy;
return this;
}
/**
* 构建表分片策略.
*
* @param tableShardingStrategy 表分片策略
* @return 规则配置对象构建器
*/
public TableRuleBuilder tableShardingStrategy(final TableShardingStrategy tableShardingStrategy) {
this.tableShardingStrategy = tableShardingStrategy;
return this;
}
/**
* 自增列.
*
* @param autoIncrementColumn 自增列名称
* @return 规则配置对象构建器
*/
public TableRuleBuilder autoIncrementColumns(final String autoIncrementColumn) {
this.autoIncrementColumnMap.put(autoIncrementColumn, null);
return this;
}
/**
* 自增列.
*
* @param autoIncrementColumn 自增列名称
* @param columnIdGeneratorClass 列Id生成器的类
* @return 规则配置对象构建器
*/
public TableRuleBuilder autoIncrementColumns(final String autoIncrementColumn, final Class<? extends IdGenerator> columnIdGeneratorClass) {
this.autoIncrementColumnMap.put(autoIncrementColumn, instanceIdGenerator(columnIdGeneratorClass));
return this;
}
/**
* 整个表的Id生成器.
*
* @param tableIdGeneratorClass Id生成器
* @return 规则配置对象构建器
*/
public TableRuleBuilder tableIdGenerator(final Class<? extends IdGenerator> tableIdGeneratorClass) {
this.tableIdGeneratorClass = tableIdGeneratorClass;
return this;
}
/**
* 构建表规则配置对象.
*
* @return 表规则配置对象
*/
public TableRule build() {
TableRule result = new TableRule(logicTable, dynamic, actualTables, dataSourceRule, dataSourceNames, databaseShardingStrategy, tableShardingStrategy);
result.autoIncrementColumnMap.putAll(autoIncrementColumnMap);
if (null == tableIdGeneratorClass) {
return result;
}
result.fillIdGenerator(tableIdGeneratorClass);
return result;
}
}
}