package net.ion.craken.node.convert.rows; import java.lang.reflect.InvocationTargetException; import java.util.List; import net.ion.craken.node.ReadNode; import net.ion.craken.node.convert.rows.function.NvlFunction; import net.ion.craken.node.convert.rows.function.SingleColumn; import net.ion.framework.util.ListUtil; import net.ion.framework.util.NumberUtil; import net.ion.framework.util.ObjectUtil; import net.ion.framework.util.StringUtil; public class ColumnParser { public ColumnParser(){ } private static List<String> FunctionName = ListUtil.toList("nvl", "tochar", "decode", "substr", "sign", "length", "power", "divide", "floor", "mod", "tonumber", "append", "lpad", "minus", "min", "max"); public NodeColumns parse(String... columns) { List<IColumn> result = ListUtil.newList() ; for (int i = 0; i < columns.length; i++) { result.add(this.parse(columns[i])); } return NodeColumns.create(result.toArray(new IColumn[0])); } public IColumn nvl(String... cols) { List<String> list = ListUtil.toList(cols); return new NvlFunction(this, (String[]) (list.subList(0, list.size() - 1).toArray(new String[0])), cols[cols.length - 1]); } public IColumn constant(Object con, String label) { return new ConstantColumn(con, label); } private String[] getParams(String expression) { List<String> list = ListUtil.newList(); String[] params = StringUtil.split(expression, ","); String value = ""; for (int i = 0; i < params.length; i++) { if (StringUtil.isEmpty(value)) value = params[i]; else { value = value + "," + params[i]; } if (isIncludeCountMatches(value, "(", ")")) { list.add(value); value = ""; } } return list.toArray(new String[0]); } private boolean isIncludeCountMatches(String value, String startKey, String endKey) { return StringUtil.countMatches(value, startKey) == StringUtil.countMatches(value, endKey); } public IColumn parse(String expression) { // decode(a, b) c // decode(r.a, r.b) c // decode(r.a, 'constant') c // String expression = _expression.toLowerCase(); try { if (isFunctionExpression(expression)) { String fnName = StringUtil.lowerCase(StringUtil.substringBefore(expression, "(")); String paramString = StringUtil.substringAfter(expression, "("); paramString = StringUtil.substringBeforeLast(paramString, ")"); String[] params = getParams(paramString); String alias = StringUtil.defaultIfEmpty(StringUtil.substringAfterLast(expression, ")").trim(), expression); Class clz = Class.forName("net.ion.craken.node.convert.rows.function." + StringUtil.capitalize(fnName) + "Function"); Object[] passed = {this, params, alias }; IColumn col = (IColumn) clz.getConstructor(ColumnParser.class, String[].class, String.class).newInstance(passed); return col; } else if (isConstantExpression(expression)) { String[] cols = StringUtil.split(expression, " "); // @TODO : not sufficiency Object value = NumberUtil.isNumber(cols[0]) ? Integer.parseInt(cols[0]) : StringUtil.substringBetween(cols[0], "'", "'"); String alias = (cols.length == 1 ? ObjectUtil.toString(value) : cols[1]); return new ConstantColumn(value, alias); } else { String[] exps = StringUtil.split(expression, " "); if (exps.length == 1) { return new PropertyColumn(exps[0], ""); } else if (exps.length == 2) { return new PropertyColumn(exps[0], exps[1]); // } else if (exps.length == 2 && expression.contains(".")) { // a.b // return new ReferenceColumn(expression, exps[1]); // } else if (exps.length == 2 && expression.contains(" ")) { // a b // return new NormalColumn(exps[0], exps[1]); // } else if (exps.length == 3 && expression.contains(".")) { // a.b c // return new ReferenceColumn(exps[0] + "." + exps[1], exps[2]); } else { throw new IllegalArgumentException(expression + " is illegal expression"); } } } catch (ClassNotFoundException e) { throw new IllegalArgumentException(e); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(e); } catch (SecurityException e) { throw new IllegalArgumentException(e); } catch (InstantiationException e) { throw new IllegalArgumentException(e); } catch (IllegalAccessException e) { throw new IllegalArgumentException(e); } catch (InvocationTargetException e) { throw new IllegalArgumentException(e); } catch (NoSuchMethodException e) { throw new IllegalArgumentException(e); } } private boolean isConstantExpression(String expression) { return expression.startsWith("'") || NumberUtil.isNumber(expression); } private boolean isFunctionExpression(String expression) { String fnName = StringUtil.lowerCase(StringUtil.substringBefore(expression, "(")); return FunctionName.contains(fnName); } } class PropertyColumn extends SingleColumn { private String targetColumn; private String label; PropertyColumn(String targetColumn, String label) { this.targetColumn = targetColumn ; this.label = label ; } public String getLabel() { if (StringUtil.isBlank(label)){ String[] names = StringUtil.split(targetColumn, "/@") ; return names[names.length-1] ; } return label ; } @Override public String toString() { return label + " ( " + targetColumn + " ) "; } public Object getValue(ReadNode node) { StringBuilder prefix = new StringBuilder() ; for(char c : targetColumn.toCharArray()){ if (c == '/'){ final String afterName = StringUtil.substringAfter(targetColumn, prefix.toString() + "/"); if ("..".equals(prefix.toString())){ return new PropertyColumn(afterName, afterName).getValue(node.parent()) ; } else if (node.hasChild(prefix.toString())){ return new PropertyColumn(afterName, afterName).getValue(node.child(prefix.toString())) ; } } else if (c == '@' && node.hasRef(prefix.toString())) { final String afterName = StringUtil.substringAfter(targetColumn, prefix.toString() + "@"); return new PropertyColumn(afterName, afterName).getValue(node.ref(prefix.toString())) ; } prefix.append(c) ; } return node.property(targetColumn).value(); } }