package eu.leads.processor.plan;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.leads.processor.Module;
import eu.leads.processor.query.Query;
import eu.leads.processor.query.QueryContext;
import eu.leads.processor.query.SQLQuery;
import eu.leads.processor.sql.Plan;
import eu.leads.processor.utils.InfinispanUtils;
import eu.leads.processor.utils.StdOutputWriter;
import eu.leads.processor.utils.StringConstants;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.statement.Statement;
import org.apache.activemq.command.ActiveMQTextMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.TextMessage;
import java.io.IOException;
import java.io.StringReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentMap;
/**
* Created with IntelliJ IDEA.
* User: vagvaz
* Date: 9/9/13
* Time: 8:33 AM
* To change this template use File | Settings | File Templates.
*/
public class QueryPlannerImpl extends Module implements QueryPlanner {
private ConcurrentMap queriesCache;
private Queue<Message> incoming;
private ObjectMapper mapper;
private final Object mutex = new Object();
public QueryPlannerImpl(String url, String name) throws Exception {
super(url, name);
com.subscribeToQueue(StringConstants.PLANNERQUEUE);
com.createQueuePublisher(StringConstants.DEPLOYERQUEUE);
com.setTopicMessageListener(this);
com.setQueueMessageListener(this);
mapper = new ObjectMapper();
incoming = new LinkedList<Message>();
queriesCache = InfinispanUtils.getOrCreatePersistentMap(StringConstants.QUERIESCACHE);
}
@Override
protected void run() throws Exception {
while (isRunning()) {
Queue<Message> unprocessed = null;
synchronized (mutex) {
if (incoming.size() > 0) {
unprocessed = incoming;
incoming = new LinkedList<Message>();
} else {
mutex.wait();
}
}
if (unprocessed != null) {
while (!unprocessed.isEmpty()) {
TextMessage message = (TextMessage) unprocessed.poll();
String type = message.getStringProperty("type");
if (type.equals("sqlTreePlan")) {
String queryType = message.getStringProperty("queryType");
SQLQuery query = new SQLQuery(message.getStringProperty("user"), message.getStringProperty("location"), message.getText(), queryType);
query.setId(message.getStringProperty("id"));
StdOutputWriter.getInstance().println("QueryPlanner is ready to produce plans for " + query.getId());
//validate query and extract the basic plan
if (validateQuery(query)) {
//Generate plans
//Right now do nothing
SortedMap<Double, Plan> plans = generatePlans(query);
//Interface with Scheduler
evaluatePlansFromScheduler();
//Choose plan from the evaluated
Plan selected = choosePlan(plans);
//Send selected plan to deployer
sendPlanToDeployer(selected, query);
} else {
//TODO Error reporting
}
} else {
}
}
}
}
}
private boolean validateQuery(SQLQuery query) {
boolean result = true;
QueryContext context = new QueryContext(query);
query.setQueryContext(context);
//Read Query
CCJSqlParserManager manager = new CCJSqlParserManager();
Statement st;
String jsonStatement;
JsonNode root = null;
try {
st = manager.parse(new StringReader(query.getQueryText()));
jsonStatement = mapper.writeValueAsString(st);
root = mapper.readTree(jsonStatement);
} catch (JSQLParserException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (JsonProcessingException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (IOException e) {
e.printStackTrace();
}
//Extract basic plan and set it to query.
BasicPlannerExtractor extractor = null;
try {
extractor = ExtractorFactory.getBasicExtractor(StatementType.getType(query.getSqlType()), root);
} catch (Exception e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
Plan p = extractor.extractPlan(context.getQueryId() + "output", context);
query.setPlan(p);
return result;
}
private void sendPlanToDeployer(Plan selected, Query query) {
TextMessage message = new ActiveMQTextMessage();
try {
//update query to hold the selected plan
query.setPlan(selected);
//Store query to KVS
queriesCache = InfinispanUtils.getOrCreatePersistentMap(StringConstants.QUERIESCACHE);
queriesCache.put(query.getId(), mapper.writeValueAsString(query));
message.setText(mapper.writeValueAsString(query.getPlan()));
message.setStringProperty("context", mapper.writeValueAsString(query.getContext()));
message.setStringProperty("type", "execute");
} catch (JMSException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (JsonProcessingException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
try {
com.publishToQueue(message, StringConstants.DEPLOYERQUEUE);
} catch (JMSException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
private SortedMap<Double, Plan> evaluatePlansFromScheduler() {
//TODO
SortedMap<Double, Plan> result = new TreeMap<Double, Plan>();
return result;
}
@Override
public void onMessage(Message message) {
// System.err.println(this.getClass().toString() + " received msg");
String messageType = "";
synchronized (mutex) {
incoming.add(message);
mutex.notify();
}
}
@Override
public SortedMap generatePlans(Query q) {
SortedMap<Double, Plan> result = new TreeMap<Double, Plan>();
result.put(1.0, q.getPlan());
return result;
}
@Override
public Plan choosePlan(SortedMap<Double, Plan> plans) {
Plan result = null;
Double headKey = plans.firstKey();
result = plans.get(headKey);
return result;
}
@Override
protected void triggerShutdown() {
synchronized (mutex) {
mutex.notify();
}
super.triggerShutdown();
}
}