package sushi.transformation; import java.util.Iterator; import java.util.Map; import sushi.esper.SushiStreamProcessingAdapter; import sushi.event.SushiEventType; import sushi.transformation.TransformationRule; import sushi.transformation.collection.SushiPatternTree; import sushi.transformation.element.EventTypeElement; 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; import com.espertech.esper.client.EPAdministrator; import com.espertech.esper.client.EPException; import com.espertech.esper.client.EPStatement; /** * Handles the transformation of events. Checks transformations rules for validity * and registers and removes them at/from the stream processing adapter. * */ public class TransformationManager { private static TransformationManager instance = null; SushiStreamProcessingAdapter esper; public TransformationManager() { esper = SushiStreamProcessingAdapter.getInstance(); initializeWithTransformationRulesFromDB(); } /** * Registers transformation rules that are stored in the database at the stream processing adapter. */ public void initializeWithTransformationRulesFromDB() { for (TransformationRule transformationRule: TransformationRule.findAll()) { register(transformationRule); System.out.println("Registered transformation rule '" + transformationRule.getTitle() + "' for event type '" + transformationRule.getEventType().getTypeName() + "' from database."); } } public static TransformationManager getInstance() { if (instance == null) { instance = new TransformationManager(); } return instance; } public static boolean instanceIsCleared() { return (instance == null); } public static void clearInstance() { instance = null; } /** * Registers transformation rule at the stream processing adapter. * @param transformationRule the transformation rule * @return transformation listener that receives values composed by Esper and outputs them as newly created events * @throws EPException */ public TransformationListener register(TransformationRule transformationRule) throws EPException { /* NOTE: one statement for each transformation rule * * other option would be: * if the transformation rule is equal an existing one, * a second listener (probably transforming to another event type but with the same attributes) * would be added to the existing statement */ EPStatement newStatement = esper.createStatement(transformationRule.getQuery(), generateStatementName(transformationRule)); TransformationListener listener = esper.createTransformationListener(transformationRule.getEventType()); newStatement.addListener(listener); return listener; } /** * Removes transformation rule from the stream processing adapter. * * @param transformationRule the transformation rule * @return true if transformation rule existed and has now been removed * @throws EPException */ public boolean removeFromEsper(TransformationRule transformationRule) throws EPException { EPStatement statement = esper.getStatement(generateStatementName(transformationRule)); if (statement != null) { // statement has only one listener - see comment in addToEsper(...) statement.removeAllListeners(); statement.destroy(); // statement.removeListener(transformationRule.getTransformationListener()); // if (!statement.getUpdateListeners().hasNext()) { // statement.destroy(); // } return true; } else { return false; } } private String generateStatementName(TransformationRule transformationRule) { return ("transformation_" + transformationRule.getEventType().getTypeName() + "_" + transformationRule.getTitle()).toLowerCase(); } public SushiStreamProcessingAdapter getEsper() { return esper; } public void setEsper(SushiStreamProcessingAdapter esper) { this.esper = esper; } public EPAdministrator getEsperAdministrator() { return esper.getEsperAdministrator(); } /** * Checks components of a transformation rule for validity. * * @param selectedEventType event type of the resulting events * @param transformationRuleName name of transformation rule * @param attributeIdentifiersAndExpressions map of attributes and desired values of the resulting events * @param attributeIdentifiersWithExternalKnowledge map of attributes using external knowledge and their sets of external knowledge expressions * @param patternTree pattern determining when a new event is created * @throws RuntimeException exception message may be used to output errors on the user interface */ public void checkForValidity(SushiEventType selectedEventType, String transformationRuleName, Map<String, String> attributeIdentifiersAndExpressions, Map<String, ExternalKnowledgeExpressionSet> attributeIdentifiersWithExternalKnowledge, SushiPatternTree patternTree) throws RuntimeException { if (patternTree.isEmpty()) { throw new RuntimeException("Pattern builder: Please provide a pattern!"); } for (PatternOperatorElement element : patternTree.getPatternOperatorElements()) { if (element.getValue() == PatternOperatorEnum.UNTIL) { RangeElement rangeElement = element.getRangeElement(); if ((rangeElement.getLeftEndpoint() < 0 && rangeElement.getRightEndpoint() < 0) || !(rangeElement.getLeftEndpoint() < rangeElement.getRightEndpoint())) { throw new RuntimeException("Pattern builder: Please check the range specification(s) of the UNTIL pattern operator(s)!"); } } else if (element.getValue() == PatternOperatorEnum.EVERY_DISTINCT) { if (element.getDistinctAttributes().isEmpty()) { throw new RuntimeException("Pattern builder: Please provide distinct attributes!"); } } else if (element.getValue() == PatternOperatorEnum.REPEAT) { RangeElement rangeElement = element.getRangeElement(); if (!(rangeElement.getLeftEndpoint() > 0)) { throw new RuntimeException("Pattern builder: Please check the provided number of event occurences for the REPEAT pattern operator(s)!"); } } } for (EventTypeElement element : patternTree.getEventTypeElements()) { if (!element.hasAlias()) { throw new RuntimeException("Pattern builder: An alias is required for each event type!"); } } for (FilterExpressionElement element : patternTree.getFilterExpressionElements()) { if ((element.getValue() == FilterExpressionOperatorEnum.IN || element.getValue() == FilterExpressionOperatorEnum.NOT_IN)) { if (element.isRightHandSideRangeBased()) { RangeElement rangeElement = element.getRightHandSideRangeOfValues(); if (!(rangeElement.getLeftEndpoint() < rangeElement.getRightEndpoint())) { throw new RuntimeException("Pattern builder: Please check the range specifications in your filter expressions!"); } } else { if (element.getRightHandSideListOfValues().isEmpty()) { throw new RuntimeException("Pattern builder: The list of values in your filter expressions is empty!"); } } } else { if (element.getLeftHandSideExpression() == null || element.getLeftHandSideExpression().isEmpty() || element.getRightHandSideExpression() == null || element.getRightHandSideExpression().isEmpty()) { throw new RuntimeException("Pattern builder: Please check your filter expressions for completion!"); } } } if (selectedEventType == null) { throw new RuntimeException("Attribute selection: Please select the event type for the transformed events!"); } Iterator <String> iterator = attributeIdentifiersAndExpressions.keySet().iterator(); while (iterator.hasNext()) { String attributeIdentifier = iterator.next(); if (attributeIdentifiersWithExternalKnowledge.get(attributeIdentifier) != null) { for (ExternalKnowledgeExpression expression : attributeIdentifiersWithExternalKnowledge.get(attributeIdentifier).getExternalKnowledgeExpressions()) { if (expression.getCriteriaAttributesAndValues().isEmpty() || expression.getDesiredAttribute() == null || expression.getEventType() == null) { throw new RuntimeException("Attribute selection: Incomplete information provided for retrieval of external knowledge - please check!"); } } } else if (attributeIdentifiersAndExpressions.get(attributeIdentifier) == null || attributeIdentifiersAndExpressions.get(attributeIdentifier).isEmpty()) { throw new RuntimeException("Attribute selection: Please provide values for all attributes!"); } } if (transformationRuleName == null || transformationRuleName.isEmpty()) { throw new RuntimeException("Please provide a name for your transformation rule!"); } } /** * Collects all necessary parameters for a transformation rule and creates it. * * @param selectedEventType event type of the resulting events * @param transformationRuleName name of transformation rule * @param attributeIdentifiersAndExpressions map of attributes and desired values of the resulting events * @param attributeIdentifiersWithExternalKnowledge map of attributes using external knowledge and their sets of external knowledge expressions * @param patternTree pattern determining when a new event is created * @return newly created transformation rule */ public TransformationRule createTransformationRule(SushiEventType selectedEventType, String transformationRuleName, SushiPatternTree patternTree, Map<String, String> attributeIdentifiersAndExpressions, Map<String, ExternalKnowledgeExpressionSet> attributeIdentifiersWithExternalKnowledge) { return new TransformationRule(selectedEventType, transformationRuleName, patternTree, attributeIdentifiersAndExpressions, attributeIdentifiersWithExternalKnowledge); } }