/** * 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.esper; import java.util.Date; import java.util.Map; import org.n52.ses.eml.v001.Constants; import org.n52.ses.api.event.MapEvent; import org.n52.ses.api.event.MapEventFactory; import org.n52.ses.eml.v001.pattern.Statement; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.PropertyAccessException; import com.espertech.esper.event.map.MapEventBean; /** * Handles updates from a {@link StatementListener}. * * @author Thomas Everding * */ public class UpdateHandlerThread implements Runnable { /* * Logger instance for this class */ private static final Logger logger = LoggerFactory .getLogger(UpdateHandlerThread.class); private EsperController controller; private Statement statement; private EventBean bean; private boolean doOutput; private StatementListener listener; /** * * Constructor * * @param listener listener that received the update * @param bean the received update */ public UpdateHandlerThread(StatementListener listener, EventBean bean) { this.doOutput = listener.isDoOutput(); this.controller = listener.getController(); this.statement = listener.getStatement(); this.bean = bean; this.listener = listener; } @Override public void run() { if (logger.isDebugEnabled()) { logger.debug("Update received for statement: " + this.statement.getStatement()); } // logger.info("bean type: " + bean.getClass().getName()); // logger.info("undelying type: " + bean.getUnderlying().getClass().getName()); //build new event MapEvent event = null; if (this.bean instanceof MapEventBean) { MapEventBean selected = (MapEventBean) this.bean; String[] propertyNames = selected.getEventType().getPropertyNames(); // StringBuilder log = new StringBuilder(); // log.append("selected event properties."); // for (String key : propertyNames) { // log.append("\n\t" + key); // } // logger.info(log.toString()); if (propertyNames.length > 1) { event = createEventFromComplexSelect(selected); } else if (propertyNames.length == 1){ event = createEventFromSimpleSelect(event, propertyNames[0]); } else { // logger.info("will create event from simple select"); event = createEventFromSimpleSelect(event); } } else { // logger.info("will create event from complex select with null event"); event = createEventFromSimpleSelect(event); } if (event == null) { //still nothing selected... UpdateHandlerThread.logger.warn("no result generated from pattern update"); return; } /* * add original message */ if (this.bean.getUnderlying() instanceof Map<?, ?>) { // logger.info("adding original message from Map<?, ?>"); Map<?, ?> alert = (Map<?, ?>) this.bean.getUnderlying(); Object message = alert.get(MapEvent.ORIGNIAL_MESSAGE_KEY); if (message != null) { event.put(MapEvent.ORIGNIAL_MESSAGE_KEY, message); } } // //create causality if wanted // if (this.statement.getSelectFunction().getCreateCausality()) { // logger.info("creating causality"); // logger.info("underl: " + bean.getUnderlying().getClass().getName()); // // StringBuilder log = new StringBuilder(); // log.append("if map then content:"); // if (bean.getUnderlying() instanceof HashMap) { // HashMap map = (HashMap) bean.getUnderlying(); // for (Object key : map.keySet()) { // log.append("\n\t" + key.toString() + ": " + map.get(key)); // } // } // logger.info(log.toString()); // // log = new StringBuilder(); // log.append("result event:"); // for (String key : event.keySet()) { // log.append("\n\t" + key + ": " + event.get(key)); // } // logger.info(log.toString()); // // //TODO: identify what is done next, dies somewhere here... // // if (bean.getUnderlying() instanceof MapEvent) { // logger.info("undelying is a map event!"); // //select event performed? // MapEvent underlying = (MapEvent) bean.getUnderlying(); // // logger.info("underlying map event: " + underlying); // // Vector<MapEvent> underlyingCausality = (Vector<MapEvent>) underlying.get(MapEvent.CAUSALITY_KEY); // // //add causality of underlying event // logger.info("undelying events: " + underlyingCausality.size()); // for (MapEvent e : underlyingCausality) { // event.addCausalAncestor(e); // } // // //add underlying event to causality // event.addCausalAncestor(underlying); // } // else if (bean.getUnderlying() instanceof HashMap) { // logger.info("undelying is a hash map"); // HashMap<?, ?> map = (HashMap<?, ?>) bean.getUnderlying(); // // log = new StringBuilder(); // log.append("undelying values:"); // for (Object key : map.keySet()) { // log.append("\n\t" + key.toString() + ": " + map.get(key).toString() + " (" + map.get(key).getClass().getName() + ")"); // } // logger.info(log.toString()); // // //notify on select performed? // EPStatement epStatement = this.controller.getEPStatement(this.statement.getStatement()); // if (epStatement != null) { // logger.info("ep statement available"); // Object obj = epStatement.getUserObject(); // if (obj != null) { // logger.info("user object: " + obj.getClass().getName()); // } // else { // logger.info("user object is null"); // } // } // // EPRuntime epRuntime = this.controller.getEpService().getEPRuntime(); // Map<String, Object> values = epRuntime.getVariableValueAll(); // // log = new StringBuilder(); // log.append("runtime variable values:"); // // for (String key : values.keySet()) { // log.append("\n\t" + key + ": " + values.get(key).toString() + " (" + values.get(key).getClass().getName() + ")"); // } // logger.info(log.toString()); // // Context context = this.controller.getEpService().getContext(); // try { // logger.info("context results for name 'arrival': " + context.lookup("arrival")); // } // catch (NamingException e) { // e.printStackTrace(); // } // } // } try { //send event to esper engine for further processing if (!this.statement.getSelectFunction().getNewEventName().equals("")) { this.controller.sendEvent(this.statement.getSelectFunction().getNewEventName(), event); } //if output=true send event to output if (this.doOutput) { if (logger.isDebugEnabled()) logger.debug("performing output for this match"); this.listener.doOutput(event); } } catch (Throwable e) { //log exception UpdateHandlerThread.logger.warn(e.getMessage()); StringBuilder log = new StringBuilder(); for (StackTraceElement ste : e.getStackTrace()) { log.append("\n" + ste.toString()); } UpdateHandlerThread.logger.warn(log.toString()); //forward exception throw new RuntimeException(e); } } /** * generates a new {@link MapEvent} from a selection with multiple values * @param meBean the selected {@link MapEventBean} * @return the new map event */ private MapEvent createEventFromComplexSelect(MapEventBean meBean) { //event selected Map<String, Object> properties = meBean.getProperties(); return parseEventFromMap(properties); } private MapEvent parseEventFromMap(Map<String, Object> properties) { return MapEventFactory.parseFromMap(properties, this.statement.getSelectFunction().getCreateCausality()); // StringBuilder log = new StringBuilder(); // log.append("parsing MapEvent from Map"); // log.append("\n\tproperties:"); // for (String key : properties.keySet()) { // log.append("\n\t" + key); // } // this.logger.info(log.toString()); // long start; // long end; // if (properties.containsKey(MapEvent.START_KEY)) { // start = Long.parseLong(properties.get(MapEvent.START_KEY).toString()); // } // else { // start = new Date().getTime(); // } // // if (properties.containsKey(MapEvent.END_KEY)) { // end = Long.parseLong(properties.get(MapEvent.END_KEY).toString()); // if (start > end) { // end = start; // } // } // else { // end = start; // } // // MapEvent event = new MapEvent(start, end); // // //copy content // for (String key : properties.keySet()) { // if (key.equals(MapEvent.START_KEY) || key.equals(MapEvent.END_KEY)) { // //already copied // } // else if (key.equals(MapEvent.THIS_KEY)) { // //ignore to prevent recursions // } // else if (key.equals(MapEvent.CAUSALITY_KEY)) { // if (this.statement.getSelectFunction().getCreateCausality()) { // //copy causality // Vector<MapEvent> causality = (Vector<MapEvent>) properties.get(key); // // for (MapEvent ancestor : causality) { // event.addCausalAncestor(ancestor); // } // } // } // else if (key.equals(MapEvent.CAUSAL_ANCESTOR_1_KEY) || key.equals(MapEvent.CAUSAL_ANCESTOR_2_KEY)) { // if (this.statement.getSelectFunction().getCreateCausality()) { // //add causal ancestors //// logger.info("causal ancestor from pattern select found. type: " + properties.get(key).getClass().getName()); // // if (properties.get(key) instanceof HashMap<?, ?>) { // MapEvent ancestorEvent = this.parseEventFromMap((Map<String, Object>) properties.get(key)); // event.addCausalAncestor(ancestorEvent); // } // else if (properties.get(key) instanceof MapEvent) { // event.addCausalAncestor((MapEvent) properties.get(key)); // } // else if (properties.get(key) instanceof MapEventBean) { // MapEventBean ancestorBean = (MapEventBean) properties.get(key); // event.addCausalAncestor(this.parseEventFromMap(ancestorBean.getProperties())); // } // } // } // else { // if (key.equals(MapEvent.VALUE_KEY) && (properties.get(key) instanceof MapEventBean)) { // /* // * select event with causality should end up here // * -> recursive call // */ // MapEventBean valueBean = (MapEventBean) properties.get(key); // event.put(key, this.parseEventFromMap(valueBean.getProperties())); // } // else { // //fallback / usual: just put it into the result // event.put(key, properties.get(key)); // } // } // } //// logger.info("Event parsed from map:\n" + event); // return event; } /** * generates a new MapEvent from the selection of a single value * @param event the selected event bean * @return the new map event */ private MapEvent createEventFromSimpleSelect(MapEvent event) { return this.createEventFromSimpleSelect(event, MapEvent.VALUE_KEY); } /** * generates a new MapEvent from the selection of a single value * @param event the selected event bean * @param propertyName the name of the only property * @return the new map event */ private MapEvent createEventFromSimpleSelect(MapEvent event, String propertyName) { Date now = new Date(); MapEvent result = null; try { // no event selected, use only the property 'value' Object obj = this.bean.get(propertyName); if (obj == null) { UpdateHandlerThread.logger.info("returning null, no value for property '" + propertyName + "'"); return null; } //check for timer events if (obj.equals(Constants.TIMER_EVENT_VALUE)) { //timer event caught result = new MapEvent(now.getTime(), now.getTime()); result.put(MapEvent.VALUE_KEY, now.getTime()); } else { //handle object as usual result = new MapEvent(now.getTime(), now.getTime()); result.put(MapEvent.VALUE_KEY, obj); } } catch (PropertyAccessException ex) { //no event property name value found UpdateHandlerThread.logger.warn(ex.getMessage()); } catch (Throwable t) { UpdateHandlerThread.logger.warn(t.getMessage()); } return result; } }