package sushi.transformation;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import sushi.event.SushiEventType;
import sushi.event.attribute.SushiAttributeTypeEnum;
import sushi.event.collection.SushiTreeElement;
import sushi.transformation.collection.SushiPatternTree;
import sushi.transformation.element.EventTypeElement;
import sushi.transformation.element.FilterExpressionConnectorElement;
import sushi.transformation.element.FilterExpressionConnectorEnum;
import sushi.transformation.element.FilterExpressionElement;
import sushi.transformation.element.FilterExpressionOperatorEnum;
import sushi.transformation.element.PatternOperatorElement;
import sushi.transformation.element.PatternOperatorEnum;
import sushi.transformation.element.RangeElement;
import sushi.transformation.element.externalknowledge.ExternalKnowledgeExpression;
import sushi.transformation.element.externalknowledge.ExternalKnowledgeExpressionSet;
/**
* Provides methods to parse queries in Esper EPL language from a transformation rule.
*/
public class EsperTransformationRuleParser extends TransformationRuleParser {
private static EsperTransformationRuleParser instance = null;
public static EsperTransformationRuleParser getInstance() {
if (instance == null) {
instance = new EsperTransformationRuleParser();
}
return instance;
}
/**
* Parses an Esper EPL query from the given parameters.
*
* @param attributeIdentifiersAndExpressions pairs of attribute identifiers and expressions - determines what values are stored in the transformed events
* @param patternTree pattern that is used to listen for events, built up from the provided elements
* @return Esper EPL query
*/
public String parseRule(SushiPatternTree patternTree, Map<String, String> attributeIdentifiersAndExpressions, Map<String, ExternalKnowledgeExpressionSet> attributeIdentifiersAndExpressionSets) {
assert(patternTree.getRoots().size() == 1);
StringBuffer query = new StringBuffer();
// SELECT part
query.append("SELECT");
String valueSelection = buildValueSelectionString(attributeIdentifiersAndExpressions, attributeIdentifiersAndExpressionSets);
query.append(valueSelection);
// FROM PATTERN part
SushiTreeElement<Serializable> rootElement = patternTree.getRoots().get(0);
String pattern = buildPatternString(rootElement);
query.append(" FROM Pattern [" + pattern + "]");
return query.toString();
}
protected String buildPatternString(SushiTreeElement<Serializable> element) {
if (element instanceof PatternOperatorElement) {
PatternOperatorElement poElement = ((PatternOperatorElement) element);
PatternOperatorEnum poType = (PatternOperatorEnum) poElement.getValue();
if (poElement.getChildren().size() == 2) {
String leftHandSideExpression = buildPatternString(poElement.getChildren().get(0));
String rightHandSideExpression = buildPatternString(poElement.getChildren().get(1));
if (poType == PatternOperatorEnum.UNTIL) {
RangeElement rangeElement = poElement.getRangeElement();
StringBuffer sb = new StringBuffer();
sb.append("(");
if (rangeElement.getLeftEndpoint() >= 0 || rangeElement.getRightEndpoint() >= 0) {
sb.append("[");
sb.append(rangeElement.getLeftEndpoint() < 0 ? "" : rangeElement.getLeftEndpoint());
sb.append(":");
sb.append(rangeElement.getRightEndpoint() < 0 ? "" : rangeElement.getRightEndpoint());
sb.append("] ");
}
sb.append(leftHandSideExpression + " UNTIL " + rightHandSideExpression);
sb.append(")");
return sb.toString();
} else if (poType == PatternOperatorEnum.AND) {
return "(" + leftHandSideExpression + " AND " + rightHandSideExpression + ")";
} else if (poType == PatternOperatorEnum.OR) {
return "(" + leftHandSideExpression + " OR " + rightHandSideExpression + ")";
} else if (poType == PatternOperatorEnum.FOLLOWED_BY) {
return "(" + leftHandSideExpression + " -> " + rightHandSideExpression + ")";
}
} else if (poElement.getChildren().size() == 1) {
String expression = buildPatternString(poElement.getChildren().get(0));
if (poType == PatternOperatorEnum.EVERY) {
return "(EVERY " + expression + ")";
} else if (poType == PatternOperatorEnum.EVERY_DISTINCT) {
StringBuffer sb = new StringBuffer();
sb.append("(EVERY-DISTINCT(");
Iterator<String> iteratorForDistinctAttributes = poElement.getDistinctAttributes().iterator();
while (iteratorForDistinctAttributes.hasNext()) {
String distinctAttribute = iteratorForDistinctAttributes.next();
sb.append(distinctAttribute);
if (iteratorForDistinctAttributes.hasNext()) {
sb.append(", ");
}
}
sb.append(") " + expression + ")");
return sb.toString();
} else if (poType == PatternOperatorEnum.REPEAT) {
RangeElement rangeElement = poElement.getRangeElement();
return "([" + rangeElement.getLeftEndpoint() + "] " + expression + ")";
} else if (poType == PatternOperatorEnum.NOT) {
return "(NOT " + expression + ")";
}
}
} else if (element instanceof EventTypeElement) {
EventTypeElement etElement = ((EventTypeElement) element);
StringBuffer sb = new StringBuffer();
if (etElement.hasAlias()) {
sb.append("(" + etElement.getAlias() + "=" + ((SushiEventType) etElement.getValue()).getTypeName());
} else {
sb.append("(" + ((SushiEventType) etElement.getValue()).getTypeName());
}
if (etElement.hasChildren()) {
sb.append("(");
Iterator<SushiTreeElement<Serializable>> iterator = element.getChildren().iterator();
while (iterator.hasNext()) {
SushiTreeElement<Serializable> currentElement = iterator.next();
sb.append(buildPatternString(currentElement));
if (iterator.hasNext()) {
sb.append(", ");
}
}
sb.append(")");
}
sb.append(")");
return sb.toString();
} else if (element instanceof FilterExpressionConnectorElement) {
FilterExpressionConnectorElement fecElement = (FilterExpressionConnectorElement) element;
FilterExpressionConnectorEnum fecType = (FilterExpressionConnectorEnum) fecElement.getValue();
if (fecType == FilterExpressionConnectorEnum.AND) {
String leftHandSideExpression = buildPatternString(fecElement.getChildren().get(0));
String rightHandSideExpression = buildPatternString(fecElement.getChildren().get(1));
return "(" + leftHandSideExpression + " AND " + rightHandSideExpression + ")";
} else if (fecType == FilterExpressionConnectorEnum.OR) {
String leftHandSideExpression = buildPatternString(fecElement.getChildren().get(0));
String rightHandSideExpression = buildPatternString(fecElement.getChildren().get(1));
return "(" + leftHandSideExpression + " OR " + rightHandSideExpression + ")";
} else if (fecType == FilterExpressionConnectorEnum.NOT) {
String expression = buildPatternString(fecElement.getChildren().get(0));
return "NOT (" + expression + ")";
}
} else if (element instanceof FilterExpressionElement) {
FilterExpressionElement feElement = (FilterExpressionElement) element;
FilterExpressionOperatorEnum feType = (FilterExpressionOperatorEnum) feElement.getValue();
StringBuffer sb = new StringBuffer();
sb.append("(");
sb.append("(" + feElement.getLeftHandSideExpression() + ") " + feType.getValue() + " ");
if (feType == FilterExpressionOperatorEnum.IN || feType == FilterExpressionOperatorEnum.NOT_IN) {
if (feElement.isRightHandSideRangeBased()) {
RangeElement rangeElement = feElement.getRightHandSideRangeOfValues();
sb.append(rangeElement.isLeftEndpointOpen() ? "(" : "[");
sb.append(rangeElement.getLeftEndpoint() + ":" + rangeElement.getRightEndpoint());
sb.append(rangeElement.isRightEndpointOpen() ? ")" : "]");
} else {
sb.append("(");
Iterator<String> iterator = feElement.getRightHandSideListOfValues().iterator();
while (iterator.hasNext()) {
sb.append(iterator.next());
if (iterator.hasNext()) {
sb.append(", ");
}
}
sb.append(")");
}
} else {
sb.append("(" + feElement.getRightHandSideExpression() + ")");
}
sb.append(")");
return sb.toString();
}
return "";
}
protected String buildValueSelectionString(Map<String, String> attributeIdentifiersAndExpressions, Map<String, ExternalKnowledgeExpressionSet> attributeIdentifiersAndExpressionSets) {
StringBuffer sb = new StringBuffer();
Iterator<String> iteratorForAttributeIdentifiers = attributeIdentifiersAndExpressions.keySet().iterator();
while (iteratorForAttributeIdentifiers.hasNext()) {
String attributeIdentifier = iteratorForAttributeIdentifiers.next();
if (attributeIdentifiersAndExpressions.get(attributeIdentifier) != null && !attributeIdentifiersAndExpressions.get(attributeIdentifier).isEmpty()) {
sb.append(" (" + attributeIdentifiersAndExpressions.get(attributeIdentifier) + ") AS " + attributeIdentifier);
if (iteratorForAttributeIdentifiers.hasNext()) {
sb.append(",");
}
} else if (attributeIdentifiersAndExpressionSets.get(attributeIdentifier) != null) {
sb.append(" (" + buildValueSelectionStringFromExternalKnowledge(attributeIdentifiersAndExpressionSets.get(attributeIdentifier)) + ") AS " + attributeIdentifier);
if (iteratorForAttributeIdentifiers.hasNext()) {
sb.append(",");
}
}
}
return sb.toString();
}
protected String buildValueSelectionStringFromExternalKnowledge(ExternalKnowledgeExpressionSet externalKnowledge) {
String externalKnowledgeFetchMethodName = null;
if (externalKnowledge.getResultingType() == SushiAttributeTypeEnum.STRING) {
externalKnowledgeFetchMethodName = "stringValueFromEvent";
} else if (externalKnowledge.getResultingType() == SushiAttributeTypeEnum.INTEGER) {
externalKnowledgeFetchMethodName = "integerValueFromEvent";
} else if (externalKnowledge.getResultingType() == SushiAttributeTypeEnum.DATE) {
externalKnowledgeFetchMethodName = "dateValueFromEvent";
}
StringBuffer sb = new StringBuffer();
sb.append("coalesce(");
for (ExternalKnowledgeExpression expression : externalKnowledge.getExternalKnowledgeExpressions()) {
sb.append(externalKnowledgeFetchMethodName + "(");
sb.append("'" + expression.getEventType().getTypeName() + "', ");
sb.append("'" + expression.getDesiredAttribute().getAttributeExpression() + "', {");
Iterator<String> iterator = expression.getCriteriaAttributesAndValues().keySet().iterator();
while (iterator.hasNext()) {
String criteriaAttributeExpression = iterator.next();
sb.append("'" + criteriaAttributeExpression + "', " + expression.getCriteriaAttributesAndValues().get(criteriaAttributeExpression));
if (iterator.hasNext()) {
sb.append(", ");
}
}
sb.append("}), ");
}
sb.append(externalKnowledge.getDefaultValue());
sb.append(")");
return sb.toString();
}
}