package eu.play_project.play_platformservices_querydispatcher.bdpl.code_generator.realtime;
import static eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.UniqueNameManager.getVarNameManager;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.sparql.expr.Expr;
import com.hp.hpl.jena.sparql.syntax.Element;
import com.hp.hpl.jena.sparql.syntax.ElementEventBinOperator;
import com.hp.hpl.jena.sparql.syntax.ElementEventGraph;
import eu.play_platform.platformservices.bdpl.VariableTypes;
import eu.play_project.play_platformservices.QueryTemplateImpl;
import eu.play_project.play_platformservices.api.QueryTemplate;
import eu.play_project.play_platformservices_querydispatcher.api.EleGenerator;
import eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.BinOperatorVisitor;
import eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.CollectVariablesInTriplesVisitor;
import eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.ComplexTypeFinder;
import eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.EventTypeVisitor;
import eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.FilterExpressionCodeGenerator;
import eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.GenerateConstructResultVisitor;
import eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.HavingVisitor;
import eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.RdfQueryRepresentativeQueryVisitor;
import eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.TriplestoreQueryVisitor;
import eu.play_project.play_platformservices_querydispatcher.bdpl.visitor.realtime.UniqueNameManager;
import eu.play_project.play_platformservices_querydispatcher.types.VariableTypeManager;
/**
* This class coordinates the code generation for the CEP-Engine.
* @author sobermeier
*
*/
public class EleGeneratorForConstructQuery implements EleGenerator {
private Query inputQuery;
// Contains the generated code.
private String elePattern;
// Currently selected element in the tree.
private Element currentElement = null;
// Manages variables which are globally unique.
private UniqueNameManager uniqueNameManager;
// Returns one triple after the other.
private Iterator<Element> eventQueryIter;
// Return operators used in the query. E.g. SEQ, AND, OR ... In the order they are used in the query.
private Iterator<ElementEventBinOperator> binOperatorIter;
// Detect the type of an event.
private EventTypeVisitor eventTypeVisitor;
//Visitors to generate code.
private BinOperatorVisitor binOperatorVisitor;
private FilterExpressionCodeGenerator filterExpressionVisitor;
private HavingVisitor havingVisitor;
private TriplestoreQueryVisitor triplestoreQueryVisitor;
private VariableTypeManager nameManager;
private List<String> rdfDbQueries; // Rdf db queries represents the semantic web part of a BDPL query. ETALIS calls this queries to check conditions for the current events.
private int eventCounter; // Count number of events in a query.
private String patternId;
//Helper methods.
private QueryTemplate queryTemplate;
@Override
public void generateQuery(Query inQuery) {
//Detect eventtypes
//variableAgregatedType = new AgregatedVariableTypes().detectType(inQuery);
elePattern = "";
this.inputQuery = inQuery;
eventQueryIter = inQuery.getEventQuery().iterator();
binOperatorIter = inQuery.getEventBinOperator().iterator();
uniqueNameManager = getVarNameManager();
uniqueNameManager.newQuery(); // Rest uniqueNameManager.
uniqueNameManager.setWindowTime(inQuery.getWindow().getValue());
// Instantiate visitors.
eventTypeVisitor = new EventTypeVisitor();
triplestoreQueryVisitor = new TriplestoreQueryVisitor(uniqueNameManager);
filterExpressionVisitor = new FilterExpressionCodeGenerator();
binOperatorVisitor = new BinOperatorVisitor();
havingVisitor = new HavingVisitor();
queryTemplate = new QueryTemplateImpl();
// Collect basic informations like variable types.
UniqueNameManager.initVariableTypeManage(inQuery);
nameManager = UniqueNameManager.getVariableTypeManage();
nameManager.collectVars();
rdfDbQueries = new LinkedList<String>();
eventCounter = 0;
// Start code generation.
ElePattern();
}
private void ElePattern(){
StringBuffer generateConstructCode;
Complex();
elePattern += "<-";
SimpleEventPattern();
while(binOperatorIter.hasNext()){
binOperatorIter.next().visit(binOperatorVisitor);
elePattern += binOperatorVisitor.getBinOperator();
SimpleEventPattern();
}
}
private void Complex() {
//Detect complex type;
elePattern += (new ComplexTypeFinder()).visit(inputQuery.getConstructTemplate());
elePattern += "(" + uniqueNameManager.getNextCeid() + "," + patternId + ") do (";
GenerateConstructResult();
SaveSharedVariabelValues();
Having();
//PrintStatisticsData();
DecrementReferenceCounter();
elePattern += ")";
}
private void GenerateConstructResult() {
StringBuffer constructResult = new StringBuffer();
GenerateConstructResultVisitor generateConstructResultVisitor = new GenerateConstructResultVisitor();
Iterator<Triple> constructTemplIter = inputQuery.getConstructTemplate().getTriples().iterator();
Triple triple;
// Concatenate q1, q2, q3 ...
StringBuffer queriesConcatenated = new StringBuffer();
for (String q : AllRdfQueryDbMethodDecl(inputQuery, patternId)) {
if(queriesConcatenated.length() > 0){
queriesConcatenated.append(", ");
queriesConcatenated.append(q);
}else{
queriesConcatenated.append(q);
}
}
constructResult.append("" +
"forall((" + queriesConcatenated.toString() + "), " +
"(");
while (constructTemplIter.hasNext()) {
triple = constructTemplIter.next();
if (!containsSharedVariablesTest(triple)) {
constructResult.append( "" +
"generateConstructResult("
+ triple.getSubject().visitWith(
generateConstructResultVisitor)
+ ","
+ triple.getPredicate().visitWith(
generateConstructResultVisitor)
+ ","
+ triple.getObject().visitWith(
generateConstructResultVisitor) + ","
+ uniqueNameManager.getCeid() +
") ");
if (constructTemplIter.hasNext()) {
constructResult.append(", ");
}
}
}
constructResult.append(")");
constructResult.append(")");
elePattern += constructResult.toString();
}
private boolean containsSharedVariablesTest(Triple triple){
boolean result = false;
if(triple.getSubject().isVariable()){
if(nameManager.isType(triple.getSubject().getName(), VariableTypes.REALTIME_TYPE) && nameManager.isType(triple.getSubject().getName(), VariableTypes.HISTORIC_TYPE)){
return true;
}
}
if(triple.getPredicate().isVariable()){
if(nameManager.isType(triple.getPredicate().getName(), VariableTypes.REALTIME_TYPE) && nameManager.isType(triple.getPredicate().getName(), VariableTypes.HISTORIC_TYPE)){
return true;
}
}
if(triple.getObject().isVariable()){
if(nameManager.isType(triple.getObject().getName(), VariableTypes.REALTIME_TYPE) && nameManager.isType(triple.getObject().getName(), VariableTypes.HISTORIC_TYPE)){
return true;
}
}
return result;
}
public void SaveSharedVariabelValues() {
StringBuffer tmpEle = new StringBuffer();
List<String> vars = nameManager.getVariables(VariableTypes.HISTORIC_TYPE, VariableTypes.REALTIME_TYPE);
for (String var : vars) {
if (!elePattern.endsWith(",")) {
elePattern += ",";
}
tmpEle.append("variabeValuesAdd(" + patternId + ",'" + var + "'," + "V" + var + ")");
}
elePattern += tmpEle.toString();
}
private void DecrementReferenceCounter(){
StringBuffer tmp = new StringBuffer();
for (String var : uniqueNameManager.getAllTripleStoreVariablesOfThisQuery()) {
tmp.append(", decrementReferenceCounter( "+ var + ")");
}
elePattern += tmp.toString();
}
//Call prolog methods which echos statistics data to the console.
private void PrintStatisticsData(){
elePattern += ", printRdfStat, printRefCountN";
}
private void SimpleEventPattern() {
elePattern += "(";
currentElement = eventQueryIter.next();
currentElement.visit(eventTypeVisitor);
elePattern += eventTypeVisitor.getEventType();
elePattern += "(";
String triplestoreVariable = uniqueNameManager.getNextTriplestoreVariable();
elePattern += triplestoreVariable;
elePattern += ") 'WHERE' (";
AdditionalConditions();
elePattern += "))";
}
private void AdditionalConditions(){
TriplestoreQuery();
FilterExpression();
ReferenceCounter();
// elePattern += ", ";
// PerformanceMeasurement();
// FIXME sobermeier: re-add these lines and test for PrologException on simple events
if(!binOperatorIter.hasNext()){
elePattern += ",";
GenerateCEID();
}
}
private void ReferenceCounter(){
elePattern += " incrementReferenceCounter(" + uniqueNameManager.getTriplestoreVariable() + ")";
}
private void PerformanceMeasurement(){
elePattern += "measure(" + patternId + ")";
}
private void TriplestoreQuery() {
String flatDbQueries;
eventCounter++; // New event in query.
// Get flat queries
currentElement.visit(triplestoreQueryVisitor);
flatDbQueries = triplestoreQueryVisitor.getTriplestoreQueryGraphTerms();
// Generate representative.
RdfQueryRepresentativeQueryVisitor v = new RdfQueryRepresentativeQueryVisitor();
currentElement.visit(v);
//Generate query method
StringBuffer dbQueryMethod = new StringBuffer();
String dbQueryDecl = RdfQueryDbMethodDecl(currentElement, eventCounter).toString();
// Combine decl and impl.
dbQueryMethod.append(dbQueryDecl + ":-(" + flatDbQueries + ")");
rdfDbQueries.add(dbQueryMethod.toString());
//Generate call for query.
int i = 0;
for (String key : v.getRdfQueryRepresentativeQuery().keySet()) {
elePattern += "(\\+forall("
+ v.getRdfQueryRepresentativeQuery().get(key) + ", "
+ "(\\+((" + dbQueryDecl + ")))" + "))";
if ((i < v.getRdfQueryRepresentativeQuery().size())) {
elePattern += ",";
}
}
}
private void FilterExpression() {
filterExpressionVisitor.startVisit(((ElementEventGraph)currentElement).getFilterExp());
if(!elePattern.endsWith(",") && !filterExpressionVisitor.getEle().equals("")){ // This filter is optional. No value needed.
elePattern += "," + filterExpressionVisitor.getEle();
}else if(!filterExpressionVisitor.getEle().equals("")){
elePattern += filterExpressionVisitor.getEle();
}
}
private void GenerateCEID(){
elePattern += "random(1000000, 9000000, " + uniqueNameManager.getCeid() + ")";
}
@Override
public String getEle() {
return elePattern;
}
@Override
public ArrayList<String[]> getEventProperties() {
return null;
}
@Override
public void setPatternId(String patternId) {
this.patternId = "'" + patternId + "'";
}
@Override
public QueryTemplate getQueryTemplate() {
return this.queryTemplate;
}
public void Having(){
if(!inputQuery.getHavingExprs().isEmpty()){
elePattern += ", ";
}
for (Expr el : inputQuery.getHavingExprs()) {
el.visit(havingVisitor);
}
elePattern += havingVisitor.getCode().toString();
}
@Override
public List<String> getRdfDbQueries() {
return rdfDbQueries;
}
/**
* Generate rdf db method declerations.
* E.g. dbQuery_abc_e1(Ve1).
* @param q Parsed Jena query.
* @return
*/
private List<String> AllRdfQueryDbMethodDecl(Query q, String patternId) {
List<String> dbDecl = new LinkedList<String>();
int eventCounter = 0;
for (Element currentElement : q.getEventQuery()) {
eventCounter++;
dbDecl.add(RdfQueryDbMethodDecl(currentElement, eventCounter).toString());
}
return dbDecl;
}
public StringBuffer RdfQueryDbMethodDecl(Element currentElement, int eventCounter) {
// Get variables
CollectVariablesInTriplesVisitor v = new CollectVariablesInTriplesVisitor();
currentElement.visit(v);
// Generate query method
StringBuffer dbQueryDecl = new StringBuffer();
// Schema "dbQuery" + patternId + idForEvent
dbQueryDecl.append("'dbQuery_" + patternId.replace("'", "") + "_e" + eventCounter + "'(");
dbQueryDecl.append(uniqueNameManager
.getTriplestoreVariableForEventNr(eventCounter) + ", "); // Mapping
// between
// event
// and
// corresponding
// data.
Iterator<String> iter = v.getVariables().iterator();
while (iter.hasNext()) {
dbQueryDecl.append(iter.next());
// Decide if it is the last variable or end of decl.
if (iter.hasNext()) {
dbQueryDecl.append(", ");
} else {
dbQueryDecl.append(")");
}
}
return dbQueryDecl;
}
}