Java tutorial
/** * The Clican-Pluto software suit is Copyright 2009, Clican Company and individual contributors, and is licensed under the GNU LGPL. * * @author clican * */ package com.clican.pluto.dataprocess.dpl.impl; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.clican.pluto.common.util.TypeUtils; import com.clican.pluto.dataprocess.dpl.DplStatement; import com.clican.pluto.dataprocess.dpl.comparator.GroupConditionComparator; import com.clican.pluto.dataprocess.dpl.comparator.OrderByComparator; import com.clican.pluto.dataprocess.dpl.function.MultiRowFunction; import com.clican.pluto.dataprocess.dpl.function.SingleRowFunction; import com.clican.pluto.dataprocess.dpl.parser.FilterParser; import com.clican.pluto.dataprocess.dpl.parser.FromParser; import com.clican.pluto.dataprocess.dpl.parser.GroupByParser; import com.clican.pluto.dataprocess.dpl.parser.OrderByParser; import com.clican.pluto.dataprocess.dpl.parser.PagingParser; import com.clican.pluto.dataprocess.dpl.parser.SelectParser; import com.clican.pluto.dataprocess.dpl.parser.SubDplParser; import com.clican.pluto.dataprocess.dpl.parser.bean.Column; import com.clican.pluto.dataprocess.dpl.parser.bean.DplResultSet; import com.clican.pluto.dataprocess.dpl.parser.bean.Group; import com.clican.pluto.dataprocess.dpl.parser.bean.GroupCondition; import com.clican.pluto.dataprocess.dpl.parser.bean.PrefixAndSuffix; import com.clican.pluto.dataprocess.dpl.parser.object.From; import com.clican.pluto.dataprocess.dpl.parser.object.GroupBy; import com.clican.pluto.dataprocess.dpl.parser.object.OrderBy; import com.clican.pluto.dataprocess.dpl.parser.object.Pagination; import com.clican.pluto.dataprocess.dpl.parser.object.Select; import com.clican.pluto.dataprocess.dpl.parser.object.SubDpl; import com.clican.pluto.dataprocess.dpl.parser.object.filter.CompareFilter; import com.clican.pluto.dataprocess.dpl.parser.object.filter.Filter; import com.clican.pluto.dataprocess.engine.ProcessorContext; import com.clican.pluto.dataprocess.engine.impl.ProcessorContextImpl; import com.clican.pluto.dataprocess.exception.DplException; import com.clican.pluto.dataprocess.exception.DplParseException; /** * <code>DplStatement</code> * <p> * ?<code>DplStatement</code>? * * ?DPL??Select, From, Filter, Order By Group By * * <ul> * <li>??</li> * <li>??</li> * <li>??</li> * <li>?Filter???</li> * <li>?Group By???</li> * <li>????Select????Filter?Select? * Selectfunction???</li> * <li>????????selectas??</li> * <li></li> * </ul> * * <p> * ?List??Map?????? Class??? * <code>DplStatementImpl</code>Map?Class?? * <p/> * * @author clican * */ public class DplStatementImpl implements DplStatement { private final static Log log = LogFactory.getLog(DplStatementImpl.class); /** * <code>FilterParser</code> */ private FilterParser filterParser; /** * <code>GroupByParser</code> */ private GroupByParser groupByParser; /** * <code>OrderByParser</code> */ private OrderByParser orderByParser; /** * <code>SelectParser</code> */ private SelectParser selectParser; /** * <code>FromParser</code> */ private FromParser fromParser; private PagingParser pagingParser; private SubDplParser subDplParser; public void setFilterParser(FilterParser filterParser) { this.filterParser = filterParser; } public void setGroupByParser(GroupByParser groupByParser) { this.groupByParser = groupByParser; } public void setOrderByParser(OrderByParser orderByParser) { this.orderByParser = orderByParser; } public void setSelectParser(SelectParser selectParser) { this.selectParser = selectParser; } public void setFromParser(FromParser fromParser) { this.fromParser = fromParser; } public void setPagingParser(PagingParser pagingParser) { this.pagingParser = pagingParser; } public void setSubDplParser(SubDplParser subDplParser) { this.subDplParser = subDplParser; } /** * @see DplStatement#execute(String, ProcessorContext) */ public List<Map<String, Object>> execute(String dpl, ProcessorContext context) throws DplException { dpl = trimDpl(dpl); if (dpl.trim().length() == 0) { log.warn("dpl statement empty, simple return null"); return null; } ProcessorContext clone = context.getCloneContext(); PrefixAndSuffix.setLocalContext(clone); try { // ?dpl?? SubDpl subDpl = subDplParser.parseSubDpl(dpl, clone); if (subDpl != null) { for (String subDplStr : subDpl.getSubDplStrAliasMap().keySet()) { String alias = subDpl.getSubDplStrAliasMap().get(subDplStr); Object result = subDpl.getAliasResultMap().get(alias); dpl = StringUtils.replaceOnce(dpl, subDplStr, alias); if (alias.startsWith("dual")) { clone.setAttribute(alias.substring(5), result); } else { clone.setAttribute(alias, result); } } } From from = fromParser.parseFrom(dpl, clone); if (from.getVariableNames().size() == 0) { throw new DplParseException("From?"); } Filter filter = filterParser.parseFilter(dpl, clone); GroupBy groupBy = groupByParser.parseGroupBy(dpl, clone); OrderBy orderBy = orderByParser.parseOrderBy(dpl, clone); Select select = selectParser.parseSelect(dpl, clone); Pagination pagination = pagingParser.parsePagination(dpl, clone); // ???? DplResultSet dplResultSet = null; if (filter != null) { filter.filter(clone); dplResultSet = clone.getAttribute(CompareFilter.DPL_RESULT_SET); } if (dplResultSet == null) { dplResultSet = new DplResultSet(); for (String name : from.getVariableNames()) { dplResultSet.getResultNames().add(name); List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(); List<Object> list = clone.getAttribute(name); if (list.size() == 0) { dplResultSet = new DplResultSet(); break; } if (dplResultSet.getResultSet().size() == 0) { for (Object obj : list) { Map<String, Object> map = new HashMap<String, Object>(); map.put(name, obj); result.add(map); } dplResultSet.setResultSet(result); } else { for (Object obj : list) { for (Map<String, Object> row : new ArrayList<Map<String, Object>>( dplResultSet.getResultSet())) { Map<String, Object> map = new HashMap<String, Object>(row); map.put(name, obj); result.add(map); } } dplResultSet.setResultSet(result); } } } // Join??? // ?? Map<String, Set<Object>> data = new HashMap<String, Set<Object>>(); for (String name : from.getVariableNames()) { if (!name.equals(CompareFilter.DPL_RESULT_SET)) { List<Object> list = clone.getAttribute(name); data.put(name, new HashSet<Object>(list)); } } // ?? List<Map<String, Object>> rs = new ArrayList<Map<String, Object>>(); // ???Join??? for (Map<String, Object> result : dplResultSet.getResultSet()) { boolean valid = true; for (String key : result.keySet()) { if (result.get(key) != null && !data.get(key).contains(result.get(key))) { valid = false; } } if (valid) { rs.add(result); } } // ???? Map<List<GroupCondition>, List<Map<String, Object>>> groupByRs = new HashMap<List<GroupCondition>, List<Map<String, Object>>>(); // ??????? if (groupBy != null) { try { for (Map<String, Object> result : rs) { List<GroupCondition> gcSet = new ArrayList<GroupCondition>(); for (int i = 0; i < groupBy.getGroups().size(); i++) { Group group = groupBy.getGroups().get(i); Object groupValue = group.getValue(result); GroupCondition gc = new GroupCondition(); gc.setPosition(i); gc.setGroupName(group.getExpr()); gc.setGroupValue(groupValue); gcSet.add(gc); } if (!groupByRs.containsKey(gcSet)) { groupByRs.put(gcSet, new ArrayList<Map<String, Object>>()); } groupByRs.get(gcSet).add(result); } } catch (Exception e) { throw new DplParseException(e); } } // SelectFunction??? List<Map<String, Object>> newRs = new ArrayList<Map<String, Object>>(); try { if (groupBy != null) { List<List<GroupCondition>> temp = new ArrayList<List<GroupCondition>>(groupByRs.keySet()); // ???? Collections.sort(temp, new GroupConditionComparator()); // ??????Select??? for (List<GroupCondition> gcSet : temp) { Map<String, Object> groupMap = new HashMap<String, Object>(); for (GroupCondition gc : gcSet) { groupMap.put(gc.getGroupName(), gc.getGroupValue()); } Map<String, Object> row = new HashMap<String, Object>(); for (Column column : select.getColumns()) { String key = column.getColumnName(); PrefixAndSuffix pas = column.getPrefixAndSuffix(); if (pas.getFunction() instanceof SingleRowFunction) { SingleRowFunction fun = (SingleRowFunction) pas.getFunction(); if (groupMap.containsKey(fun.getExpr())) { Object value = groupMap.get(fun.getExpr()); row.put(key, value); groupMap.put(key, value); } else { Object value = fun.recurseCalculate(groupByRs.get(gcSet), groupMap); row.put(key, value); groupMap.put(key, value); } } else if (pas.getFunction() instanceof MultiRowFunction) { MultiRowFunction fun = (MultiRowFunction) pas.getFunction(); Object value = fun.recurseCalculate(groupByRs.get(gcSet)); row.put(key, value); groupMap.put(key, value); } else { Object value = pas.getValue(groupMap); row.put(key, value); groupMap.put(key, value); } } newRs.add(row); } } else { // ???Join????Select??? if (select.containMultiRowCalculation()) { // ? Map<String, Object> map = new HashMap<String, Object>(); Map<String, Object> row = new HashMap<String, Object>(); map.putAll(context.getMap()); for (Column column : select.getColumns()) { String key = column.getColumnName(); PrefixAndSuffix pas = column.getPrefixAndSuffix(); if (pas.getFunction() instanceof SingleRowFunction) { SingleRowFunction fun = (SingleRowFunction) pas.getFunction(); Object value = fun.recurseCalculate(rs, map); map.put(key, value); row.put(key, value); } else if (pas.getFunction() instanceof MultiRowFunction) { MultiRowFunction cal = (MultiRowFunction) pas.getFunction(); Object value = cal.recurseCalculate(rs); map.put(key, value); row.put(key, value); } else { Object value = pas.getValue(map); if (value == null) { pas.isSupportInMultiFunctionWithoutGroupBy(); } map.put(key, value); row.put(key, value); } } newRs.add(row); } else { for (Map<String, Object> map : rs) { Map<String, Object> row = new HashMap<String, Object>(); for (Column column : select.getColumns()) { String key = column.getColumnName(); PrefixAndSuffix pas = column.getPrefixAndSuffix(); if (pas.getFunction() instanceof SingleRowFunction) { SingleRowFunction fun = (SingleRowFunction) pas.getFunction(); Object value = fun.recurseCalculate(rs, map); map.put(key, value); row.put(key, value); } else if (pas.getFunction() instanceof MultiRowFunction) { throw new DplException("????"); } else { Object value = pas.getValue(map); map.put(key, value); row.put(key, value); } } newRs.add(row); } } } } catch (Exception e) { throw new DplException(e); } // ???? List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(newRs); if (orderBy != null) { Collections.sort(list, new OrderByComparator(orderBy)); } // ?? if (pagination != null) { if (pagination.isReverse()) { if (pagination.getLimit() == null) { if (list.size() - pagination.getOffset() > 0) { return list.subList(0, list.size() - pagination.getOffset()); } else { return new ArrayList<Map<String, Object>>(); } } else { if (list.size() - pagination.getOffset() > 0) { if (list.size() - pagination.getOffset() - pagination.getLimit() >= 0) { return list.subList(list.size() - pagination.getOffset() - pagination.getLimit(), list.size() - pagination.getOffset()); } else { return list.subList(0, list.size() - pagination.getOffset()); } } else { return new ArrayList<Map<String, Object>>(); } } } else { if (pagination.getLimit() == null) { if (list.size() - pagination.getOffset() > 0) { return list.subList(pagination.getOffset(), list.size()); } else { return new ArrayList<Map<String, Object>>(); } } else { if (list.size() - pagination.getOffset() > 0) { if (list.size() - pagination.getOffset() - pagination.getLimit() >= 0) { return list.subList(pagination.getOffset(), pagination.getOffset() + pagination.getLimit()); } else { return list.subList(pagination.getOffset(), list.size()); } } else { return new ArrayList<Map<String, Object>>(); } } } } else { return list; } } finally { PrefixAndSuffix.releaseLocalContext(); } } /** * * * @param dpl * @return */ private String trimDpl(String dpl) { String[] dplLines = dpl.split("\n"); StringBuffer buf = new StringBuffer(dpl.length()); for (String dplLine : dplLines) { if (dplLine.trim().startsWith("--")) { continue; } else { // ??? dplLine = " " + dplLine.trim() + " "; } buf.append(dplLine); } dpl = buf.toString(); // tab?? dpl = dpl.replaceAll("\t", " "); return dpl; } /** * @see DplStatement#execute(String, ProcessorContext, Class) */ @SuppressWarnings("unchecked") public <T> List<T> execute(String dpl, ProcessorContext context, Class<T> clazz) throws DplException { List<Map<String, Object>> list = this.execute(dpl, context); if (clazz == null) { return (List<T>) list; } List<T> result = new ArrayList<T>(); for (Map<String, Object> row : list) { T t = null; // ?? if (row.size() == 1) { t = (T) row.entrySet().iterator().next().getValue(); } else { // ???clazz???? try { t = clazz.newInstance(); } catch (Exception e) { throw new DplException(e); } Method[] methods = clazz.getMethods(); Map<String, Method> methodMap = new HashMap<String, Method>(); for (Method method : methods) { methodMap.put(method.getName(), method); methodMap.put(method.getName().toLowerCase(), method); } for (String name : row.keySet()) { try { if (row.get(name) != null) { String setMethodName = com.clican.pluto.common.util.StringUtils.getSetMethodName(name); Object value = row.get(name); if (methodMap.containsKey(setMethodName) || methodMap.containsKey(setMethodName.toLowerCase())) { Class type = methodMap.get(setMethodName.toLowerCase()).getParameterTypes()[0]; if (!value.getClass().equals(type)) { if (value instanceof Number) { value = TypeUtils.numberToNumber((Number) value, type); } else if (value instanceof String) { value = TypeUtils.stringToNumber((String) value, type); } } if (methodMap.containsKey(setMethodName)) { methodMap.get(setMethodName).invoke(t, new Object[] { value }); } else { methodMap.get(setMethodName.toLowerCase()).invoke(t, new Object[] { value }); } } else { if (log.isTraceEnabled()) { log.trace("There is no this property [" + name + "]"); } } } } catch (Exception e) { if (log.isTraceEnabled()) { log.trace("There is no this property [" + name + "]"); } } } } result.add(t); } return result; } public <T> List<T> execute(String dpl, Map<String, Object> context, Class<T> clazz) throws DplException { ProcessorContext ctx = new ProcessorContextImpl(); for (String key : context.keySet()) { ctx.setAttribute(key, context.get(key)); } return this.execute(dpl, ctx, clazz); } public List<Map<String, Object>> execute(String dpl, Map<String, Object> context) throws DplException { ProcessorContext ctx = new ProcessorContextImpl(); for (String key : context.keySet()) { ctx.setAttribute(key, context.get(key)); } return this.execute(dpl, ctx); } } // $Id: DplStatementImpl.java 16208 2010-07-16 00:57:34Z wei.zhang $