Commit 2a32723b authored by gaohongtao's avatar gaohongtao
Browse files

remove groovy script

parent 21a47afe
Loading
Loading
Loading
Loading
+112 −61
Original line number Diff line number Diff line
@@ -17,29 +17,38 @@

package com.dangdang.ddframe.rdb.sharding.config.common.api;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collections;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;

import com.dangdang.ddframe.rdb.sharding.api.rule.BindingTableRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.DataSourceRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.MultipleKeysShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.ShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.ShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.SingleKeyShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.NoneDatabaseShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.NoneTableShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.MultipleKeysDatabaseShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.SingleKeyDatabaseShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.MultipleKeysTableShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.config.common.api.config.BindingTableRuleConfig;
import com.dangdang.ddframe.rdb.sharding.config.common.api.config.ShardingRuleConfig;
import com.dangdang.ddframe.rdb.sharding.config.common.internal.AbstractShardingRuleConfigFileDelegate;
import com.google.common.base.Joiner;
import com.dangdang.ddframe.rdb.sharding.config.common.api.config.StrategyConfig;
import com.dangdang.ddframe.rdb.sharding.config.common.api.config.TableRuleConfig;
import com.dangdang.ddframe.rdb.sharding.config.common.internal.ConfigUtil;
import com.dangdang.ddframe.rdb.sharding.config.common.internal.algorithm.ClosureDatabaseShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.config.common.internal.algorithm.ClosureTableShardingAlgorithm;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import lombok.Getter;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.slf4j.LoggerFactory;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;

/**
 * 分片规则构建器.
@@ -48,21 +57,20 @@ import org.slf4j.LoggerFactory;
 */
public class ShardingRuleBuilder {
    
    private Map<String, DataSource> dataSourceMap;
    private Map<String, DataSource> externalDataSourceMap = new HashMap<>();
    
    @Getter
    private AbstractShardingRuleConfigFileDelegate ruleConfigDelegate;
    private ShardingRuleConfig config;
    
    private DataSourceRule dataSourceRule;
    private String logRoot;
    
