/** * Copyright (C) 2008 - 2014 52°North Initiative for Geospatial Open Source * Software GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * * If the program is linked with libraries which are licensed under one of * the following licenses, the combination of the program with the linked * library is not considered a "derivative work" of the program: * * - Apache License, version 2.0 * - Apache Software License, version 1.0 * - GNU Lesser General Public License, version 3 * - Mozilla Public License, versions 1.0, 1.1 and 2.0 * - Common Development and Distribution License (CDDL), version 1.0 * * Therefore the distribution of the program linked with libraries licensed * under the aforementioned licenses, is permitted by the copyright holders * if the distribution is compliant with both the GNU General Public * icense version 2 and the aforementioned licenses. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. */ /** * Part of the diploma thesis of Thomas Everding. * @author Thomas Everding */ package org.n52.ses.eml.v002.pattern; import java.util.HashMap; import org.n52.ses.api.eml.ILogicController; import org.n52.ses.api.event.MapEvent; import org.n52.ses.eml.v002.Constants; import org.n52.ses.eml.v002.filterlogic.EMLParser; import org.n52.ses.eml.v002.filterlogic.esper.customFunctions.MethodNames; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * representation of a complex pattern * * @author Thomas Everding * */ public class PatternComplex extends AGuardedViewPattern { /* * Logger instance for this class */ private static final Logger logger = LoggerFactory .getLogger(PatternComplex.class); private PatternOperator operator; private String firstPatternID; private String secondPatternID; private int firstSelectFunctionNumber; private int secondSelectFunctionNumber; private ILogicController controller; private long maxListeningDuration = -1; private EMLParser parser; /** * @return the operator */ public PatternOperator getOperator() { return this.operator; } /** * sets the operator * * @param operator the operator to set */ public void setOperator(PatternOperator operator) { this.operator = operator; } /** * @return the first pattern ID */ public String getFirstPatternID() { return this.firstPatternID; } /** * @param firstPatternID the first pattern ID to set */ public void setFirstPatternID(String firstPatternID) { this.firstPatternID = firstPatternID; } /** * @return the second pattern ID */ public String getSecondPatternID() { return this.secondPatternID; } /** * @param secondPatternID the second pattern ID to set */ public void setSecondPatternID(String secondPatternID) { this.secondPatternID = secondPatternID; } /** * @return the firstSelectFunctionNumber */ public int getFirstSelectFunctionNumber() { return this.firstSelectFunctionNumber; } /** * @param firstSelectFunctionNumber the firstSelectFunctionNumber to set */ public void setFirstSelectFunctionNumber(int firstSelectFunctionNumber) { this.firstSelectFunctionNumber = firstSelectFunctionNumber; } /** * @return the secondSelectFunctionNumber */ public int getSecondSelectFunctionNumber() { return this.secondSelectFunctionNumber; } /** * @param secondSelectFunctionNumber the secondSelectFunctionNumber to set */ public void setSecondSelectFunctionNumber(int secondSelectFunctionNumber) { this.secondSelectFunctionNumber = secondSelectFunctionNumber; } /** * @param logicController the controller to set */ public void setController(ILogicController logicController) { this.controller = logicController; } /** * @return the maxListeningDuration (ms) */ public long getMaxListeningDuration() { return this.maxListeningDuration; } /** * @param maxListeningDuration the maxListeningDuration to set (ms) */ public void setMaxListeningDuration(long maxListeningDuration) { this.maxListeningDuration = maxListeningDuration; } @Override public Statement[] createEsperStatements() { Statement[] result = new Statement[this.selectFunctions.size()]; String firstInputEventName = ""; String secondInputEventName = ""; if (this.controller != null ) { //get first input event name firstInputEventName = this.controller.getNewEventName(this.firstPatternID, this.firstSelectFunctionNumber); //get second input event name secondInputEventName = this.controller.getNewEventName(this.secondPatternID, this.secondSelectFunctionNumber); } else if (this.parser != null) { firstInputEventName = getNewEventNameWithParser(this.firstSelectFunctionNumber) ; secondInputEventName = getNewEventNameWithParser(this.secondSelectFunctionNumber); } else { //something went wrong return null; } /* * build statements */ String selectClause; String fromClause; String whereClause = ""; SelFunction sel; Statement stat; if (this.guard != null) { //TODO workaround //build where clause (use maxListeningDuration and the Guard!) String pName = null; try { //TODO: does only work with one select function... HashMap<String, Object> params = this.selectFunctions.get(0).getFunctionParameters(); if (params.containsKey(Constants.SELECT_PARAM_PROPERTY_NAME)) { pName = params.get(Constants.SELECT_PARAM_PROPERTY_NAME).toString(); } } catch (Throwable t) { PatternComplex.logger.warn("could not load parameters from select function"); } whereClause = this.guard.createStatement(true); if (pName != null) pName = pName.trim(); //TODO: wtf? this worked and seems not be changed, but now the (overloaded?) method is gone?! // whereClause = this.guard.createStatement(true, pName); } if (this.operator.equals(Constants.OPERATOR_CAUSE_NAME) || this.operator.equals(Constants.OPERATOR_BEFORE_NAME)) { //TODO operator.name ? evtl parallel statt before /* * CAUSE and PARALLEL have to work different (using guards with user functions) */ //build where clause if (whereClause.equals("")) { //no previous where clause, create one whereClause = Constants.EPL_WHERE + " " + this.buildCausalCheckString(firstInputEventName, secondInputEventName); } else { //append to existing where clause whereClause += "and" + this.buildCausalCheckString(firstInputEventName, secondInputEventName); } //build from clause (always use and) fromClause = Constants.EPL_FROM + " " + Constants.EPL_PATTERN + " [every (((" + firstInputEventName + "=" + firstInputEventName + ") and (" + secondInputEventName + "=" + secondInputEventName + ")) " + this.buildPatternTimerClause() + ")]"; } else { //build from clause fromClause = this.buildFromClause(firstInputEventName, secondInputEventName); } for (int i = 0; i < result.length; i++) { sel = this.selectFunctions.get(i); //build select clause selectClause = Constants.EPL_SELECT + " " + sel.getSelectString(false) + " "; //build statement stat = new Statement(); stat.setSelectFunction(sel); stat.setStatement(selectClause + fromClause + whereClause); stat.setView(this.view); //add statement to result result[i] = stat; } return result; } /** * Method for creating statements using just an EMLParser instead * of EsperController. (added by Matthes Rieke) */ private String getNewEventNameWithParser(int selectFunctionNumber) { int selFuncNumber = selectFunctionNumber; //get all patterns from parser HashMap<String, APattern> patterns = this.parser.getPatterns(); //search for pattern if (!this.parser.getPatterns().containsKey(this.patternID)) { PatternComplex.logger.warn("pattern ID (" + this.patternID + ") not found"); return null; } APattern pattern = patterns.get(this.patternID); //search for select function if (!(pattern.getSelectFunctions().size() > selFuncNumber)) { if (!(pattern.getSelectFunctions().size() >= 0)) { PatternComplex.logger.warn("No select function and therefore no 'newEventName' defined in pattern '" + this.patternID + "'. Can not use this pattern in a repetitive pattern."); return null; } PatternComplex.logger.warn("The pattern with the id '" + this.patternID + "does not define at least " + selFuncNumber + " selectfunctions. Using first select function instead."); //set number to 0 selFuncNumber = 0; } //return newEventName return pattern.getSelectFunctions().get(selFuncNumber).getNewEventName(); } @Override public Statement[] createEsperStatements(EMLParser emlParser) { this.parser = emlParser; return createEsperStatements(); } /** * build a part of the where clause for CAUSE and PARALLEL operators * * @param secondInputEventName name of the possible causal ancestor * @param firstInputEventName name of the event with the causal vector * * @return the part of the where clause without 'where' */ private String buildCausalCheckString(String firstInputEventName, String secondInputEventName) { String result = ""; //add operator if (this.operator.equals(Constants.OPERATOR_CAUSE_NAME)) { //CAUSE result += MethodNames.IS_CAUSAL_ANCESTOR_NAME + "("; } else { //PARALLEL result += MethodNames.IS_NOT_CAUSAL_ANCESTOR_NAME + "("; } //add parameters result += firstInputEventName + ", " + secondInputEventName + "." + MapEvent.CAUSALITY_KEY + ")"; return result; } /** * builds a from clause * * @param firstInputEventName name of the first input event * @param secondInputEventName name of the second input event * @return */ private String buildFromClause(String firstInputEventName, String secondInputEventName) { String clause = Constants.EPL_FROM + " " + Constants.EPL_PATTERN + " [every (((" + firstInputEventName + "=" + firstInputEventName + ") " + this.getOperatorString() + " (" + secondInputEventName + "=" + secondInputEventName + ")) " + this.buildPatternTimerClause() + ")]" /* * see esper-reference 2.3.0 chapter 5.2.2: * "In addition, a data window view can be declared onto a pattern." */ + this.view.getViewString() +" "; return clause; } /** * build the timer:within clause * * @return the pattern guard (timer:within) */ private String buildPatternTimerClause() { if(this.maxListeningDuration < 0) { //no within clause return ""; } //build clause String result = Constants.EPL_WHERE + " timer:within(" + this.maxListeningDuration + " msec)"; return result; } /** * * @return the esper representation for the operator */ private String getOperatorString() { String op = ""; String opName = this.operator.getName(); //AND if (opName.equals(Constants.OPERATOR_AND_NAME)) { op = "and"; } //AND NOT else if (opName.equals(Constants.OPERATOR_AND_NOT_NAME)) { op = ") and not ("; /* * The parentheses are necessary for correct execution. * The 'every' operator must only be used for the first pattern. */ } //OR else if (opName.equals(Constants.OPERATOR_OR_NAME)) { op = "or"; } //BEFORE else if (opName.equals(Constants.OPERATOR_BEFORE_NAME)) { op = "->"; } //CAUSE else if (opName.equals(Constants.OPERATOR_CAUSE_NAME)) { op = "and"; //functionality must be implemented as guard using 'in' } //PARALLEL else if (opName.equals(Constants.OPERATOR_PARALLEL_NAME)) { op = "and"; //functionality must be implemented as guard using 'in' } //user defined operators here else { PatternComplex.logger.warn("the operator '" + opName + "' is not supported"); } return op; } }