package eu.play_project.dcep.distributedetalis;
import static eu.play_project.dcep.constants.DcepConstants.LOG_DCEP_FAILED_EXIT;
import static eu.play_project.play_commons.constants.Event.DATE_FORMAT_8601;
import static eu.play_project.play_commons.constants.Event.EVENT_ID_PLACEHOLDER;
import static eu.play_project.play_commons.constants.Event.EVENT_ID_SUFFIX;
import static eu.play_project.play_commons.constants.Namespace.EVENTS;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.event_processing.events.types.Event;
import org.ontoware.rdf2go.impl.jena.TypeConversion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.NodeFactory;
import com.jtalis.core.event.EtalisEvent;
import com.jtalis.core.event.JtalisOutputEventProvider;
import eu.play_project.dcep.constants.DcepConstants;
import eu.play_project.dcep.distributedetalis.api.EcConnectionManager;
import eu.play_project.dcep.distributedetalis.api.HistoricalDataEngine;
import eu.play_project.dcep.distributedetalis.api.SimplePublishApi;
import eu.play_project.dcep.distributedetalis.api.VariableBindings;
import eu.play_project.dcep.distributedetalis.join.Engine;
import eu.play_project.dcep.distributedetalis.measurement.MeasurementUnit;
import eu.play_project.play_commons.constants.Source;
import eu.play_project.play_commons.eventtypes.EventHelpers;
import eu.play_project.play_platformservices.api.BdplQuery;
import eu.play_project.play_platformservices.api.HistoricalData;
import fr.inria.eventcloud.api.CompoundEvent;
import fr.inria.eventcloud.api.Quadruple;
public class JtalisOutputProvider implements JtalisOutputEventProvider, Serializable {
private static final long serialVersionUID = 100L;
private static Logger logger = LoggerFactory.getLogger(JtalisOutputProvider.class);
MeasurementUnit measurementUnit;
boolean shutdownEtalis = false; // If true ETALIS will shutdown.
private final PlayJplEngineWrapper engine;
private final Set<SimplePublishApi> recipients;
private final Map<String, BdplQuery> registeredQueries;
private final HistoricalDataEngine historicData;
private final static Node STARTTIME = TypeConversion.toJenaNode(Event.STARTTIME);
private final static Node ENDTIME = TypeConversion.toJenaNode(Event.ENDTIME);
private final static Node EVENTPATTERN = TypeConversion.toJenaNode(Event.EVENTPATTERN);
private final static Node SOURCE = TypeConversion.toJenaNode(Event.SOURCE);
private final static String PATTERN_BASE_URI = DcepConstants.getProperties().getProperty("platfomservices.querydispatchapi.rest");
public JtalisOutputProvider(Set<SimplePublishApi> recipients, Map<String, BdplQuery> registeredQueries, EcConnectionManager ecConnectionManager, MeasurementUnit measurementUnit) {
this.engine = PlayJplEngineWrapper.getPlayJplEngineWrapper();
this.recipients = recipients;
this.registeredQueries = registeredQueries;
this.historicData = new Engine(ecConnectionManager);
this.measurementUnit = measurementUnit;
}
@Override
public void setup() {
}
@Override
public void shutdown() {
shutdownEtalis = true;
}
@Override
public void outputEvent(EtalisEvent event) {
try {
System.out.println(event);
List<Quadruple> quadruples = this.getEventData(engine, event);
// Publish complex event
CompoundEvent result = new CompoundEvent(quadruples);
measurementUnit.eventProduced(result, event.getName());
if(recipients.size() < 1) {
logger.warn(LOG_DCEP_FAILED_EXIT + "No recipients for complex events.");
}
for (SimplePublishApi recipient : recipients) {
recipient.publish(result);
}
} catch (RetractEventException e) {
logger.info(LOG_DCEP_FAILED_EXIT + "Retract ... an event was not created because its historic part was not fulfilled.");
} catch (Exception e) {
logger.error(LOG_DCEP_FAILED_EXIT + "Exception appeared: " + e.getMessage(), e);
}
}
/**
* Get event data from Prolog and Event Cloud.
*/
public List<Quadruple> getEventData(PlayJplEngineWrapper engine, EtalisEvent event) throws RetractEventException {
List<Quadruple> quadruples = new ArrayList<Quadruple>();
String eventId = EVENTS.getUri() + event.getProperty(0).toString();
final Node GRAPHNAME = NodeFactory.createURI(eventId);
final Node EVENTID = NodeFactory.createURI(eventId + EVENT_ID_SUFFIX);
/*
* Add implicit values from Jtalis to each event:
*/
quadruples.add(new Quadruple(
GRAPHNAME,
EVENTID,
EVENTPATTERN,
//Node.createURI(DcepConstants.getProperties().getProperty("platfomservices.querydispatchapi.rest") + event.getRuleID()))); // FIXME sobermeier
NodeFactory.createURI(PATTERN_BASE_URI + event.getStringProperty(1))));
quadruples.add(new Quadruple(
GRAPHNAME,
EVENTID,
STARTTIME,
NodeFactory.createLiteral(
DateFormatUtils.format(event.getTimeStarts(), DATE_FORMAT_8601),
XSDDatatype.XSDdateTime)));
quadruples.add(new Quadruple(
GRAPHNAME,
EVENTID,
ENDTIME,
NodeFactory.createLiteral(
DateFormatUtils.format(event.getTimeEnds(), DATE_FORMAT_8601),
XSDDatatype.XSDdateTime)));
quadruples.add(new Quadruple(
GRAPHNAME,
EVENTID,
SOURCE,
NodeFactory.createURI(Source.Dcep.toString())));
//TODO sobermeier: Add :members to the event (an RDF list of all simple events which were detected)
/*
* Add payload data to event:
*/
Hashtable<String, Object>[] triples = engine.getTriplestoreData(event.getStringProperty(0));
if (triples.length < 1) {
logger.warn("No event attributes (triples) were returned from Etalis for event '{}'", eventId);
}
for(Hashtable<String, Object> item : triples) {
// Remove single quotes around Prolog strings
String subject = item.get("S").toString();
subject = subject.substring(1, subject.length() - 1);
String predicate = item.get("P").toString();
predicate = predicate.substring(1, predicate.length() - 1);
String object = item.get("O").toString();
if (object.startsWith("'") && object.endsWith("'")) {
object = object.substring(1, object.length() - 1);
}
Node objectNode = EventHelpers.toJenaNode(object);
quadruples.add(new Quadruple(
GRAPHNAME,
// Replace dummy event id placeholder with actual unique id for complex event:
(subject.equals(EVENT_ID_PLACEHOLDER) ? EVENTID : NodeFactory.createURI(subject)),
NodeFactory.createURI(predicate),
objectNode));
}
/*
* Add historic data to event:
*/
BdplQuery query = this.registeredQueries.get(event.getProperties()[1].toString());
if (query == null) {
logger.error("Query with ID {} was not found in registeredQueries.", event.getProperties()[1].toString());
} else if (query.getHistoricalQueries() != null && !query.getHistoricalQueries().isEmpty()) {
//Get variable bindings.
VariableBindings variableBindings = JtalisOutputProvider.getSharedVariablesValues(engine, event.getProperties()[1].toString());
//Get historical data to the given binding.
HistoricalData values = this.historicData.get(query.getHistoricalQueries(), variableBindings);
if (values.isEmpty()) {
// there is no matching historic data so the event pattern is not fulfilled:
throw new RetractEventException();
} else {
String vars = "";
for (String varName : values.keySet()) {
vars += " " + varName;
}
logger.debug("SHARED VARIABLES: " + vars);
quadruples.addAll(query.getConstructTemplate().fillTemplate(values, GRAPHNAME, EVENTID));
}
}
return quadruples;
}
public static VariableBindings getSharedVariablesValues(PlayJplEngineWrapper engine, String queryId) {
// HashMap with values of variables.
VariableBindings variableValues = new VariableBindings();
try {
// Get variables and values
Hashtable<String, Object>[] result = engine.execute("variableValues(" + queryId + ", VarName, VarValue)");
// Get all values of a variable
for (Hashtable<String, Object> resultTable : result) {
String varName = resultTable.get("VarName").toString();
String varValue = resultTable.get("VarValue").toString();
// Prepare list
if (!variableValues.containsKey(varName)) {
variableValues.put(varName, new ArrayList<Object>());
}
// Add new value to list
if (varValue != null && varValue.isEmpty()) {
variableValues.get(varName).add(varValue);
}
}
} catch (Exception e) {
logger.debug("No Variable results", e);
}
return variableValues;
}
}