    /**
     * 设置数据源映射.
     *
     * @param dataSourceMap 数据源映射
     * @param externalDataSourceMap 数据源映射
     * @return 构建器对象
     */
    public ShardingRuleBuilder setDataSourceMap(final Map<String, DataSource> dataSourceMap) {
        this.dataSourceMap = dataSourceMap;
    public ShardingRuleBuilder setExternalDataSourceMap(final Map<String, DataSource> externalDataSourceMap) {
        this.externalDataSourceMap.putAll(externalDataSourceMap);
        return this;
    }
    
@@ -84,55 +92,98 @@ public class ShardingRuleBuilder {
     * @return 构建器对象
     */
    public ShardingRuleBuilder parse(final String logRoot, final ShardingRuleConfig config) {
        if (null == dataSourceMap && null != config.getDataSource()) {
            dataSourceMap = config.getDataSource();
        }
        Binding binding = new Binding();
        binding.setProperty("shardingRuleConfig", config);
        GroovyShell shell = new GroovyShell(binding);
        URL templateUrl = this.getClass().getClassLoader().getResource("shardingJDBC_config_template.groovy");
        Preconditions.checkNotNull(templateUrl);
        Object result;
        try {
            result = shell.run(templateUrl.toURI(), new String[]{});
        } catch (final IOException | URISyntaxException ignored) {
            throw new UnsupportedOperationException("can not load template");
        }
        ruleConfigDelegate = (AbstractShardingRuleConfigFileDelegate) getShell(logRoot).parse(result.toString());
        initDelegate();
        this.config = config;
        this.logRoot = logRoot;
        return this;
    }
    
    private GroovyShell getShell(final String logRoot) {
        CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
        compilerConfiguration.setScriptBaseClass(AbstractShardingRuleConfigFileDelegate.class.getName());
        Binding binding = new Binding();
        binding.setVariable("log", LoggerFactory.getLogger(Joiner.on(".").join("com.dangdang.ddframe.rdb.sharding.configFile", logRoot)));
        return new GroovyShell(binding, compilerConfiguration);
    }
    
    private void initDelegate() {
        if (null != dataSourceMap) {
            dataSourceRule = new DataSourceRule(dataSourceMap);
            ruleConfigDelegate.setDataSourceRule(dataSourceRule);
        }
    }
    
    /**
     * 构建分片规则.
     * 
     * @return 分片规则对象
     */
    public ShardingRule build() {
        ruleConfigDelegate.run();
        Preconditions.checkNotNull(ruleConfigDelegate.getTableRules(), "Sharding JDBC: Config file must contains table config");
        DataSourceRule dataSourceRule = buildDataSourceRule();
        Collection<TableRule> tableRules = buildTableRule(dataSourceRule);
        return new ShardingRule(dataSourceRule, tableRules, buildBindingTableRule(tableRules),
                buildShardingStrategy(config.getDefaultDatabaseStrategy(), DatabaseShardingStrategy.class),
                buildShardingStrategy(config.getDefaultTableStrategy(), TableShardingStrategy.class));
    }
    
        return new ShardingRule(ruleConfigDelegate.getDataSourceRule(), ruleConfigDelegate.getTableRules(),
                null == ruleConfigDelegate.getBindingTableRules() ? Collections.<BindingTableRule>emptyList() : ruleConfigDelegate.getBindingTableRules(),
                null == ruleConfigDelegate.getDefaultDatabaseShardingStrategy() ? new DatabaseShardingStrategy(Collections.<String>emptyList(),
                        new NoneDatabaseShardingAlgorithm()) : ruleConfigDelegate.getDefaultDatabaseShardingStrategy(),
                null == ruleConfigDelegate.getDefaultTableShardingStrategy() ? new TableShardingStrategy(Collections.<String>emptyList(),
                        new NoneTableShardingAlgorithm()) : ruleConfigDelegate.getDefaultTableShardingStrategy());
    private DataSourceRule buildDataSourceRule() {
        Preconditions.checkArgument(config.getDataSource().size() > 0 || null != externalDataSourceMap && externalDataSourceMap.size() > 0, "Sharding JDBC: No data source config");
        return config.getDataSource().size() > 0 ? new DataSourceRule(config.getDataSource()) : new DataSourceRule(externalDataSourceMap);
    }
    
    private Collection<TableRule> buildTableRule(final DataSourceRule dataSourceRule) {
        Collection<TableRule> result = new ArrayList<>(config.getTables().size());
        for (Map.Entry<String, TableRuleConfig> each : config.getTables().entrySet()) {
            result.add(new TableRule(each.getKey(), ConfigUtil.transformCommaStringToList(each.getValue().getActualTables()), dataSourceRule,
                    buildShardingStrategy(each.getValue().getDatabaseStrategy(), DatabaseShardingStrategy.class),
                    buildShardingStrategy(each.getValue().getTableStrategy(), TableShardingStrategy.class)));
        }
        return result;
    }
    
    private Collection<BindingTableRule> buildBindingTableRule(final Collection<TableRule> tableRules) {
        Collection<BindingTableRule> result = new ArrayList<>(config.getBindingTables().size());
        for (BindingTableRuleConfig each : config.getBindingTables()) {
            result.add(new BindingTableRule(Lists.transform(ConfigUtil.transformCommaStringToList(each.getTableNames()), new Function<String, TableRule>() {
                @Override
                public TableRule apply(final String input) {
                    return findTableRuleByLogicTableName(tableRules, input);
                }
            })));
        }
        return result;
    }
    
    private TableRule findTableRuleByLogicTableName(final Collection<TableRule> tableRules, final String logicTableName) {
        for (TableRule each : tableRules) {
            if (logicTableName.equals(each.getLogicTable())) {
                return each;
            }
        }
        throw new IllegalArgumentException("Sharding JDBC: Binding table %s is not an available Table rule");
    }
    
    private <T extends ShardingStrategy> T buildShardingStrategy(final StrategyConfig config, final Class<T> returnClass) {
        if (null == config) {
            return null;
        }
        Preconditions.checkArgument(Strings.isNullOrEmpty(config.getAlgorithmExpression()) && !Strings.isNullOrEmpty(config.getAlgorithmClassName())
                || !Strings.isNullOrEmpty(config.getAlgorithmExpression()) && Strings.isNullOrEmpty(config.getAlgorithmClassName()));
        Preconditions.checkState(returnClass.isAssignableFrom(DatabaseShardingStrategy.class) || returnClass.isAssignableFrom(TableShardingStrategy.class), "Sharding-JDBC: returnClass is illegal");
        List<String> shardingColumns = ConfigUtil.transformCommaStringToList(config.getShardingColumns());
        if (!Strings.isNullOrEmpty(config.getAlgorithmClassName())) {
            return buildClassNameAlgorithmShardingStrategy(shardingColumns, config.getAlgorithmClassName(), returnClass);
        } else {
            return buildExpressionAlgorithmShardingStrategy(shardingColumns, config.getAlgorithmExpression(), returnClass);
        }
    }
    
    @SuppressWarnings("unchecked")
    private <T extends ShardingStrategy> T buildClassNameAlgorithmShardingStrategy(final List<String> shardingColumns, final String algorithmClassName, final Class<T> returnClass) {
        ShardingAlgorithm shardingAlgorithm;
        try {
            shardingAlgorithm = (ShardingAlgorithm) Class.forName(algorithmClassName).newInstance();
        } catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            throw new IllegalArgumentException(e);
        }
        Preconditions.checkState(shardingAlgorithm instanceof SingleKeyShardingAlgorithm || shardingAlgorithm instanceof MultipleKeysShardingAlgorithm, "Sharding-JDBC: algorithmClassName is illegal");
        if (shardingAlgorithm instanceof SingleKeyShardingAlgorithm) {
            Preconditions.checkArgument(shardingColumns.size() == 1, "Sharding-JDBC: SingleKeyShardingAlgorithm must match only ONE shading column");
            return returnClass.isAssignableFrom(DatabaseShardingStrategy.class) ? (T) new DatabaseShardingStrategy(shardingColumns.get(0), (SingleKeyDatabaseShardingAlgorithm<?>) shardingAlgorithm)
                    : (T) new TableShardingStrategy(shardingColumns.get(0), (SingleKeyTableShardingAlgorithm<?>) shardingAlgorithm);
        } else {
            return returnClass.isAssignableFrom(DatabaseShardingStrategy.class) ? (T) new DatabaseShardingStrategy(shardingColumns, (MultipleKeysDatabaseShardingAlgorithm) shardingAlgorithm)
                    : (T) new TableShardingStrategy(shardingColumns, (MultipleKeysTableShardingAlgorithm) shardingAlgorithm);
        }
    }
    
    @SuppressWarnings("unchecked")
    private <T extends ShardingStrategy> T buildExpressionAlgorithmShardingStrategy(final List<String> shardingColumns, final String algorithmExpression, final Class<T> returnClass) {
        return returnClass.isAssignableFrom(DatabaseShardingStrategy.class) ? (T) new DatabaseShardingStrategy(shardingColumns, new ClosureDatabaseShardingAlgorithm(algorithmExpression, logRoot))
                : (T) new TableShardingStrategy(shardingColumns, new ClosureTableShardingAlgorithm(algorithmExpression, logRoot));
    }
}
+0 −58
Original line number Diff line number Diff line
/**
 * 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.config.common.exception;

import com.dangdang.ddframe.rdb.sharding.config.common.internal.ConfigUtil;
import com.google.common.base.Strings;
import groovy.lang.MissingMethodException;
import lombok.RequiredArgsConstructor;
import org.codehaus.groovy.runtime.InvokerHelper;

/**
 * 缺失配置异常.
 * 
 * @author gaohongtao
 */
@RequiredArgsConstructor
public class MissingConfigNodeException extends RuntimeException {
    
