/**
* 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.v001.filterlogic;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Vector;
import net.opengis.eml.x001.AbstractGuardedViewPatternType;
import net.opengis.eml.x001.AbstractPatternType;
import net.opengis.eml.x001.AbstractViewPatternType;
import net.opengis.eml.x001.EventAttributeType;
import net.opengis.eml.x001.GuardType;
import net.opengis.eml.x001.RepetitivePatternType;
import net.opengis.eml.x001.SelectFunctionType;
import net.opengis.eml.x001.SimplePatternType;
import net.opengis.eml.x001.TimerPatternType;
import net.opengis.eml.x001.UserDefinedOperatorType;
import net.opengis.eml.x001.UserParameterType;
import net.opengis.eml.x001.ViewType;
import net.opengis.eml.x001.ComplexPatternDocument.ComplexPattern;
import net.opengis.eml.x001.ComplexPatternType.Logicaloperator;
import net.opengis.eml.x001.ComplexPatternType.StructuralOperator;
import net.opengis.eml.x001.EMLDocument.EML;
import net.opengis.eml.x001.SelectFunctionType.NotifyOnSelect;
import net.opengis.eml.x001.SelectFunctionType.SelectAvg;
import net.opengis.eml.x001.SelectFunctionType.SelectEvent;
import net.opengis.eml.x001.SelectFunctionType.SelectMax;
import net.opengis.eml.x001.SelectFunctionType.SelectMin;
import net.opengis.eml.x001.SelectFunctionType.SelectProperty;
import net.opengis.eml.x001.SelectFunctionType.SelectSum;
import net.opengis.eml.x001.SelectFunctionType.UserDefinedSelectFunction;
import net.opengis.eml.x001.TimerPatternType.TimerAt;
import net.opengis.eml.x001.ViewType.LengthView;
import net.opengis.eml.x001.ViewType.TimeLengthView;
import net.opengis.eml.x001.ViewType.TimeView;
import net.opengis.eml.x001.ViewType.UserDefinedView;
import org.apache.xmlbeans.GDuration;
import org.n52.ses.api.eml.ILogicController;
import org.n52.ses.eml.v001.Constants;
import org.n52.ses.eml.v001.pattern.AGuardedViewPattern;
import org.n52.ses.eml.v001.pattern.APattern;
import org.n52.ses.eml.v001.pattern.AViewPattern;
import org.n52.ses.eml.v001.pattern.DataView;
import org.n52.ses.eml.v001.pattern.PatternComplex;
import org.n52.ses.eml.v001.pattern.PatternGuard;
import org.n52.ses.eml.v001.pattern.PatternOperator;
import org.n52.ses.eml.v001.pattern.PatternOutputReference;
import org.n52.ses.eml.v001.pattern.PatternRepetitive;
import org.n52.ses.eml.v001.pattern.PatternSimple;
import org.n52.ses.eml.v001.pattern.PatternTimer;
import org.n52.ses.eml.v001.pattern.PropRestriction;
import org.n52.ses.eml.v001.pattern.SelFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* parses an EML file and generates an esper controller
*
* @author Thomas Everding
*
*/
public class EMLParser {
private HashMap<String, APattern> patterns;
private ILogicController controller;
private static final Logger logger = LoggerFactory
.getLogger(EMLParser.class);
/**
*
* Constructor
*
* @param controller controller of this process
*
*/
public EMLParser(ILogicController controller) {
this.patterns = new HashMap<String, APattern>();
this.controller = controller;
}
/**
* parses an EML document and creates an esper controller
*
* @param eml the EML document
*/
public void parseEML(EML eml) {
EMLParser.logger.info("parsing EML document");
/*
* parse simple patterns
*/
SimplePatternType[] sPatterns = eml.getSimplePatterns().getSimplePatternArray();
for (SimplePatternType pattern : sPatterns) {
//parse pattern
this.parseSimplePattern(pattern);
}
/*
* parse complex patterns
*/
ComplexPattern[] cPatterns = eml.getComplexPatterns().getComplexPatternArray();
for (ComplexPattern pattern : cPatterns) {
//parse pattern
this.parseComplexPattern(pattern);
}
/*
* parse timer patterns
*/
TimerPatternType[] tPatterns = eml.getTimerPatterns().getTimerPatternArray();
for (TimerPatternType pattern : tPatterns) {
//parse pattern
this.parseTimerPattern(pattern);
}
/*
* parse repetitive patterns
*/
RepetitivePatternType[] rPatterns = eml.getRepetitivePatterns().getRepetitivePatternArray();
for (RepetitivePatternType pattern : rPatterns) {
//parse pattern
this.parseRepetitivePattern(pattern);
}
}
/**
* parses a simple patterns
*
* @param pattern the pattern to parse
*/
private void parseSimplePattern(SimplePatternType pattern) {
//create representation
PatternSimple simplePattern = new PatternSimple(this.controller);
/*
* parse SimplePattern content
*/
//set input name
simplePattern.setInputName(pattern.getInputName().toString()
.replaceAll(":", "__").replaceAll("\\.", "_"));
//set property restrictions
if (pattern.getPropertyRestrictions().getPropertyRestrictionArray().length > 0) {
EventAttributeType[] restrictions = pattern.getPropertyRestrictions().getPropertyRestrictionArray();
for (EventAttributeType restr : restrictions) {
simplePattern.addPropertyRestriction(this.parsePropertyRestriction(restr, simplePattern.getPropertyNames()));
}
}
/*
* parse derived content
*/
//parse AbstractPatternType content
this.parsePattern(simplePattern, pattern);
//parse AbstractViewPattern
this.parseViewPattern(simplePattern, pattern);
//parse AbstractGuardedViewPattern
this.parseGuardedViewPattern(simplePattern, pattern);
/*
* store simple pattern
*/
this.patterns.put(simplePattern.getPatternID(), simplePattern);
}
/**
* parses a complex pattern
*
* @param pattern the pattern to parse
*/
private void parseComplexPattern(ComplexPattern pattern) {
//create representation
PatternComplex complexPattern = new PatternComplex();
/*
* parse complex pattern content
*/
//set operator
complexPattern.setOperator(this.parsePatternOperator(pattern));
//set first pattern ID
complexPattern.setFirstPatternID(pattern.getFirstPattern().getPatternReference().trim());
//set select function to use
complexPattern.setFirstSelectFunctionNumber(pattern.getFirstPattern().getSelectFunctionNumber());
//set second pattern
complexPattern.setSecondPatternID(pattern.getSecondPattern().getPatternReference().trim());
//set select function to use
complexPattern.setSecondSelectFunctionNumber(pattern.getSecondPattern().getSelectFunctionNumber());
//set controller reference
complexPattern.setController(this.controller);
//set maximum listening duration
if (pattern.isSetMaximumListeningDuration()) {
complexPattern.setMaxListeningDuration(this.parseTimerDuration(pattern.getMaximumListeningDuration()));
}
/*
* parse derived content
*/
//parse AbstractPatternType content
this.parsePattern(complexPattern, pattern);
//parse AbstractViewPattern
this.parseViewPattern(complexPattern, pattern);
//parse AbstractGuardedViewPattern
this.parseGuardedViewPattern(complexPattern, pattern);
/*
* store complex pattern
*/
this.patterns.put(complexPattern.getPatternID(), complexPattern);
}
/**
* parses a timer pattern
*
* @param pattern the pattern to parse
*/
private void parseTimerPattern(TimerPatternType pattern) {
//create representation
PatternTimer timerPattern = new PatternTimer();
/*
* parse timer pattern content
*/
if (pattern.isSetTimerInterval()) {
//interval timer
timerPattern.setInterval(true);
//set duration
timerPattern.setDuration(this.parseTimerDuration(pattern.getTimerInterval()));
}
else {
//at timer
timerPattern.setInterval(false);
//set second,
TimerAt t = pattern.getTimerAt();
if (t.isSetSecond()) {
timerPattern.setSecond(t.getSecond());
}
//minute,
if (t.isSetMinute()) {
timerPattern.setMinute(t.getMinute());
}
//hour,
if (t.isSetHour()) {
timerPattern.setHour(t.getHour());
}
//weekday,
if (t.isSetDayOfWeek()) {
timerPattern.setDayOfWeek(t.getDayOfWeek());
}
//day of month,
if (t.isSetDayOfMonth()) {
timerPattern.setDayOfMonth(t.getDayOfMonth());
}
//and month
if (t.isSetMonth()) {
timerPattern.setMonth(t.getMonth());
}
}
/*
* parse derived content
*/
//parse AbstractPatternType content
this.parsePattern(timerPattern, pattern);
//parse AbstractViewPattern
this.parseViewPattern(timerPattern, pattern);
/*
* store timer pattern
*/
this.patterns.put(timerPattern.getPatternID(), timerPattern);
}
/**
* parses a repetivite pattern
*
* @param pattern
*/
private void parseRepetitivePattern(RepetitivePatternType pattern) {
//create representation
PatternRepetitive repetitivePattern = new PatternRepetitive();
/*
* parse repetitive pattern content
*/
//set event count
repetitivePattern.setRepetitionCount(pattern.getEventCount().intValue());
//set pattern to repeat
repetitivePattern.setPatternToRepeatID(pattern.getPatternToRepeat().getPatternReference().trim());
//set select function to use
repetitivePattern.setSelectFunctionToUse(pattern.getPatternToRepeat().getSelectFunctionNumber());
//set controller
repetitivePattern.setController(this.controller);
/*
* parse derived content
*/
//parse AbstractPatternType content
this.parsePattern(repetitivePattern, pattern);
/*
* store repetitive pattern
*/
this.patterns.put(repetitivePattern.getPatternID(), repetitivePattern);
}
/**
* parses the content of AbstractPatterns
*
* @param representation internal representation of the pattern
* @param bean bean of the pattern
*/
private void parsePattern(APattern representation, AbstractPatternType bean) {
/*
* set pattern ID
*/
representation.setPatternID(bean.getPatternID().trim());
/*
* set description
*/
if (bean.isSetPatternDescription()) {
representation.setDescription(bean.getPatternDescription());
}
/*
* set select functions
*/
//first get input names
//TODO this only adds the last events from a set (view) as causal ancestor
Object inputNames = null;
if (representation instanceof PatternSimple) {
//get input name defined in pattern as input names
inputNames = ((PatternSimple)representation).getInputName();
}
else if (representation instanceof PatternComplex) {
//get the new event names of the two source patterns as input names
Vector<PatternOutputReference> vec = new Vector<PatternOutputReference>(2);
PatternComplex cp = (PatternComplex) representation;
vec.add(new PatternOutputReference(cp.getFirstSelectFunctionNumber(), cp.getFirstPatternID(), this.controller));
vec.add(new PatternOutputReference(cp.getSecondSelectFunctionNumber(), cp.getSecondPatternID(), this.controller));
inputNames = vec;
}
else if (representation instanceof PatternRepetitive) {
//get the event to count as input name
Vector<PatternOutputReference> vec = new Vector<PatternOutputReference>(1);
PatternRepetitive rp = (PatternRepetitive) representation;
vec.add(new PatternOutputReference(rp.getSelectFunctionNumber(), rp.getPatternToRepeatID(), this.controller));
inputNames = vec;
}
//no input names for timer patterns, causality does not make sense there
if (bean.getSelectFunctions().getSelectFunctionArray().length > 0) {
SelectFunctionType[] selFunctions = bean.getSelectFunctions().getSelectFunctionArray();
for (SelectFunctionType selectFunction : selFunctions) {
HashSet<Object> pn = representation.getPropertyNames();
SelFunction sf = this.parseSelectFunction(selectFunction, pn, inputNames);
representation.addSelectFunction(sf);
}
}
}
/**
* parses the content of AbstractViewPatterns
*
* @param representation internal representation of the pattern
* @param bean bean of the pattern
*/
private void parseViewPattern(AViewPattern representation, AbstractViewPatternType bean) {
//set view
if (bean.isSetView()) {
representation.setView(this.parseView(bean.getView()));
}
else {
//all view as standard
DataView view = new DataView();
view.setViewName(Constants.VIEW_ALL_NAME);
representation.setView(view);
}
}
/**
* parses the content of AbstractGuardedViewPatterns
*
* @param representation internal representation of the pattern
* @param bean bean of the pattern
*/
private void parseGuardedViewPattern(AGuardedViewPattern representation, AbstractGuardedViewPatternType bean) {
//set guard
if (bean.isSetGuard()) {
representation.setGuard(this.parseGuard(bean.getGuard(), representation.getPropertyNames()));
}
}
/**
* parses a single select function
*
* @return an internal representation for the select function
*/
@SuppressWarnings("unchecked")
private SelFunction parseSelectFunction(SelectFunctionType selectFunction, HashSet<Object> propertyNames, Object inputNames) {
SelFunction result = new SelFunction(this.controller);
/*
* parse the select function standard properties
*/
//set the newEventName
result.setNewEventName(selectFunction.getNewEventName()
.replaceAll(":", "__").replaceAll("\\.", "_"));
//set output name
if (selectFunction.isSetOutputName()) {
result.setOutputName(selectFunction.getOutputName().trim());
}
//set create causality
if (selectFunction.isSetCreateCausality()) {
result.setCreateCausality(selectFunction.getCreateCausality());
//set inputs for causal ancestors
if (inputNames != null) {
if (inputNames instanceof Vector<?>) {
result.setInputReferences((Vector<PatternOutputReference>) inputNames);
}
// else if (inputNames instanceof String) {
// result.setInputName((String) inputNames);
// }
}
}
/*
* parse the function itself and its parameters
*/
//check SelectEvent
if (selectFunction.isSetSelectEvent()) {
result.setFunctionName(Constants.FUNC_SELECT_EVENT_NAME);
SelectEvent se = selectFunction.getSelectEvent();
result.addFunctionParameter(Constants.SELECT_PARAM_EVENT_NAME, se.getEventName());
}
//check SelectProperty
else if (selectFunction.isSetSelectProperty()) {
result.setFunctionName(Constants.FUNC_SELECT_PROPERTY_NAME);
SelectProperty sp = selectFunction.getSelectProperty();
result.addFunctionParameter(Constants.SELECT_PARAM_PROPERTY_NAME, sp.getPropertyName());
if (!propertyNames.contains(sp.getPropertyName())) {
propertyNames.add(sp.getPropertyName());
}
}
//check SelectSum
else if (selectFunction.isSetSelectSum()) {
result.setFunctionName(Constants.FUNC_SELECT_SUM_NAME);
SelectSum sum = selectFunction.getSelectSum();
result.addFunctionParameter(Constants.SELECT_PARAM_PROPERTY_NAME, sum.getPropertyName());
if (!propertyNames.contains(sum.getPropertyName())) {
propertyNames.add(sum.getPropertyName());
}
}
//check SelectAvg
else if (selectFunction.isSetSelectAvg()) {
result.setFunctionName(Constants.FUNC_SELECT_AVG_NAME);
SelectAvg avg = selectFunction.getSelectAvg();
result.addFunctionParameter(Constants.SELECT_PARAM_PROPERTY_NAME, avg.getPropertyName());
if (!propertyNames.contains(avg.getPropertyName())) {
propertyNames.add(avg.getPropertyName());
}
}
//check SelectMax
else if (selectFunction.isSetSelectMax()) {
result.setFunctionName(Constants.FUNC_SELECT_MAX_NAME);
SelectMax max = selectFunction.getSelectMax();
result.addFunctionParameter(Constants.SELECT_PARAM_PROPERTY_NAME, max.getPropertyName());
if (!propertyNames.contains(max.getPropertyName())) {
propertyNames.add(max.getPropertyName());
}
}
//check SelectMin
else if (selectFunction.isSetSelectMin()) {
result.setFunctionName(Constants.FUNC_SELECT_MIN_NAME);
SelectMin min = selectFunction.getSelectMin();
result.addFunctionParameter(Constants.SELECT_PARAM_PROPERTY_NAME, min.getPropertyName());
if (!propertyNames.contains(min.getPropertyName())) {
propertyNames.add(min.getPropertyName());
}
}
//check SelectCount
else if (selectFunction.isSetSelectCount()) {
result.setFunctionName(Constants.FUNC_SELECT_COUNT_NAME);
}
//check NotifyOnSelect
else if (selectFunction.isSetNotifyOnSelect()) {
result.setFunctionName(Constants.FUNC_NOTIFY_ON_SELECT_NAME);
NotifyOnSelect nos = selectFunction.getNotifyOnSelect();
result.addFunctionParameter(Constants.SELECT_PARAM_MESSAGE_NAME, nos.getMessage());
}
//else user defined function
else {
EMLParser.logger.info("parsing user defined sel function");
UserDefinedSelectFunction udsf = selectFunction.getUserDefinedSelectFunction();
result.setFunctionName(udsf.getName());
UserParameterType[] parameters = udsf.getFunctionParameters().getFunctionParameterArray();
for (UserParameterType param : parameters) {
result.addFunctionParameter(param.getUserParameterName(), param.getUserParameterValue());
}
}
return result;
}
/**
* parses a view
*
* @param view
* @return an internal representation for the view
*/
private DataView parseView(ViewType view) {
DataView result = new DataView();
/*
* parse view
*/
//check LengthView
if (view.isSetLengthView()) {
result.setViewName(Constants.VIEW_LENGTH_NAME);
LengthView lv = view.getLengthView();
if (lv.isSetIsBatch()) {
result.setBatch(lv.getIsBatch());
}
result.addParameter(Constants.VIEW_PARAM_EVENT_COUNT_NAME, lv.getEventCount());
}
//check TimeView
else if (view.isSetTimeView()) {
result.setViewName(Constants.VIEW_TIME_NAME);
TimeView tv = view.getTimeView();
if (tv.isSetIsBatch()) {
result.setBatch(tv.getIsBatch());
}
result.addParameter(Constants.VIEW_PARAM_DURATION_NAME, this.parseTimerDuration(tv.getDuration()));
}
//check TimeLengthView
else if (view.isSetTimeLengthView()) {
result.setViewName(Constants.VIEW_TIME_LENGTH_NAME);
TimeLengthView tlv = view.getTimeLengthView();
if (tlv.isSetIsBatch()) {
result.setBatch(tlv.getIsBatch());
}
result.addParameter(Constants.VIEW_PARAM_EVENT_COUNT_NAME, tlv.getEventCount());
result.addParameter(Constants.VIEW_PARAM_DURATION_NAME, this.parseTimerDuration(tlv.getDuration()));
}
//check AllView
else if (view.isSetAllView()) {
result.setViewName(Constants.VIEW_ALL_NAME);
}
//else user defined view
else {
UserDefinedView udv = view.getUserDefinedView();
result.setViewName(udv.getName());
UserParameterType[] parameters = udv.getViewParameters().getViewParameterArray();
for (UserParameterType param : parameters) {
result.addParameter(param.getUserParameterName(), param.getUserParameterValue());
}
}
return result;
}
/**
* parses a guard
*
* @param guard
* @return an internal representation for the guard
*/
private PatternGuard parseGuard(GuardType guard, HashSet<Object > propertyNames) {
PatternGuard result = new PatternGuard();
result.setFilter(guard.getFilter(), propertyNames);
return result;
}
/**
* parses a property restriction
*
* @param restriction
* @return an internal representation for the property restriction
*/
private PropRestriction parsePropertyRestriction(EventAttributeType restriction, HashSet<Object> propertyNames) {
PropRestriction result = new PropRestriction();
//property name
String propName = restriction.getName().trim();
/*
* parse
* "<EventName>/<PropName>/<NestedPropName>"
* to
* "<PropName>.<NestedPropName>"
*
* (nested names are optional,
* event name and at least one
* property name are mandatory)
*/
propName = propName.substring(propName.indexOf("/") + 1);
propName = propName.replaceAll("/", ".");
result.setName(propName);
if (!propertyNames.contains(propName)) {
propertyNames.add(propName);
}
//property value
String valueString = restriction.getValue().toString();
//TODO: parse SWE Common
try {
//cut of start
int index = valueString.indexOf(">");
valueString = valueString.substring(index + 1);
//cut of end
index = valueString.lastIndexOf("<");
valueString = valueString.substring(0, index);
result.setValue("\"" + valueString + "\"");
}
catch (Exception ex) {
result.setValue("");
}
// String[] segments = valueString.split(SWE_VALUE_TAG);
// if (segments.length == 2) {
// result.setValue(segments[1].split("</")[0]);
// }
// else {
// result.setValue("");
// }
return result;
}
/**
* parses the complex pattern operator
*
* @param pattern
* @return an internal representation for the operator
*/
private PatternOperator parsePatternOperator(ComplexPattern pattern) {
PatternOperator result = new PatternOperator();
/*
* parse structural operators
*/
if (pattern.isSetStructuralOperator()) {
StructuralOperator so = pattern.getStructuralOperator();
//CAUSE
if (so.isSetCAUSE()) {
result.setName(Constants.OPERATOR_CAUSE_NAME);
}
//PARALLEL
else if (so.isSetPARALLEL()) {
result.setName(Constants.OPERATOR_PARALLEL_NAME);
}
//BEFORE
else {
result.setName(Constants.OPERATOR_BEFORE_NAME);
}
}
/*
* parse logical operators
*/
else if (pattern.isSetLogicaloperator()) {
Logicaloperator lo = pattern.getLogicaloperator();
//AND
if (lo.isSetAND()) {
result.setName(Constants.OPERATOR_AND_NAME);
}
//AND_NOT
else if (lo.isSetANDNOT()) {
result.setName(Constants.OPERATOR_AND_NOT_NAME);
}
//OR
else {
result.setName(Constants.OPERATOR_OR_NAME);
}
}
/*
* parse user defined operators
*/
else {
//user defined
UserDefinedOperatorType uop = pattern.getUserDefindeBinaryOperator();
result.setName(uop.getName());
}
return result;
}
/**
* parses a xs:duration to long(ms)
*
* @param timerInterval xs:duration
* @return long(ms)
*/
private long parseTimerDuration(GDuration timerInterval) {
long result = 0;
//years
result += timerInterval.getYear() * 365 * 24 * 60 * 60 * 1000;
//months
result += timerInterval.getMonth() * 30 * 24 * 60 * 60 * 1000;
//days
result += timerInterval.getDay() * 24 * 60 * 60 * 1000;
//hours
result += timerInterval.getHour() * 60 * 60 * 1000;
//minutes
result += timerInterval.getMinute() * 60 * 1000;
//seconds
result += timerInterval.getSecond() * 1000;
//fraction of second
result += timerInterval.getFraction().multiply(new BigDecimal(1000)).longValue();
return result;
}
/**
* @return the parsed patterns
*/
public HashMap<String, APattern> getPatterns() {
return this.patterns;
}
}