package com.taobao.tddl.rule.impl;
import groovy.lang.GroovyClassLoader;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.codehaus.groovy.control.CompilationFailedException;
import com.taobao.tddl.rule.impl.groovy.ShardingFunction;
import com.taobao.tddl.common.utils.logger.Logger;
import com.taobao.tddl.common.utils.logger.LoggerFactory;
/**
* 基于groovy实现
*
* @author jianghang 2013-11-4 下午3:50:29
* @since 5.0.0
*/
public class GroovyRule<T> extends EnumerativeRule<T> {
private static final Logger logger = LoggerFactory.getLogger(GroovyRule.class);
// 应用置入的上下文,可以用在evel的groovy脚本里
private static final String IMPORT_EXTRA_PARAMETER_CONTEXT = "import com.taobao.tddl.rule.impl.groovy.ExtraParameterContext;";
private static final String IMPORT_STATIC_METHOD = "import static com.taobao.tddl.rule.impl.groovy.GroovyStaticMethod.*;";
private static final Pattern RETURN_WHOLE_WORD_PATTERN = Pattern.compile("\\breturn\\b",
Pattern.CASE_INSENSITIVE); // 全字匹配
private String extraPackagesStr;
private ShardingFunction shardingFunction;
public GroovyRule(String expression){
this(expression, null);
}
public GroovyRule(String expression, String extraPackagesStr){
super(expression);
if (extraPackagesStr == null) {
this.extraPackagesStr = "";
} else {
this.extraPackagesStr = extraPackagesStr;
}
initGroovy();
}
private void initGroovy() {
if (expression == null) {
throw new IllegalArgumentException("未指定 expression");
}
GroovyClassLoader loader = new GroovyClassLoader(GroovyRule.class.getClassLoader());
String groovyRule = getGroovyRule(expression, extraPackagesStr);
Class<?> c_groovy;
try {
c_groovy = loader.parseClass(groovyRule);
} catch (CompilationFailedException e) {
throw new IllegalArgumentException(groovyRule, e);
}
try {
// 新建类实例
Object ruleObj = c_groovy.newInstance();
if (ruleObj instanceof ShardingFunction) {
shardingFunction = (ShardingFunction) ruleObj;
} else {
throw new IllegalArgumentException("should not be here");
}
// 获取方法
} catch (Throwable t) {
throw new IllegalArgumentException("实例化规则对象失败", t);
}
}
protected static String getGroovyRule(String expression, String extraPackagesStr) {
StringBuffer sb = new StringBuffer();
sb.append(extraPackagesStr);
sb.append(IMPORT_STATIC_METHOD);
sb.append(IMPORT_EXTRA_PARAMETER_CONTEXT);
sb.append("public class RULE implements com.taobao.tddl.rule.impl.groovy.ShardingFunction").append("{");
sb.append("public Object eval(Map map, Object outerCtx) {");
Matcher returnMarcher = RETURN_WHOLE_WORD_PATTERN.matcher(expression);
if (!returnMarcher.find()) {
sb.append("return ");
sb.append(expression);
sb.append("+\"\";};}");
} else {
sb.append(expression);
sb.append(";};}");
}
if (logger.isDebugEnabled()) {
logger.debug(sb.toString());
}
return sb.toString();
}
/**
* 替换成(map.get("name"));以在运算时通过列名取得参数值(描点值)
*/
protected String replace(com.taobao.tddl.rule.Rule.RuleColumn ruleColumn) {
return new StringBuilder("(map.get(\"").append(ruleColumn.key).append("\"))").toString();
}
/**
* 调用groovy的方法:public Object eval(Map map,Map ctx){...}");
*/
public T eval(Map<String, Object> columnValues, Object outerCtx) {
try {
T value = (T) shardingFunction.eval(columnValues, outerCtx);
if (value == null) {
throw new IllegalArgumentException("rule eval resulte is null! rule:" + this.expression);
}
return value;
} catch (Throwable t) {
throw new IllegalArgumentException("调用方法失败: " + expression, t);
}
}
@Override
public String toString() {
return new StringBuilder("GroovyRule{expression=").append(expression)
.append(", parameters=")
.append(parameters)
.append("}")
.toString();
}
}