    private final MissingMethodException mme;
    
    private final String suggestion;
    
    public String getMessage() {
        StringBuilder messageBuilder = new StringBuilder();
        if (Strings.isNullOrEmpty(suggestion)) {
            messageBuilder.append("Unsupported method: ").append(mme.getType().getName())
                    .append(".").append(mme.getMethod());
        } else {
            messageBuilder.append("No signature of method: ")
                    .append(mme.getType().getName())
                    .append(".")
                    .append(mme.getMethod())
                    .append("() is applicable for argument types: (")
                    .append(InvokerHelper.toTypeString(mme.getArguments()))
                    .append(") values: ")
                    .append(InvokerHelper.toArrayString(mme.getArguments(), 60, true))
                    .append(ConfigUtil.LINE_SEPARATOR)
                    .append("Standard syntax is ").append(mme.getMethod()).append("(").append(suggestion).append(")");
        }
        return messageBuilder.toString();
    }
    
}
+0 −165
Original line number Diff line number Diff line
/**
 * 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.config.common.internal;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;

import com.dangdang.ddframe.rdb.sharding.api.rule.BindingTableRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.DataSourceRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.ShardingStrategy;
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.config.common.exception.MissingConfigNodeException;
import com.dangdang.ddframe.rdb.sharding.config.common.internal.algorithm.ClosureDatabaseShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.config.common.internal.algorithm.ClosureTableShardingAlgorithm;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import groovy.lang.Closure;
import groovy.lang.MissingMethodException;
import groovy.lang.Script;
import lombok.Getter;
import lombok.Setter;

/**
 * 构建分片策略文件委派.
 * 
 * @author gaohongtao
 */
@Getter
public abstract class AbstractShardingRuleConfigFileDelegate extends Script {
    
    @Setter
    private DataSourceRule dataSourceRule;
    
    private DatabaseShardingStrategy defaultDatabaseShardingStrategy;
    
    private TableShardingStrategy defaultTableShardingStrategy;
    
    private List<TableRule> tableRules = new ArrayList<>();
    
    private List<BindingTableRule> bindingTableRules = new ArrayList<>();
    
    void datasource(final Map<String, DataSource> datasourceMap) {
        this.dataSourceRule = new DataSourceRule(datasourceMap);
    }
    
