package com.taobao.top.analysis.statistics.data.impl; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.taobao.top.analysis.exception.AnalysisException; import com.taobao.top.analysis.statistics.data.Alias; import com.taobao.top.analysis.statistics.data.ICalculator; import com.taobao.top.analysis.statistics.data.ObjectColumn; import com.taobao.top.analysis.util.AnalysisConstants; import com.taobao.top.analysis.util.ReportUtil; public class SimpleCalculator implements ICalculator { /** * */ private static final long serialVersionUID = 8024981401877328739L; /** * value表达式中的变量列表 */ private List<Object> bindingStack; /** * value表达式中的操作列表 */ private List<Byte> operatorStack; private final String value; /** * 关联使用的entry */ private Set<String> referEntries; /** * @return the referEntries */ public Set<String> getReferEntries() { return referEntries; } public String getValue() { return value; } public List<Object> getBindingStack() { return bindingStack; } public List<Byte> getOperatorStack() { return operatorStack; } public void init(Map<String, Alias> aliasPool) throws AnalysisException{ //从这里init的代码可以看出,分析器的配置解析规则,并非是全部读取后,然后进行一次性解析的,它的report配置是有固定顺序的 //一旦顺序出错,则会引起出错,同时alias和entry已经#的常量,三者是不可以重名的,否则会出错,这些潜规则都是在代码里反应出的 //后续可以对这些进行改造,毕竟这并非是一个友好而完善的解析方式 if (value != null && !"".equals(value) && (value.indexOf("$") >= 0 || value .indexOf("entry(") >= 0)) { bindingStack = new ArrayList<Object>(); operatorStack = new ArrayList<Byte>(); referEntries = new HashSet<String>(); String c = value; String temp; while (c.indexOf("$") >= 0 || c.indexOf("#") >= 0) { if (c.indexOf("$") >= 0) { if (c.indexOf("#") < 0 || (c.indexOf("#") >= 0 && c.indexOf("$") < c .indexOf("#"))) { c = c.substring(c.indexOf("$") + 1); temp = c.substring(0, c.indexOf("$")); c = c.substring(c.indexOf("$") + 1); if (aliasPool != null && aliasPool.size() > 0 && aliasPool.get(temp) != null) { bindingStack.add(aliasPool.get(temp).getKey()); } else if (aliasPool != null && aliasPool.size() > 0 && temp.indexOf(".") > 0 && aliasPool.get(temp.substring(0, temp.indexOf("."))) != null) { bindingStack.add(new ObjectColumn(aliasPool.get(temp.substring(0, temp.indexOf("."))).getKey(), temp.substring(temp.indexOf(".")+1))); } else bindingStack.add(Integer.valueOf(temp)); continue; } } if (c.indexOf("#") >= 0) { if (c.indexOf("$") < 0 || (c.indexOf("$") >= 0 && c.indexOf("$") > c .indexOf("#"))) { c = c.substring(c.indexOf("#") + 1); temp = c.substring(0, c.indexOf("#")); c = c.substring(c.indexOf("#") + 1); bindingStack.add("#" + temp); continue; } } } while (c.indexOf("entry(") >= 0) { c = c.substring(c.indexOf("entry(") + "entry(".length()); temp = c.substring(0, c.indexOf(")")); c = c.substring(c.indexOf(")") + 1); bindingStack.add(temp); referEntries.add(temp); } char[] cs = value.toCharArray(); for (char _ch : cs) { if (_ch == '+' || _ch == '-' || _ch == '*' || _ch == '/') operatorStack.add(ReportUtil.generateOperationFlag(_ch)); } } } public SimpleCalculator(String valueExpression, Map<String, Alias> aliasPool) throws AnalysisException { this.value = valueExpression; init(aliasPool); } @Override public Object calculator(Object[] contents) { Object result = null; double left = 0; if (bindingStack != null && bindingStack.size() > 0) { if (bindingStack.size() > 1) { if (bindingStack.get(0) instanceof String && ((String)bindingStack.get(0)).startsWith("#")) left = Double.valueOf(((String)bindingStack.get(0)).substring(1)); else if (bindingStack.get(0) instanceof ObjectColumn) { if (((ObjectColumn)bindingStack.get(0)).getcIndex() - 1 >= contents.length) return result; Object o = contents[((ObjectColumn)bindingStack.get(0)).getcIndex() - 1]; o = ReportUtil.getValueFromJosnObj(o.toString(),((ObjectColumn)bindingStack.get(0)).getSubKeyName()); if(o instanceof Number){ left = ((Number) o).doubleValue(); }else{ left = Double.valueOf(o.toString()); } } else { if ((Integer)bindingStack.get(0) - 1 >= contents.length) return result; Object o = contents[(Integer)bindingStack.get(0) - 1]; if(o instanceof Number){ left = ((Number) o).doubleValue(); }else{ left = Double.valueOf(o.toString()); } } double right = 0; int size = bindingStack.size(); for (int i = 0; i < size - 1; i++) { if (bindingStack.get(i + 1) instanceof String && ((String)bindingStack.get(i + 1)).startsWith("#")) right = Double.valueOf(((String)bindingStack.get(i + 1)) .substring(1)); else if (bindingStack.get(i + 1) instanceof ObjectColumn) { if (((ObjectColumn)bindingStack.get(i+1)).getcIndex() - 1 >= contents.length) return result; Object o = contents[((ObjectColumn)bindingStack.get(i+1)).getcIndex() - 1]; o = ReportUtil.getValueFromJosnObj(o.toString(),((ObjectColumn)bindingStack.get(i+1)).getSubKeyName()); if(o instanceof Number){ right = ((Number) o).doubleValue(); }else{ right = Double.valueOf(o.toString()); } } else { if ((Integer)bindingStack.get(i + 1) - 1 >= contents.length) return result; Object o = contents[(Integer)bindingStack.get(i + 1) - 1]; if(o instanceof Number){ right = ((Number) o).doubleValue(); }else{ right = Double.valueOf(o.toString()); } } if (operatorStack.get(i) == AnalysisConstants.OPERATE_PLUS) { left += right; continue; } if (operatorStack.get(i) == AnalysisConstants.OPERATE_MINUS) { left -= right; continue; } if (operatorStack.get(i) == AnalysisConstants.OPERATE_RIDE) { left = left * right; continue; } if (operatorStack.get(i) == AnalysisConstants.OPERATE_DIVIDE) { left = left / right; continue; } } result = left; } else { if (bindingStack.get(0) instanceof String && ((String)bindingStack.get(0)).startsWith("#")) result = Double.valueOf(((String)bindingStack.get(0)).substring(1)); else if (bindingStack.get(0) instanceof ObjectColumn) { if (((ObjectColumn)bindingStack.get(0)).getcIndex() - 1 >= contents.length) return result; result = contents[((ObjectColumn)bindingStack.get(0)).getcIndex() - 1]; result = ReportUtil.getValueFromJosnObj(result.toString(),((ObjectColumn)bindingStack.get(0)).getSubKeyName()); } else { if ((Integer)bindingStack.get(0) - 1 >= contents.length) return result; result = contents[(Integer)bindingStack.get(0) - 1]; } } } return result; } }