package com.taobao.tddl.rule.enumerator;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import com.taobao.tddl.rule.enumerator.handler.CloseIntervalFieldsEnumeratorHandler;
import com.taobao.tddl.rule.enumerator.handler.DatePartDiscontinousRangeEnumerator;
import com.taobao.tddl.rule.enumerator.handler.DefaultEnumerator;
import com.taobao.tddl.rule.enumerator.handler.IntegerPartDiscontinousRangeEnumerator;
import com.taobao.tddl.rule.enumerator.handler.LongPartDiscontinousRangeEnumerator;
import com.taobao.tddl.rule.exceptions.TddlRuleException;
import com.taobao.tddl.rule.model.AdvancedParameter;
import com.taobao.tddl.rule.model.sqljep.Comparative;
import com.taobao.tddl.rule.model.sqljep.ComparativeAND;
import com.taobao.tddl.rule.model.sqljep.ComparativeBaseList;
import com.taobao.tddl.rule.model.sqljep.ComparativeOR;
/**
* 针对{@linkplain ComparativeBaseList},基于{@linkplain AdvancedParameter}实现区间范围的枚举<br/>
* 简单的{@linkplain Comparative}通过{@linkplain AdvancedParameter}
* 的enumerateRange方法已经能搞定
*
* @author jianghang 2013-10-29 下午5:57:27
* @since 5.0.0
*/
public class EnumeratorImp implements Enumerator {
private static final String DEFAULT_ENUMERATOR = "DEFAULT_ENUMERATOR";
protected static final Map<String, CloseIntervalFieldsEnumeratorHandler> enumeratorMap = new HashMap<String, CloseIntervalFieldsEnumeratorHandler>();
private boolean isDebug = false;
{
enumeratorMap.put(Integer.class.getName(), new IntegerPartDiscontinousRangeEnumerator());
enumeratorMap.put(Long.class.getName(), new LongPartDiscontinousRangeEnumerator());
enumeratorMap.put(BigDecimal.class.getName(), new LongPartDiscontinousRangeEnumerator());
enumeratorMap.put(Date.class.getName(), new DatePartDiscontinousRangeEnumerator());
enumeratorMap.put(java.sql.Date.class.getName(), new DatePartDiscontinousRangeEnumerator());
enumeratorMap.put(java.sql.Timestamp.class.getName(), new DatePartDiscontinousRangeEnumerator());
enumeratorMap.put(DEFAULT_ENUMERATOR, new DefaultEnumerator());
}
public Set<Object> getEnumeratedValue(Comparable condition, Integer cumulativeTimes, Comparable<?> atomIncrValue,
boolean needMergeValueInCloseInterval) {
Set<Object> retValue = null;
if (!isDebug) {
retValue = new HashSet<Object>();
} else {
retValue = new TreeSet<Object>();
}
try {
process(condition, retValue, cumulativeTimes, atomIncrValue, needMergeValueInCloseInterval);
} catch (EnumerationInterruptException e) {
processAllPassableFields(e.getComparative(),
retValue,
cumulativeTimes,
atomIncrValue,
needMergeValueInCloseInterval);
}
return retValue;
}
private void process(Comparable<?> condition, Set<Object> retValue, Integer cumulativeTimes,
Comparable<?> atomIncrValue, boolean needMergeValueInCloseInterval) {
if (condition == null) {
retValue.add(null);
} else if (condition instanceof ComparativeOR) {
processComparativeOR(condition, retValue, cumulativeTimes, atomIncrValue, needMergeValueInCloseInterval);
} else if (condition instanceof ComparativeAND) {
processComparativeAnd(condition, retValue, cumulativeTimes, atomIncrValue, needMergeValueInCloseInterval);
} else if (condition instanceof Comparative) {
processComparativeOne(condition, retValue, cumulativeTimes, atomIncrValue, needMergeValueInCloseInterval);
} else {
retValue.add(condition);
}
}
private void processComparativeOR(Comparable<?> condition, Set<Object> retValue, Integer cumulativeTimes,
Comparable<?> atomIncrValue, boolean needMergeValueInCloseInterval) {
List<Comparative> orList = ((ComparativeOR) condition).getList();
for (Comparative comp : orList) {
// 递归调用
process(comp, retValue, cumulativeTimes, atomIncrValue, needMergeValueInCloseInterval);
}
}
private void processComparativeAnd(Comparable<?> condition, Set<Object> retValue, Integer cumulativeTimes,
Comparable<?> atomIncrValue, boolean needMergeValueInCloseInterval) {
List<Comparative> andList = ((ComparativeAND) condition).getList();
// 多余两个感觉没什么实际的意义,碰到了再处理
if (andList.size() == 2) {
Comparable<?> arg1 = andList.get(0);
Comparable<?> arg2 = andList.get(1);
Comparative compArg1 = valid2varableInAndIsNotComparativeBaseList(arg1);
Comparative compArg2 = valid2varableInAndIsNotComparativeBaseList(arg2);
int compResult = 0;
try {
compArg1.setValue(EnumeratorUtils.toPrimaryValue(compArg1.getValue()));
compArg2.setValue(EnumeratorUtils.toPrimaryValue(compArg2.getValue()));
compResult = compArg1.getValue().compareTo(compArg2.getValue());
} catch (NullPointerException e) {
throw new IllegalArgumentException("and条件中有一个值为null", e);
}
if (compResult == 0) {
// 值相等,如果都含有=关系,那么还有个公共点,否则一个公共点都没有
if (containsEquvilentRelation(compArg1) && containsEquvilentRelation(compArg2)) {
retValue.add(compArg1.getValue());
}
} else if (compResult < 0) {
// arg1 < arg2
processTwoDifferentArgsInComparativeAnd(retValue,
compArg1,
compArg2,
cumulativeTimes,
atomIncrValue,
needMergeValueInCloseInterval);
} else {
// compResult>0
// arg1 > arg2
processTwoDifferentArgsInComparativeAnd(retValue,
compArg2,
compArg1,
cumulativeTimes,
atomIncrValue,
needMergeValueInCloseInterval);
}
} else {
throw new TddlRuleException("目前只支持一个and节点上有两个子节点");
}
}
private void processComparativeOne(Comparable<?> condition, Set<Object> retValue, Integer cumulativeTimes,
Comparable<?> atomIncrValue, boolean needMergeValueInCloseInterval) {
Comparative comp = (Comparative) condition;
int comparison = comp.getComparison();
switch (comparison) {
case 0:
// 为0 的时候表示纯粹的包装对象。
process(comp.getValue(), retValue, cumulativeTimes, atomIncrValue, needMergeValueInCloseInterval);
break;
case Comparative.Equivalent:
// 等于关系,直接放在collection
retValue.add(EnumeratorUtils.toPrimaryValue(comp.getValue()));
break;
case Comparative.GreaterThan:
case Comparative.GreaterThanOrEqual:
case Comparative.LessThan:
case Comparative.LessThanOrEqual:
// 各种需要全取的情况
throw new EnumerationInterruptException(comp);
default:
throw new TddlRuleException("not support yet");
}
}
/**
* 处理在一个and条件中的两个不同的argument
*
* @param samplingField
* @param from
* @param to
*/
private void processTwoDifferentArgsInComparativeAnd(Set<Object> retValue, Comparative from, Comparative to,
Integer cumulativeTimes, Comparable<?> atomIncrValue,
boolean needMergeValueInCloseInterval) {
if (isCloseInterval(from, to)) { // 处理 1 < x < 3的情况
mergeFeildOfDefinitionInCloseInterval(from,
to,
retValue,
cumulativeTimes,
atomIncrValue,
needMergeValueInCloseInterval);
} else { // 处理 1 < x = 3 or 1 = x <= 3
Comparable temp = compareAndGetIntersactionOneValue(from, to);
if (temp != null) {
retValue.add(temp);
} else {
// 闭区间已经处理过,x >= ? and x = ? 或者 x <= ? and x = ?有交的也处理过,纯粹的> 和
// <已经被转化为 >= 以及<=
// 这里主要处理三类情况 x <= 3 and x>=5 这类,
if (from.getComparison() == Comparative.LessThanOrEqual || from.getComparison() == Comparative.LessThan) {
if (to.getComparison() == Comparative.LessThanOrEqual || to.getComparison() == Comparative.LessThan) {
// 处理 x <= 3 and x <= 5
processAllPassableFields(from,
retValue,
cumulativeTimes,
atomIncrValue,
needMergeValueInCloseInterval);
} else {
// to为GreaterThanOrEqual,或者为Equals 那么是个开区间,无交集
// do nothing.
}
} else if (to.getComparison() == Comparative.GreaterThanOrEqual
|| to.getComparison() == Comparative.GreaterThan) {
if (from.getComparison() == Comparative.GreaterThanOrEqual
|| from.getComparison() == Comparative.GreaterThan) {
// 处理 x >= 3 and x >= 5
processAllPassableFields(to,
retValue,
cumulativeTimes,
atomIncrValue,
needMergeValueInCloseInterval);
} else {
// from为LessThanOrEqual,或者为Equals,为开区间,无交集
// do nothing.
}
} else {
throw new TddlRuleException("should not be here");
}
}
}
}
// ======================== 委托调用handler进行处理==========================
/**
* 函数的目标是返回全部可能的值,主要用于无限的定义域的处理,一般的说,对于部分连续部分不连续的函数曲线。
* 这个值应该是从任意一个值开始,按照原子自增值与倍数穷举出该函数的y的一个变化周期中x对应的变化周期的所有点即可。
*
* @param retValue
* @param cumulativeTimes
* @param atomIncrValue
*/
private void processAllPassableFields(Comparative source, Set<Object> retValue, Integer cumulativeTimes,
Comparable<?> atomIncrValue, boolean needMergeValueInCloseInterval) {
if (!needMergeValueInCloseInterval) {
throw new IllegalArgumentException("请打开规则的needMergeValueInCloseInterval选项,以支持分库分表条件中使用> < >= <=");
}
// 重构 现在这种架构下,id =? id in (?,?,?)都能走最短路径,但如果有多个 id > ? and id < ? or id>
// ? and id<? 则要从map中查多次。不过因为这种情况比较少,因此可以忽略
CloseIntervalFieldsEnumeratorHandler closeIntervalFieldsEnumeratorHandler = getCloseIntervalEnumeratorHandlerByComparative(source,
needMergeValueInCloseInterval);
closeIntervalFieldsEnumeratorHandler.processAllPassableFields(source, retValue, cumulativeTimes, atomIncrValue);
}
/**
* 穷举出从from到to中的所有值,根据自增value
*
* @param from
* @param to
*/
private void mergeFeildOfDefinitionInCloseInterval(Comparative from, Comparative to, Set<Object> retValue,
Integer cumulativeTimes, Comparable<?> atomIncrValue,
boolean needMergeValueInCloseInterval) {
if (!needMergeValueInCloseInterval) {
throw new IllegalArgumentException("请打开规则的needMergeValueInCloseInterval选项,以支持分库分表条件中使用> < >= <=");
}
// 重构 现在这种架构下,id =? id in (?,?,?)都能走最短路径
// 但如果有多个 id > ? and id < ? or id > ? and id<?
// 则要从map中查多次。不过因为这种情况比较少,因此可以忽略
CloseIntervalFieldsEnumeratorHandler closeIntervalFieldsEnumeratorHandler = getCloseIntervalEnumeratorHandlerByComparative(from,
needMergeValueInCloseInterval);
closeIntervalFieldsEnumeratorHandler.mergeFeildOfDefinitionInCloseInterval(from,
to,
retValue,
cumulativeTimes,
atomIncrValue);
}
/**
* 根据传入的参数决定使用哪类枚举器
*
* @param comp
* @param needMergeValueInCloseInterval
* @return
*/
private CloseIntervalFieldsEnumeratorHandler getCloseIntervalEnumeratorHandlerByComparative(Comparative comp,
boolean needMergeValueInCloseInterval) {
if (!needMergeValueInCloseInterval) {
return enumeratorMap.get(DEFAULT_ENUMERATOR);
}
if (comp == null) {
throw new IllegalArgumentException("不知道当前值是什么类型的,无法找到对应的枚举器" + comp);
}
Comparable value = comp.getValue();
if (value instanceof ComparativeBaseList) {
ComparativeBaseList comparativeBaseList = (ComparativeBaseList) value;
for (Comparative comparative : comparativeBaseList.getList()) {
return getCloseIntervalEnumeratorHandlerByComparative(comparative, needMergeValueInCloseInterval);
}
throw new TddlRuleException("should not be here");
} else if (value instanceof Comparative) {
return getCloseIntervalEnumeratorHandlerByComparative(comp, needMergeValueInCloseInterval);
} else {
// 表明是一个comparative对象
CloseIntervalFieldsEnumeratorHandler enumeratorHandler = enumeratorMap.get(value.getClass().getName());
if (enumeratorHandler != null) {
return enumeratorHandler;
} else {
return enumeratorMap.get(DEFAULT_ENUMERATOR);
}
}
}
// ======================== helper method ==================
private Comparative valid2varableInAndIsNotComparativeBaseList(Comparable<?> arg) {
if (arg instanceof ComparativeBaseList) {
throw new TddlRuleException("在一组and条件中只支持两个范围的值共同决定分表,不支持3个");
}
if (arg instanceof Comparative) {
Comparative comp = ((Comparative) arg);
int comparison = comp.getComparison();
if (comparison == 0) {
// 0的时候意味着这个非ComparativeBaseList的Comparative是个纯粹的包装对象。
return valid2varableInAndIsNotComparativeBaseList(comp.getValue());
} else {
// 其他就是有意义的值对象了
return comp;
}
} else {
// 否则就是基本对象,应该用等于包装
// return new Comparative(Comparative.Equivalent,arg);
throw new IllegalArgumentException("input value is not a comparative: " + arg);
}
}
private boolean containsEquvilentRelation(Comparative comp) {
int comparasion = comp.getComparison();
if (comparasion == Comparative.Equivalent || comparasion == Comparative.GreaterThanOrEqual
|| comparasion == Comparative.LessThanOrEqual) {
return true;
}
return false;
}
/**
* 是否属于一个区间
*/
private boolean isCloseInterval(Comparative from, Comparative to) {
int fromComparasion = from.getComparison();
int toComparasion = to.getComparison();
// 本来想简单通过数值比大小,但发现里面还有not in,like这类的标记,还是保守点写清楚
if ((fromComparasion == Comparative.GreaterThan || fromComparasion == Comparative.GreaterThanOrEqual)
&& (toComparasion == Comparative.LessThan || toComparasion == Comparative.LessThanOrEqual)) {
return true;
} else {
return false;
}
}
/**
* 处理一个and条件中 x > 1 and x = 3 类似这样的情况,因为前面已经对from 和 to 相等的情况作了处理
* 因此这里只需要处理不等的情况中的上述问题。 同时也处理了x = 1 and x = 2这种情况。以及x = 1 and x>2 和x < 1
* and x =2这种情况
*
* @param from
* @param to
* @return
*/
protected static Comparable compareAndGetIntersactionOneValue(Comparative from, Comparative to) {
// x = from and x <= to
if (from.getComparison() == Comparative.Equivalent) {
if (to.getComparison() == Comparative.LessThan || to.getComparison() == Comparative.LessThanOrEqual) {
return from.getValue();
}
}
// x <= from and x = to
if (to.getComparison() == Comparative.Equivalent) {
if (from.getComparison() == Comparative.GreaterThan
|| from.getComparison() == Comparative.GreaterThanOrEqual) {
return to.getValue();
}
}
return null;
}
public boolean isDebug() {
return isDebug;
}
public void setDebug(boolean isDebug) {
this.isDebug = isDebug;
}
}