    DatabaseShardingStrategy databaseStrategy(final List<String> shardingColumns, final Closure<String> algorithm) {
        checkStrategyArgument(shardingColumns, algorithm);
        return new DatabaseShardingStrategy(shardingColumns, new ClosureDatabaseShardingAlgorithm(algorithm));
    }
    
    TableShardingStrategy tableStrategy(final List<String> shardingColumns, final Closure<String> algorithm) {
        checkStrategyArgument(shardingColumns, algorithm);
        return new TableShardingStrategy(shardingColumns, new ClosureTableShardingAlgorithm(algorithm));
    }
    
    private void checkStrategyArgument(final List<String> shardingColumns, final Closure<String> algorithm) {
        Preconditions.checkNotNull(shardingColumns);
        Preconditions.checkArgument(shardingColumns.size() > 0);
        Preconditions.checkNotNull(algorithm);
    }
    
    void defaultStrategy(final ShardingStrategy shardingStrategy) {
        if (shardingStrategy instanceof DatabaseShardingStrategy) {
            defaultDatabaseShardingStrategy = (DatabaseShardingStrategy) shardingStrategy;
        } else if (shardingStrategy instanceof TableShardingStrategy) {
            defaultTableShardingStrategy = (TableShardingStrategy) shardingStrategy;
        }
    }
    
    void table(final CharSequence logicTable, final List actualTables, final DatabaseShardingStrategy databaseShardingStrategy) {
        table(logicTable, actualTables, databaseShardingStrategy, null);
    }
    
    void table(final CharSequence logicTable, final List actualTables, final TableShardingStrategy tableShardingStrategy) {
        table(logicTable, actualTables, null, tableShardingStrategy);
    }
    
    void table(final CharSequence logicTable, final List actualTables) {
        table(logicTable.toString(), actualTables, null, null);
    }
    
    void table(final CharSequence logicTable, final List actualTables, final DatabaseShardingStrategy databaseShardingStrategy, final TableShardingStrategy tableShardingStrategy) {
        Preconditions.checkNotNull(logicTable);
        Preconditions.checkArgument(logicTable.length() > 0);
        Preconditions.checkNotNull(actualTables);
        Preconditions.checkArgument(actualTables.size() > 0);
        
        tableRules.add(new TableRule(logicTable.toString(), ConfigUtil.generateList(actualTables), dataSourceRule, databaseShardingStrategy, tableShardingStrategy));
    }
    
    void bind(final List tableNames) {
        bindingTableRules.add(new BindingTableRule(Lists.transform(ConfigUtil.generateList(tableNames), new Function<String, TableRule>() {
            @Override
            public TableRule apply(final String tableName) {
                for (TableRule each : tableRules) {
                    if (each.getLogicTable().equals(tableName)) {
                        return each;
                    }
                }
                throw new NullPointerException(String.format("can not find table rule with logic table name : %s", tableName));
            }
        })));
    }
    
    /**
     * 调用拦截器.
     *
     * @param name 方法名称
     * @param args 调用方法的参数
     * @return 调用返回值
     */
    @Override
    public Object invokeMethod(final String name, final Object args) {
        try {
            return super.invokeMethod(name, args);
        } catch (final MissingMethodException mme) {
            throw new MissingConfigNodeException(mme, getMissingConfigSuggestion(name));
        }
    }
    
    private String getMissingConfigSuggestion(final String methodName) {
        switch (methodName) {
            case "table":
                return "String logicTable, List actualTables, (Optional)DatabaseShardingStrategy databaseShardingStrategy, (Optional)TableShardingStrategy tableShardingStrategy";
            case "databaseStrategy":
                return "List shardingColumns, {}";
            case "tableStrategy":
                return "List shardingColumns, {}";
            case "defaultStrategy":
                return "databaseStrategy or tableStrategy";
            case "bind":
                return "List tableNames";
            default:
                return "";
        }
    }
    
    /**
     * 该方法将被脚本实现.
     *
     * @return 脚本返回的结果
     */
    @Override
    public abstract Object run();
}
+84 −58

File changed.

Preview size limit exceeded, changes collapsed.

+2 −3
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@
package com.dangdang.ddframe.rdb.sharding.config.common.internal.algorithm;

import com.dangdang.ddframe.rdb.sharding.api.strategy.database.MultipleKeysDatabaseShardingAlgorithm;
import groovy.lang.Closure;

/**
 * 分库闭包算法.
@@ -27,7 +26,7 @@ import groovy.lang.Closure;
 */
public class ClosureDatabaseShardingAlgorithm extends ClosureShardingAlgorithm implements MultipleKeysDatabaseShardingAlgorithm {
    
    public ClosureDatabaseShardingAlgorithm(final Closure<String> closure) {
        super(closure);
    public ClosureDatabaseShardingAlgorithm(final String scriptText, final String logRoot) {
        super(scriptText, logRoot);
    }
}
Loading