/** * 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 java.util.Vector; 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.views.DynamicSpatialBufferView; import org.n52.ses.util.common.ConfigurationRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * represents a single select function * * @author Thomas Everding * */ public class SelFunction { /* * Logger instance for this class */ private static final Logger logger = LoggerFactory .getLogger(SelFunction.class); private String outputName = ""; private boolean createCausality = false; private String selectString = ""; private String newEventName = ""; private String functionName; private HashMap<String, Object> functionParameters; private HashMap<String, String> fullPropertyNames; // private String inputName = ""; private Vector<PatternOutputReference> inputReferences; private String statement; private boolean singleValueOutput; private boolean allowOriginalMessageAsResult = false; private ILogicController controller; /** * contains the data types of the resulting event or the inner (nested) types, if the resulting event contains * an event. */ private HashMap<String, Object> dataTypes; /** * * Constructor * * @param logicController controller of this process * */ public SelFunction(ILogicController logicController) { this.functionParameters = new HashMap<String, Object>(); this.fullPropertyNames = new HashMap<String, String>(); this.dataTypes = new HashMap<String, Object>(); this.inputReferences = new Vector<PatternOutputReference>(); this.controller = logicController; } /** * @return the outputName */ public String getOutputName() { return this.outputName; } /** * @param outputName the outputName to set */ public void setOutputName(String outputName) { this.outputName = outputName; } /** * @return the createCausality */ public boolean getCreateCausality() { return this.createCausality; } /** * @param createCausality the createCausality to set */ public void setCreateCausality(boolean createCausality) { this.createCausality = createCausality; } /** * @return the newEventName */ public String getNewEventName() { return this.newEventName; } /** * @param newEventName the newEventName to set */ public void setNewEventName(String newEventName) { this.newEventName = newEventName; } /** * @return the functionName */ public String getFunctionName() { return this.functionName; } /** * @param functionName the functionName to set */ public void setFunctionName(String functionName) { this.functionName = functionName; } /** * @return the functionParameters */ public HashMap<String, Object> getFunctionParameters() { return this.functionParameters; } /** * adds a single parameter to the function parameter map * * @param pName name of the parameter * @param pValue value of the parameter */ public void addFunctionParameter(String pName, Object pValue) { Object pV = pValue; if (pName.equals(Constants.SELECT_PARAM_PROPERTY_NAME)) { //parse property name pV = this.parsePropertyName(pValue.toString()); } this.functionParameters.put(pName, pV); } /** * parses a property name for use in esper * * @param name the property name in EML */ private String parsePropertyName(String name) { String result = name; // int i = name.indexOf("/"); // // if (i >= 0) { // //cut off the event name // result = name.substring(i + 1); // } // else { // result = name; // } //replace "/" by "." result = result.replaceAll("/", "."); //save property name this.fullPropertyNames.put(result, name); return result; } /** * * @param forSimplePattern set to <code>true</code> if called for a simple pattern * @return the select string, creates it if necessary */ public String getSelectString(boolean forSimplePattern) { //boolean that indicates if additional selections are possible boolean preservingPossible = false; if (this.selectString.equals("")) { //create select string /* * SelectEvent */ if (this.functionName.equals(Constants.FUNC_SELECT_EVENT_NAME)) { this.singleValueOutput = false; this.allowOriginalMessageAsResult = true; //preserving not necessary if (this.functionParameters.containsKey(Constants.SELECT_PARAM_EVENT_NAME)) { //with EventName given String eventName = "" + this.functionParameters.get(Constants.SELECT_PARAM_EVENT_NAME); if (forSimplePattern) { //named not possible in simple patterns this.selectString = "*"; } else { //select specified event this.selectString = "" + eventName + " as value"; } //set data type this.dataTypes.put(MapEvent.VALUE_KEY, this.controller.getEventDatatype(eventName)); } else { SelFunction.logger.warn("No event name given."); // //no EventName given // this.selectString = "*"; // // //set data type // this.dataTypes.put(MapEvent.VALUE_KEY, MapEvent.class); } } /* * SelectProperty */ else if (this.functionName.equals(Constants.FUNC_SELECT_PROPERTY_NAME)) { this.singleValueOutput = true; preservingPossible = true; //load property data type String fullPropertyName = this.fullPropertyNames.get(this.functionParameters.get(Constants.SELECT_PARAM_PROPERTY_NAME)); this.dataTypes.put(MapEvent.VALUE_KEY, this.controller.getDatatype(fullPropertyName)); //adjust property name for simple patterns String pName = this.functionParameters.get(Constants.SELECT_PARAM_PROPERTY_NAME).toString(); if (forSimplePattern) { if (pName.contains(".")) { //exclude event name pName = pName.substring(pName.indexOf(".") + 1); } } //pName.replaceAll(":", "__"); //build select string this.selectString = "" + pName + " as value"; } /* * SelectSum */ else if (this.functionName.equals(Constants.FUNC_SELECT_SUM_NAME)) { this.singleValueOutput = true; this.dataTypes.put(MapEvent.VALUE_KEY, Number.class); //preserving not possible //adjust property name for simple patterns String pName = this.functionParameters.get(Constants.SELECT_PARAM_PROPERTY_NAME).toString(); if (forSimplePattern) { if (pName.contains(".")) { //exclude event name pName = pName.substring(pName.indexOf(".") + 1); } } //pName.replaceAll(":", "__"); this.selectString = "sum(" + pName + ")" + " as value"; } /* * SelectAvg */ else if (this.functionName.equals(Constants.FUNC_SELECT_AVG_NAME)) { this.singleValueOutput = true; this.dataTypes.put(MapEvent.VALUE_KEY, Number.class); //preserving not possible //adjust property name for simple patterns String pName = this.functionParameters.get(Constants.SELECT_PARAM_PROPERTY_NAME).toString(); if (forSimplePattern) { if (pName.contains(".")) { //exclude event name pName = pName.substring(pName.indexOf(".") + 1); } } //pName.replaceAll(":", "__"); this.selectString = "avg(" + pName + ")" + " as value"; } /* * SelectMax */ else if (this.functionName.equals(Constants.FUNC_SELECT_MAX_NAME)) { this.singleValueOutput = true; this.dataTypes.put(MapEvent.VALUE_KEY, Number.class); preservingPossible = true; //adjust property name for simple patterns String pName = this.functionParameters.get(Constants.SELECT_PARAM_PROPERTY_NAME).toString(); if (forSimplePattern) { if (pName.contains(".")) { //exclude event name pName = pName.substring(pName.indexOf(".") + 1); } } //pName.replaceAll(":", "__"); this.selectString = "max(" + pName + ")" + " as value"; } /* * SelectMin */ else if (this.functionName.equals(Constants.FUNC_SELECT_MIN_NAME)) { this.singleValueOutput = true; this.dataTypes.put(MapEvent.VALUE_KEY, Number.class); preservingPossible = true; //adjust property name for simple patterns String pName = this.functionParameters.get(Constants.SELECT_PARAM_PROPERTY_NAME).toString(); if (forSimplePattern) { if (pName.contains(".")) { //exclude event name pName = pName.substring(pName.indexOf(".") + 1); } } //pName.replaceAll(":", "__"); this.selectString = "min(" + pName + ")" + " as value"; } /* * SelectCount */ else if (this.functionName.equals(Constants.FUNC_SELECT_COUNT_NAME)) { this.singleValueOutput = true; this.dataTypes.put(MapEvent.VALUE_KEY, Integer.class); this.selectString = "count(*) as value"; //preserving not possible } /* * NotifyOnSelect */ else if (this.functionName.equals(Constants.FUNC_NOTIFY_ON_SELECT_NAME)) { this.singleValueOutput = true; this.dataTypes.put(MapEvent.VALUE_KEY, String.class); this.selectString = "\"" + this.functionParameters.get(Constants.SELECT_PARAM_MESSAGE_NAME) + "\" as value"; //preserving not possible } /* * SelectStdDev (user defined) */ else if (this.functionName.equals(Constants.FUNC_SELECT_STDDEV_NAME)) { this.singleValueOutput = true; this.dataTypes.put(MapEvent.VALUE_KEY, Number.class); //preserving not possible //adjust property name for simple patterns String pName = this.functionParameters.get(Constants.SELECT_PARAM_PROPERTY_NAME).toString(); if (forSimplePattern) { if (pName.contains(".")) { //exclude event name pName = pName.substring(pName.indexOf(".") + 1); } } //pName.replaceAll(":", "__"); this.selectString = "stddev(" + pName + ")" + " as value"; } /* * GetAdditiveInverseValue (user defined) */ else if (this.functionName.equals(Constants.FUNC_GET_ADD_INV_VALUE_NAME)) { int logcount = 0; SelFunction.logger.info("###### creating select string for 'get additive inverse value'"); this.singleValueOutput = true; preservingPossible = true; SelFunction.logger.info("####### " + logcount++);//0 //load property data type String fullPropertyName = this.fullPropertyNames.get(this.functionParameters.get(Constants.SELECT_PARAM_PROPERTY_NAME)); SelFunction.logger.info("####### " + logcount++);//1 Object dataType = this.controller.getDatatype(fullPropertyName); SelFunction.logger.info("####### " + logcount++);//2 this.dataTypes.put(MapEvent.VALUE_KEY, dataType); SelFunction.logger.info("####### property data type loaded: " + dataType.toString()); //adjust property name for simple patterns String pName = this.functionParameters.get(Constants.SELECT_PARAM_PROPERTY_NAME).toString(); if (forSimplePattern) { if (pName.contains(".")) { //exclude event name pName = pName.substring(pName.indexOf(".") + 1); } } //pName.replaceAll(":", "__"); SelFunction.logger.info("####### property name for simple patterns adjusted"); //get stream name from propertyName String streamName = fullPropertyName.substring(0, fullPropertyName.indexOf("/")); SelFunction.logger.info("####### stream name: " + streamName); //build select string if (dataType.equals(Number.class)) { this.selectString = "("+ streamName +"."+ MapEvent.DOUBLE_VALUE_KEY +" * -1) as value"; // this.selectString = "(input.observedProperty * -1) as value"; } else { this.selectString = "" + pName + " as value"; } SelFunction.logger.debug("####### the select string is: " + this.selectString); } /* * SelectDifference (user defined) */ else if (this.functionName.equals(Constants.FUNC_GET_DIFFERENCE)) { SelFunction.logger.info("##++## building select function for select difference"); //set singleValueOutput this.singleValueOutput = true; preservingPossible = true; //get references String firstReference = "" + this.functionParameters.get(Constants.SELECT_PARAM_1_NAME); String secondReference = "" + this.functionParameters.get(Constants.SELECT_PARAM_2_NAME); if (firstReference.equals("") || secondReference.equals("")) { //references not found SelFunction.logger.warn("references for user defined select function 'SelectDifference' not found"); return ""; } if (forSimplePattern) { //adjust references for simple pattern firstReference = firstReference.substring(firstReference.indexOf("/")); secondReference = secondReference.substring(secondReference.indexOf("/")); } //replace / by . firstReference = firstReference.replaceAll("/", "."); secondReference = secondReference.replaceAll("/", "."); this.selectString = "(" + firstReference + " - " + secondReference + ") as value"; SelFunction.logger.info("##++## select string: " + this.selectString); } /* * SelectFirst (user defined) * select prev(count(*) -1, value) as value from aEvent.win:time(60000 msec) */ else if (this.functionName.equals(Constants.FUNC_SELECT_FIRST)){ SelFunction.logger.info("##++## building select string for SelectFirst"); this.singleValueOutput = true; String property = "" + this.functionParameters.get(Constants.SELECT_PARAM_PROPERTY_NAME); if (property.equals("")) { SelFunction.logger.warn("property for user defined select function 'SelectFirst' not found"); return ""; } if (forSimplePattern) { if (property.contains(".")) { //exclude event name property = property.substring(property.indexOf(".") + 1); } } this.selectString = " prev(count(*)-1, " + property + ") as value"; SelFunction.logger.info("##++## select string: " + this.selectString); } else if (this.functionName.equals(DynamicSpatialBufferView.SELECTFUNCTION_NAME)) { /* * THE dynamic buffer for OWS-8+ */ this.selectString = DynamicSpatialBufferView.SELECT_STRING; this.allowOriginalMessageAsResult = DynamicSpatialBufferView.ALLOW_ORIGINAL_MESSAGE; } /* * parse additional select functions here */ } /* * select also inputs for causality creation */ if (this.createCausality) { if (forSimplePattern) { // if (!this.inputName.equals("")) { //causality for simple pattern this.selectString += ", * " + " as " + MapEvent.CAUSAL_ANCESTOR_1_KEY; } else if (!(this.inputReferences.size() < 1)) { //causality for complex or repetitive pattern PatternOutputReference ref = this.inputReferences.get(0); String eventName = ref.getNewEventName(); this.selectString += ", " + eventName + " as " + MapEvent.CAUSAL_ANCESTOR_1_KEY; if (this.inputReferences.size() > 1) { //also add the second ref = this.inputReferences.get(1); if (!eventName.equals(ref.getNewEventName())) { //ancestor 1 is not the same as ancestor 2 eventName = ref.getNewEventName(); this.selectString += ", " + eventName + " as " + MapEvent.CAUSAL_ANCESTOR_2_KEY; } } } /* * TODO: add selection of all ancestors here (view, ...) * SELECT * as MapEvent.CAUSAL_ANCESTORS should work */ } if (preservingPossible && forSimplePattern) { //more properties can be preserved boolean geometry = Boolean.parseBoolean(ConfigurationRegistry.getInstance().getPropertyForKey(ConfigurationRegistry.PRESERVE_GEOMETRY)); if (geometry) { //add geometry also this.selectString += ", " + MapEvent.GEOMETRY_KEY + " as " + MapEvent.GEOMETRY_KEY; } /* * add more here * * 1. go to ConfiguratioRegistry and create new property key * 2. go to SESProperties and enter as default value "false" */ } return this.selectString; } /** * @return the statement */ public String getStatement() { return this.statement; } /** * @param statement the statement to set */ public void setStatement(String statement) { this.statement = statement; } /** * @return the singleValueOutput */ public boolean isSingleValueOutput() { return this.singleValueOutput; } /** * @return the dataTypes */ public HashMap<String, Object> getDataTypes() { return this.dataTypes; } // /** // * @param inputName the inputName of the pattern (for simple patterns with causality) // */ // public void setInputName(String inputName) { // this.inputName = inputName; // } /** * @param inputReferences the inputReferences of a complex or repetitve pattern for the causality */ public void setInputReferences(Vector<PatternOutputReference> inputReferences) { this.inputReferences = inputReferences; } /** * @return true if it is allowed to return the original message as result */ public boolean allowsOriginalMessageAsResult() { return this.allowOriginalMessageAsResult; } /** * registers newEventName.doubleValue at the DataTypesMap if * should be. */ public void registerOutputProperties() { // if (this.functionName.equals(Constants.FUNC_SELECT_COUNT_NAME) || // this.functionName.equals(Constants.FUNC_SELECT_AVG_NAME) || // this.functionName.equals(Constants.FUNC_SELECT_MAX_NAME) || // this.functionName.equals(Constants.FUNC_SELECT_MIN_NAME) || // this.functionName.equals(Constants.FUNC_SELECT_STDDEV_NAME) || // this.functionName.equals(Constants.FUNC_SELECT_SUM_NAME)) { // // /* // * TODO: is this ok? value is then recognized as Double in every // * stream // */ // DataTypesMap.getInstance().registerNewDataType(this.newEventName+ "."+ MapEvent.DOUBLE_VALUE_KEY, Double.class); // //preserving not possible // } } }