/************************************************************************************** * Copyright (C) 2008 EsperTech, Inc. All rights reserved. * * http://esper.codehaus.org * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * **************************************************************************************/ package com.espertech.esper.epl.parse; import com.espertech.esper.epl.expression.ExprChainedSpec; import com.espertech.esper.epl.expression.ExprNode; import com.espertech.esper.epl.expression.ExprTimePeriod; import com.espertech.esper.epl.generated.EsperEPL2Ast; import com.espertech.esper.epl.spec.*; import com.espertech.esper.pattern.EvalFactoryNode; import com.espertech.esper.util.JavaClassHelper; import org.antlr.runtime.tree.Tree; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.ArrayList; import java.util.List; import java.util.Map; public class ASTContextHelper { private static final Log log = LogFactory.getLog(ASTContextHelper.class); public static CreateContextDesc walkCreateContext(Tree parent, Map<Tree, ExprNode> astExprNodeMap, Map<Tree, EvalFactoryNode> astPatternNodeMap, PropertyEvalSpec propertyEvalSpec, FilterSpecRaw filterSpec) { String contextName = parent.getChild(0).getText(); Tree detailParent = parent.getChild(1); ContextDetail contextDetail; // temporal fixed (start+end) and overlapping (initiated/terminated) if (detailParent.getType() == EsperEPL2Ast.CREATE_CTX_INIT || detailParent.getType() == EsperEPL2Ast.CREATE_CTX_FIXED) { ContextDetailCondition startEndpoint = getContextCondition(detailParent.getChild(0), astExprNodeMap, astPatternNodeMap, propertyEvalSpec); ContextDetailCondition endEndpoint = getContextCondition(detailParent.getChild(1), astExprNodeMap, astPatternNodeMap, propertyEvalSpec); boolean overlapping = detailParent.getType() == EsperEPL2Ast.CREATE_CTX_INIT; contextDetail = new ContextDetailInitiatedTerminated(startEndpoint, endEndpoint, overlapping); } // categorized else if (detailParent.getType() == EsperEPL2Ast.CREATE_CTX_CAT){ List<ContextDetailCategoryItem> items = new ArrayList<ContextDetailCategoryItem>(); for (int i = 0; i < detailParent.getChildCount() -1; i++) { Tree categoryParent = detailParent.getChild(i); ExprNode exprNode = astExprNodeMap.remove(categoryParent.getChild(0)); String name = categoryParent.getChild(1).getText(); items.add(new ContextDetailCategoryItem(exprNode, name)); } filterSpec = ASTExprHelper.walkFilterSpec(detailParent.getChild(detailParent.getChildCount() - 1), propertyEvalSpec, astExprNodeMap); contextDetail = new ContextDetailCategory(items, filterSpec); } // partitioned else if (detailParent.getType() == EsperEPL2Ast.CREATE_CTX_PART){ List<ContextDetailPartitionItem> rawSpecs = new ArrayList<ContextDetailPartitionItem>(); for (int i = 0; i < detailParent.getChildCount(); i++) { Tree partitionParent = detailParent.getChild(i); filterSpec = ASTExprHelper.walkFilterSpec(partitionParent.getChild(0), propertyEvalSpec, astExprNodeMap); propertyEvalSpec = null; List<String> propertyNames = new ArrayList<String>(); for (int j = 1; j < partitionParent.getChildCount(); j++) { String propertyName = ASTFilterSpecHelper.getPropertyName(partitionParent.getChild(j), 0); propertyNames.add(propertyName); } rawSpecs.add(new ContextDetailPartitionItem(filterSpec, propertyNames)); } contextDetail = new ContextDetailPartitioned(rawSpecs); } // partitioned else if (detailParent.getType() == EsperEPL2Ast.CREATE_CTX_COAL){ List<ContextDetailHashItem> rawSpecs = new ArrayList<ContextDetailHashItem>(); int count = 0; for (int i = 0; i < detailParent.getChildCount(); i++) { Tree hashItemParent = detailParent.getChild(i); if (hashItemParent.getType() == EsperEPL2Ast.COALESCE) { count++; ExprChainedSpec func = ASTLibHelper.getLibFunctionChainSpec(hashItemParent.getChild(0), astExprNodeMap); filterSpec = ASTExprHelper.walkFilterSpec(hashItemParent.getChild(1), propertyEvalSpec, astExprNodeMap); propertyEvalSpec = null; rawSpecs.add(new ContextDetailHashItem(func, filterSpec)); } } String granularity = detailParent.getChild(count).getText(); if (!granularity.toLowerCase().equals("granularity")) { throw new ASTWalkException("Expected 'granularity' keyword after list of coalesce items, found '" + granularity + "' instead"); } Number num = (Number) ASTConstantHelper.parse(detailParent.getChild(count + 1)); String preallocateStr = detailParent.getChildCount() - 1 < count+2 ? null : detailParent.getChild(count + 2).getText(); if (preallocateStr != null && !preallocateStr.toLowerCase().equals("preallocate")) { throw new ASTWalkException("Expected 'preallocate' keyword after list of coalesce items, found '" + preallocateStr + "' instead"); } if (!JavaClassHelper.isNumericNonFP(num.getClass()) || JavaClassHelper.getBoxedType(num.getClass()) == Long.class) { throw new ASTWalkException("Granularity provided must be an int-type number, received " + num.getClass() + " instead"); } contextDetail = new ContextDetailHash(rawSpecs, num.intValue(), preallocateStr != null); } else if (detailParent.getType() == EsperEPL2Ast.CREATE_CTX_NESTED) { List<CreateContextDesc> contexts = new ArrayList<CreateContextDesc>(); for (int i = 0; i < detailParent.getChildCount(); i++) { Tree parentCreate = detailParent.getChild(i); if (parentCreate.getType() != EsperEPL2Ast.CREATE_CTX) { throw new IllegalStateException("Child to nested context is not a context-create but type " + parentCreate.getType()); } contexts.add(walkCreateContext(parentCreate, astExprNodeMap, astPatternNodeMap, propertyEvalSpec, filterSpec)); } contextDetail = new ContextDetailNested(contexts); } else { throw new IllegalStateException("Unrecognized context detail type '" + detailParent.getType() + "'"); } return new CreateContextDesc(contextName, contextDetail); } private static ContextDetailCondition getContextCondition(Tree parent, Map<Tree, ExprNode> astExprNodeMap, Map<Tree, EvalFactoryNode> astPatternNodeMap, PropertyEvalSpec propertyEvalSpec) { if (parent.getType() == EsperEPL2Ast.CRONTAB_LIMIT_EXPR_PARAM) { List<ExprNode> crontab = ASTExprHelper.getRemoveAllChildExpr(parent, astExprNodeMap); return new ContextDetailConditionCrontab(crontab); } else if (parent.getType() == EsperEPL2Ast.CREATE_CTX_PATTERN) { EvalFactoryNode evalNode = astPatternNodeMap.remove(parent.getChild(0).getChild(0)); boolean inclusive = false; if (parent.getChildCount() > 1) { String ident = parent.getChild(1).getText(); if (ident != null && !ident.toLowerCase().equals("inclusive")) { throw new ASTWalkException("Expected 'inclusive' keyword after '@', found '" + ident + "' instead"); } inclusive = true; } return new ContextDetailConditionPattern(evalNode, inclusive); } else if (parent.getType() == EsperEPL2Ast.STREAM_EXPR) { FilterSpecRaw filterSpecRaw = ASTExprHelper.walkFilterSpec(parent.getChild(0), propertyEvalSpec, astExprNodeMap); String asName = parent.getChildCount() > 1 ? parent.getChild(1).getText() : null; return new ContextDetailConditionFilter(filterSpecRaw, asName); } else if (parent.getType() == EsperEPL2Ast.AFTER) { ExprTimePeriod timePeriod = (ExprTimePeriod) astExprNodeMap.remove(parent.getChild(0)); return new ContextDetailConditionTimePeriod(timePeriod); } else { throw new IllegalStateException("Unrecognized child type " + parent.getType()); } } }