public enum DatabaseType {

    H2, MySQL, Oracle, SQLServer, DB2;

    public static DatabaseType valueFrom(final String databaseName) {
        try {
            return DatabaseType.valueOf(databaseName);
        } catch (final IllegalArgumentException ex) {
            throw new DatabaseTypeUnsupportedException(databaseName);
        }
    }

} public class ShardingJdbcException extends RuntimeException {

    private static final long serialVersionUID = -1343739516839252250L;

    public ShardingJdbcException(final String errorMessage, final Object... args) {
        super(String.format(errorMessage, args));
    }

    public ShardingJdbcException(final Exception cause) {
        super(cause);
    }

} public class SqlParserException extends ShardingJdbcException {

    private static final long serialVersionUID = -1498980479829506655L;

    public SqlParserException(final String message, final Object... args) {
        super(String.format(message, args));
    }

} public class DefaultShardingAction implements ShardingAction {

    private ShardingRule shardingRule;

    private ConditionContext conditionContext;

    private Set<String> logicTables;

    private SqlAppender sqlAppender;

    private SqlStatementType sqlStatementType;

    public DefaultShardingAction(final ShardingRule shardingRule, final ConditionContext conditionContext, final Set<String> logicTables, final SqlAppender sqlAppender, final SqlStatementType sqlStatementType) {
        this.shardingRule = shardingRule;
        this.conditionContext = conditionContext;
        this.logicTables = logicTables;
        this.sqlAppender = sqlAppender;
        this.sqlStatementType = sqlStatementType;
    }

    @Override
    public Collection<SqlExecutionUnit> doSharding() {
        //分区的结果
        Set<SqlExecutionUnit> result = new HashSet<SqlExecutionUnit>();
        //组装分区值
        Collection<RouterCondition> conditions = conditionContext.getAllConditions();
        List<ShardingValue> shardingValues = new ArrayList<ShardingValue>(conditions.size());
        //判断该sql位于哪一个库,以及相关的表的替换
        for (RouterCondition condition : conditions) {
            //判断该表以及字段是否命中
            ShardingValue shardingValue = constructShardingValue(shardingRule, condition);
            if (shardingValue != null) {
                shardingValues.add(shardingValue);
            }
        }
        //算法计算出结果
        Algorithm algorithm = shardingRule.getAlgorithm();
        List<AlgorithmResult> algorithmResultList = new ArrayList<AlgorithmResult>(1);
        for (ShardingValue shardingValue : shardingValues) {
            algorithmResultList.add(algorithm.doAlgorithm(shardingValue));
        }
        for (AlgorithmResult algorithmResult : algorithmResultList) {
            SqlAppender newSqlAppender = sqlAppender.cloneBuilder();
            if(!algorithmResult.getLogicTable().equals(algorithmResult.getTargetTableName())) {
                newSqlAppender.buildSQL(algorithmResult.getLogicTable() , algorithmResult.getTargetTableName());
            }
            SqlExecutionUnit sqlExecutionUnit = new SqlExecutionUnit(algorithmResult.getTargetDataSource(), newSqlAppender);
            result.add(sqlExecutionUnit);
        }
        return result;
    }

    //======================================================================== private method start ========================================================================
    private ShardingValue constructShardingValue(ShardingRule shardingRule, RouterCondition condition) {
        //所有的表规则(表以及列)
        List<ShardingKey> shardingKeyList = shardingRule.getShardingKey();
        RouterColumn routerColumn = condition.getRouterColumn();
        String tableName = routerColumn.getTableName();
        String columnName = routerColumn.getColumnName();
        //是否命中相关的表 以及分区关键字
        boolean isHit = false;
        for (ShardingKey shardingKey : shardingKeyList) {
            if (shardingKey.getShardingColumn().equals(columnName) && shardingKey.getTableName().equals(tableName)) {
                isHit = true;
                break;
            }
        }
        if (!isHit) {
            return null;
        }
        List<Comparable<?>> conditionValues = condition.getValues();
        switch (condition.getOperator()) {
            case EQUAL:
            case IN:
                if (1 == conditionValues.size()) {
                    return new ShardingValue<Comparable<?>>(condition.getRouterColumn().getTableName(), condition.getRouterColumn().getColumnName(), conditionValues.get(0));
                }
                //TODO BETWEEN ? 暂时不处理 2016-09-30相关 第二版开发
            default:
                throw new UnsupportedOperationException(condition.getOperator().getExpression());
        }
    }
    //======================================================================== private method end ========================================================================


} public interface ShardingAction {

    Collection<SqlExecutionUnit> doSharding();

} public class SqlParserEngine {

    private SQLStatement sqlStatement;

    private List<Object> parameters;

    private SQLASTOutputVisitor visitor;

    public SqlParserEngine(SQLStatement sqlStatement, List<Object> parameters, SQLASTOutputVisitor visitor) {
        this.sqlStatement = sqlStatement;
        this.parameters = parameters;
        this.visitor = visitor;
    }

    public SqlParserResult parse() {
        //判断验证参数
        Preconditions.checkArgument(visitor instanceof SqlVisitor);

        SqlVisitor sqlVisitor = (SqlVisitor) visitor;
        SqlParserContext sqlParserContext = sqlVisitor.getSqlParserContext();
        //ast parser是将输入文本转换为ast（抽象语法树），parser有包括两个部分，Parser和Lexer，其中Lexer实现词法分析，Parser实现语法分析。
        //AST是Abstract Syntax Tree的缩写，也就是抽象语法树。AST是parser输出的结果。Visitor是遍历AST的手段，是处理AST最方便的模式，Visitor是一个接口，有缺省什么都没做的实现VistorAdapter
        visitor.setParameters(parameters);
        sqlStatement.accept(visitor);

        //将当前解析的条件对象归并入解析结果
        sqlParserContext.mergeCurrentConditionContext();

        //急躁 、易怒是我情绪上的弱点 ,加油 ~~~~~
        SqlParserResult sqlParserResult = sqlParserContext.getSqlParsedResult();
        sqlParserResult.getRouteContext().setSqlAppender(sqlVisitor.getSqlAppender());
        sqlParserResult.getRouteContext().setSqlStatementType(getType());

        return sqlParserResult;
    }

    private SqlStatementType getType() {
        if (sqlStatement instanceof SQLSelectStatement) {
            return SqlStatementType.SELECT;
        }
        if (sqlStatement instanceof SQLInsertStatement) {
            return SqlStatementType.INSERT;
        }
        if (sqlStatement instanceof SQLUpdateStatement) {
            return SqlStatementType.UPDATE;
        }
        if (sqlStatement instanceof SQLDeleteStatement) {
            return SqlStatementType.DELETE;
        }
        throw new SqlParserException("Unsupported SQL statement: [%s]", sqlStatement);
    }

} public final class SqlParserFactory {

    private final static Logger logger = LoggerFactory.getLogger(SqlParserFactory.class);

    public static SqlParserEngine createParserEngine(final DatabaseType databaseType, final String sql, final List<Object> parameters) throws SqlParserException {
        if (logger.isDebugEnabled()) {
            logger.debug("Logic SQL: {}", sql);
        }
        SQLStatementParser sqlStatementParser = getSQLStatementParser(databaseType, sql);
        SQLStatement sqlStatement = sqlStatementParser.parseStatement();
        if (logger.isDebugEnabled()) {
            logger.debug("Get {} SQL Statement", sqlStatement.getClass().getName());
        }
        SQLASTOutputVisitor sqlastOutputVisitor = getSQLVisitor(databaseType, sqlStatement);
        SqlParserEngine sqlParserEngine = new SqlParserEngine(sqlStatement, parameters, sqlastOutputVisitor);
        return sqlParserEngine;
    }

    private static SQLStatementParser getSQLStatementParser(final DatabaseType databaseType, final String sql) {
        switch (databaseType) {
            case H2:
            case MySQL:
                return new MySqlStatementParser(sql);
            case Oracle:
                return new OracleStatementParser(sql);
            case SQLServer:
                return new SQLServerStatementParser(sql);
            case DB2:
                return new DB2StatementParser(sql);
            default:
                throw new UnsupportedOperationException(String.format("Cannot support database type [%s]", databaseType));
        }
    }

    private static SQLASTOutputVisitor getSQLVisitor(final DatabaseType databaseType, final SQLStatement sqlStatement) {
        if (sqlStatement instanceof SQLSelectStatement) {
            return VisitorLogProxy.enhance(SqlVisitorRegistry.getSelectVistor(databaseType));
        }
        if (sqlStatement instanceof SQLInsertStatement) {
            return VisitorLogProxy.enhance(SqlVisitorRegistry.getInsertVistor(databaseType));
        }
        if (sqlStatement instanceof SQLUpdateStatement) {
            return VisitorLogProxy.enhance(SqlVisitorRegistry.getUpdateVistor(databaseType));
        }
        if (sqlStatement instanceof SQLDeleteStatement) {
            return VisitorLogProxy.enhance(SqlVisitorRegistry.getDeleteVistor(databaseType));
        }
        throw new SqlParserException("Unsupported SQL statement: [%s]", sqlStatement);
    }

} public class SqlParserResult {

    private final RouterContext routeContext = new RouterContext();

    private final List<ConditionContext> conditionContexts = new ArrayList<ConditionContext>();

    private final MergeContext mergeContext = new MergeContext();

    //===================================================================== get set method start ======================================================================

    public RouterContext getRouteContext() {
        return routeContext;
    }

    public List<ConditionContext> getConditionContexts() {
        return conditionContexts;
    }

    public MergeContext getMergeContext() {
        return mergeContext;
    }

    //===================================================================== get set method end ======================================================================

} public class MergeContext {

    // TODO: 2016/9/17 数据合并相关 后续开发

} public class ShardingRule {

    //默认mysql数据类型也可以配置
    private DatabaseType databaseType = DatabaseType.MySQL;

    private DataSourceContainer dataSourceContainer;

    private Algorithm algorithm;

    private List<ShardingKey> shardingKey;

    //======================================================================get  set method start ======================================================================
    public DatabaseType getDatabaseType() {
        return databaseType;
    }

    public void setDatabaseType(DatabaseType databaseType) {
        this.databaseType = databaseType;
    }

    public List<ShardingKey> getShardingKey() {
        return shardingKey;
    }

    public void setShardingKey(List<ShardingKey> shardingKey) {
        this.shardingKey = shardingKey;
    }

    public Algorithm getAlgorithm() {
        return algorithm;
    }

    public void setAlgorithm(Algorithm algorithm) {
        this.algorithm = algorithm;
    }

    public DataSourceContainer getDataSourceContainer() {
        return dataSourceContainer;
    }

    public void setDataSourceContainer(DataSourceContainer dataSourceContainer) {
        this.dataSourceContainer = dataSourceContainer;
    }

//======================================================================get  set method end =======================================================================

}
import com.elong.pb.newdda.client.constants.DatabaseType;
import com.elong.pb.newdda.client.exception.ShardingJdbcException;
import com.elong.pb.newdda.client.exception.SqlParserException;
import com.elong.pb.newdda.client.router.action.DefaultShardingAction;
import com.elong.pb.newdda.client.router.action.ShardingAction;
import com.elong.pb.newdda.client.router.parser.SqlParserEngine;
import com.elong.pb.newdda.client.router.parser.SqlParserFactory;
import com.elong.pb.newdda.client.router.parser.SqlParserResult;
import com.elong.pb.newdda.client.router.result.merge.MergeContext;
import com.elong.pb.newdda.client.router.result.router.*;
import com.elong.pb.newdda.client.router.rule.ShardingRule;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
package com.elong.pb.newdda.client.router;



/**
 * sql语句路由相关的内容
 * Created by zhangyong on 2016/7/27.
 */
public class SqlRouterEngine {

    private final static Logger logger = LoggerFactory.getLogger(SqlRouterEngine.class);

    private DatabaseType databaseType;

    private final ShardingRule shardingRule;

    public SqlRouterEngine(ShardingRule shardingRule) {
        this.shardingRule = shardingRule;
        this.databaseType = shardingRule.getDatabaseType();
    }

    public SqlRouterResult route(final String logicSql) throws SqlParserException {
        return route(logicSql, Collections.emptyList());
    }

    public SqlRouterResult route(final String logicSql, final List<Object> parameters) throws SqlParserException {
        SqlParserResult sqlParserResult = parserSql(logicSql, parameters);