package com.taobao.tddl.rule.utils;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.lang.time.DateFormatUtils;
import com.taobao.tddl.common.utils.TStringUtil;
import com.taobao.tddl.rule.exceptions.TddlRuleException;
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;
/**
* 提供一种机制,允许业务自定义condition,通过该解析类转化为Rule锁需要的{@linkplain Comparative}对象
*
* <pre>
* 简单语法: KEY CMP VALUE [:TYPE]
* 1. KEY: 类似字段名字,用户随意定义
* 2. CMP: 链接符,比如< = > 等,具体可查看{@linkplain Comparative}
* 3. VALUE: 对应的值,比如1
* 4. TYPE: 描述VALUE的类型,可选型,如果不填默认为Long类型。支持: int/long/string/date,可以使用首字母做为缩写,比如i/l/s/d。
*
* 几个例子:
* 1. id = 1
* 2. id = 1 : long
* 3. id > 1 and id < 1 : long
* 4. gmt_create = 2011-11-11 : date
* 5. id in (1,2,3,4) : long
* </pre>
*
* @author jianghang 2013-11-6 下午5:23:02
* @since 5.0.0
*/
public class ComparativeStringAnalyser {
private static final String TYPE_SPLIT = ":";
private static final String[] DATE_FORMATS = new String[] { "yyyy-MM-dd", "HH:mm:ss", "yyyy-MM-dd HH:mm:ss",
"yyyy-MM-dd hh:mm:ss.S", "EEE MMM dd HH:mm:ss zzz yyyy", DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(),
DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(),
DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), };
public static Map<String, Comparative> decodeComparativeString2Map(String conditionStr) {
Map<String, Comparative> comparativeMap = new HashMap<String, Comparative>();
// 处理 ComparativeMap
String[] comStrs = conditionStr.split(";");
for (int i = 0; i < comStrs.length; i++) {
String value = comStrs[i].toUpperCase();
if (TStringUtil.isNotBlank(value)) {
boolean containsAnd = TStringUtil.contains(value, " AND ");
boolean containsOr = TStringUtil.contains(value, " OR ");
if (containsAnd || containsOr) {
ComparativeBaseList comparativeBaseList = null;
String op;
if (containsOr) {
comparativeBaseList = new ComparativeOR();
op = "OR";
} else if (containsAnd) {
comparativeBaseList = new ComparativeAND();
op = "AND";
} else {
throw new TddlRuleException("decodeComparative not support ComparativeBaseList value:" + value);
}
String[] compValues = TStringUtil.twoPartSplit(value, op);
String key = null;
for (String compValue : compValues) {
Comparative comparative = decodeComparative(compValue, null);
if (null != comparative) {
comparativeBaseList.addComparative(comparative);
}
String temp = decodeComparativeKey(compValue).trim();
if (null == key) {
key = temp;
} else if (!temp.equals(key)) {
throw new RuntimeException("decodeComparative not support ComparativeBaseList value:"
+ value);
}
}
comparativeMap.put(key, comparativeBaseList); // 必须大写
} else {
// 说明只是Comparative
String key = decodeComparativeKey(value);
Comparative comparative = decodeComparative(value, null);
if (null != comparative) {
comparativeMap.put(key, comparative); // 必须大写
}
}
}
}
return comparativeMap;
}
/**
* 解析类似: =1:int or in(1,2,3):long
*
* @param compValue
* @return
*/
public static Comparative decodeComparative(String compValue, String globalType) {
compValue = compValue.toUpperCase();
boolean containsIn = TStringUtil.contains(compValue, " IN");
Comparative comparative = null;
if (!containsIn) {
int compEnum = Comparative.getComparisonByCompleteString(compValue);
String splitor = Comparative.getComparisonName(compEnum);
int size = splitor.length();
int index = compValue.indexOf(splitor);
String valueTypeStr = TStringUtil.substring(compValue, index + size);
int lastColonIndex = valueTypeStr.lastIndexOf(TYPE_SPLIT);
if (lastColonIndex != -1) {
String value = valueTypeStr.substring(0, lastColonIndex);
String type = valueTypeStr.substring(lastColonIndex + 1);
comparative = decodeComparative(type, compEnum, value);
} else { // 如果不存在类型
comparative = decodeComparative(globalType, compEnum, valueTypeStr);
}
} else {
// 处理下in表达式
String[] compValues = TStringUtil.twoPartSplit(compValue, " IN");
int lastColonIndex = compValues[1].lastIndexOf(TYPE_SPLIT);
String inValues = compValues[1];
String type = null;
if (lastColonIndex != -1) {
inValues = compValues[1].substring(0, lastColonIndex);
type = compValues[1].substring(lastColonIndex + 1);
} else {
inValues = compValues[1];
type = globalType;
}
ComparativeOR comparativeBaseList = new ComparativeOR();
String[] values = TStringUtil.split(TStringUtil.getBetween(inValues, "(", ")"), ",");
for (String value : values) {
Comparative cmp = decodeComparative(type, Comparative.Equivalent, value);
comparativeBaseList.addComparative(cmp);
}
comparative = comparativeBaseList;
}
return comparative;
}
/**
* 根据类型解析下数据
*
* @param type
* @param compEnum
* @param value
* @return
*/
private static Comparative decodeComparative(String type, int compEnum, String value) {
if (value == null) {
throw new RuntimeException("decodeComparative Error notSupport Comparative valueType value: " + value
+ TYPE_SPLIT + type);
}
if (type == null) {
type = "l"; // 默认按照long来处理
}
Comparative comparative = null;
if ("i".equalsIgnoreCase(type.trim()) || "int".equalsIgnoreCase(type.trim())) {
comparative = new Comparative(compEnum, Integer.valueOf(value.trim()));
} else if ("l".equalsIgnoreCase(type.trim()) || "long".equalsIgnoreCase(type.trim())) {
comparative = new Comparative(compEnum, Long.valueOf(value.trim()));
} else if ("s".equalsIgnoreCase(type.trim()) || "string".equalsIgnoreCase(type.trim())) {
comparative = new Comparative(compEnum, value.trim());
} else if ("d".equalsIgnoreCase(type.trim()) || "date".equalsIgnoreCase(type.trim())) {
Date date = null;
try {
date = parseDate(value.trim(), DATE_FORMATS, Locale.ENGLISH);
} catch (Exception err) {
try {
date = parseDate(value.trim(), DATE_FORMATS, Locale.getDefault());
} catch (Exception e) {
throw new TddlRuleException("unSupport date parse :" + value.trim());
}
}
comparative = new Comparative(compEnum, date);
} else {
throw new TddlRuleException("decodeComparative Error notSupport Comparative valueType value: " + value
+ TYPE_SPLIT + type);
}
return comparative;
}
/**
* 获取对应的key,类似id=xx中的id信息
*/
public static String decodeComparativeKey(String compValue) {
boolean containsIn = TStringUtil.contains(compValue, " IN");
if (containsIn) {
String[] compValues = TStringUtil.twoPartSplit(compValue, " IN");
return compValues[0].trim();
} else {
int value = Comparative.getComparisonByCompleteString(compValue);
String splitor = Comparative.getComparisonName(value);
int index = compValue.indexOf(splitor);
return TStringUtil.substring(compValue, 0, index).trim();
}
}
private static Date parseDate(String str, String[] parsePatterns, Locale locale) throws ParseException {
if ((str == null) || (parsePatterns == null)) {
throw new IllegalArgumentException("Date and Patterns must not be null");
}
SimpleDateFormat parser = null;
ParsePosition pos = new ParsePosition(0);
for (int i = 0; i < parsePatterns.length; i++) {
if (i == 0) {
parser = new SimpleDateFormat(parsePatterns[0], locale);
} else {
parser.applyPattern(parsePatterns[i]);
}
pos.setIndex(0);
Date date = parser.parse(str, pos);
if ((date != null) && (pos.getIndex() == str.length())) {
return date;
}
}
throw new ParseException("Unable to parse the date: " + str, -1);
}
}