package eu.leads.processor.ui;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import eu.leads.processor.Module;
import eu.leads.processor.execute.Tuple;
import eu.leads.processor.query.Query;
import eu.leads.processor.query.SQLQuery;
import eu.leads.processor.query.WorkflowQuery;
import eu.leads.processor.sql.QueryVisitor;
import eu.leads.processor.utils.*;
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.*;
import java.util.concurrent.ConcurrentMap;
/**
* Created with IntelliJ IDEA.
* User: vagvaz
* Date: 9/8/13
* Time: 12:57 PM
* To change this template use File | Settings | File Templates.
*/
public class UserInterfaceManager extends Module {
private ConcurrentMap queriesCache;
private CCJSqlParserManager manager;
private ObjectMapper mapper;
private static final CommandLineUtil log = new CommandLineUtil();//Logger.getLogger(QueryProcessor.class.getName());
private final Object mutex = new Object();
private LinkedList<Message> incoming;
public UserInterfaceManager(String url, String name) throws Exception {
super(url, name);
com.subscribeToQueue(StringConstants.UIMANAGERQUEUE);
com.createQueuePublisher(StringConstants.PLANNERQUEUE);
com.setTopicMessageListener(this);
com.setQueueMessageListener(this);
manager = new CCJSqlParserManager();
mapper = new ObjectMapper();
queriesCache = InfinispanUtils.getOrCreatePersistentMap(StringConstants.QUERIESCACHE);
incoming = new LinkedList<Message>();
}
public String generateNewQueryId(Query query) {
UUID id = UUID.randomUUID();
while (queriesCache.containsKey(query.getUser() + "." + id)) {
id = UUID.randomUUID();
}
return id.toString();
}
public void processQuery(SQLQuery query) throws JsonProcessingException {
query.setId(query.getUser() + generateNewQueryId(query));
Statement st = null;
try {
st = manager.parse(new StringReader(query.getQueryText()));
} catch (JSQLParserException e) {
log.error(e.toString());
}
try {
Map<String, String> queries = InfinispanUtils.getOrCreatePersistentMap("queries");
queries.put(query.getId(), mapper.writeValueAsString(query));
sendAck(query);
} catch (JMSException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
try {
sendQueryToPlanner(query, getQueryType(st), query.getQueryText());
} catch (JMSException e) {
e.printStackTrace();
}
}
private String getQueryType(Statement st) {
if (st != null) {
QueryVisitor visitor = new QueryVisitor();
st.accept(visitor);
return visitor.getStatementType();
}
return "";
}
private void sendQueryToPlanner(Query query, String type, String treePlan) throws JMSException {
TextMessage message;
message = new ActiveMQTextMessage();
message.setText(treePlan);
message.setStringProperty("user", query.getUser());
message.setStringProperty("location", query.getLocation());
message.setStringProperty("id", query.getId());
message.setStringProperty("type", "sqlTreePlan");
message.setStringProperty("queryType", type);
com.publishToQueue(message, "PLANNERQUEUE");
}
private void sendAck(Query query) throws JMSException {
TextMessage reply = new ActiveMQTextMessage();
reply.setText(query.getId());
reply.setStringProperty("type", "ack");
reply.setText(query.getId());
reply.setStringProperty("sqlText", ((SQLQuery) query).getQueryText());
// System.out.println("ack..." + query.getLocation());
com.publishToDestination(reply, query.getLocation());
}
public void processQuery() {
throw new RuntimeException("Unsupported Query");
}
Set<Tuple> fecthResults(Query query) {
Query stored = (Query) queriesCache.get(query.getId());
Set<Tuple> result = new HashSet<Tuple>();
if (stored.isCompleted()) {
// Set<String> resultKeys = InfinispanUtils.getOrCreateSet(query.getId() + ".results");
}
return result;
}
@Override
protected void run() throws Exception {
while (isRunning()) {
LinkedList<Message> toprocess = null;
synchronized (mutex) {
if (incoming.size() > 0) {
toprocess = incoming;
incoming = new LinkedList<Message>();
} else {
mutex.wait();
}
}
if (toprocess != null) {
while (toprocess.size() > 0) {
Message message = toprocess.poll();
try {
if (message.getStringProperty("type").equals("SQLQueryMessage")) {
// log.info("SQLQUEry message");
StdOutputWriter.getInstance().println("UserInterfaceManager received a SQLQuery");
TextMessage msg = (TextMessage) message;
SQLQuery newQuery = new SQLQuery(message.getStringProperty("user"), message.getJMSReplyTo().toString(), msg.getText(), SQLUtils.getSQLType(msg.getText()));
processQuery(newQuery);
} else if (message.getStringProperty("type").equals("isCompleted")) {
TextMessage msg = (TextMessage) message;
String id = msg.getText();
StdOutputWriter.getInstance().println("UserInterfaceManager received a request for completion of query " + id);
replyCompleted(id);
} else if (message.getStringProperty("type").equals("getResults")) {
TextMessage msg = (TextMessage) message;
String id = msg.getText();
StdOutputWriter.getInstance().println("UserInterfaceManager received a request for the results of query " + id);
replyGetResults(id);
} else if (message.getStringProperty("type").equals("queryCompletion")) {
TextMessage msg = (TextMessage) message;
replyCompleted(msg.getText());
StdOutputWriter.getInstance().println("UserInterfaceManager was informed that query " + msg.getText() + " has been completed");
}
} catch (JMSException e) {
e.printStackTrace();
} catch (JsonProcessingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
}
}
@Override
public void onMessage(Message message) {
// System.err.println(this.getClass().toString() + " received msg");
synchronized (mutex) {
if (message == null)
return;
incoming.add(message);
mutex.notify();
}
}
private void replyCompleted(String id) {
TextMessage msg = new ActiveMQTextMessage();
String query = (String) queriesCache.get(id);
try {
msg.setStringProperty("type", "completion");
msg.setText(id);
} catch (JMSException e) {
e.printStackTrace();
}
try {
//read json object for query
JsonNode root = mapper.readTree(query);
ObjectNode node = (ObjectNode) root;
//check if query is completed
if (node.has("queryState") && !node.path("queryState").isNull())
if (node.get("queryState").asText().equals("\"COMPLETED\"")) {
String replyTo = node.get("location").asText();
com.publishToDestination(msg, replyTo);
} else {
System.out.println("query " + id + " is not completed to respont to ");
}
} catch (IOException e) {
e.printStackTrace();
}
}
//Reply to results for the query select url,count(pagerank) from webpages join entities on url=webpage group by domainName order by sum(pagerank)
private void replyGetResults(String id) {
TextMessage msg = new ActiveMQTextMessage();
String query = (String) queriesCache.get(id);
try {
msg.setStringProperty("type", "results");
} catch (JMSException e) {
e.printStackTrace();
}
try {
JsonNode root = mapper.readTree(query);
ObjectNode node = (ObjectNode) root;
String readFrom = mapper.readValue(node.path("output").textValue(), String.class);
List<String> tuples = new ArrayList<String>();
Map<String, String> resultSet = InfinispanUtils.getOrCreatePersistentMap(readFrom);
if (!node.has("isSorted")) {
for (Map.Entry<String, String> t : resultSet.entrySet()) {
tuples.add(t.getValue());
}
} else {
int size = resultSet.size();
for (int i = 0; i < size; i++) {
tuples.add((resultSet.get(readFrom + Integer.toString(i))));
}
}
msg.setText(mapper.writeValueAsString(tuples));
String replyTo = node.get("location").asText();
com.publishToDestination(msg, replyTo);
InfinispanUtils.removeCache(readFrom);
msg = null;
tuples.clear();
node = null;
tuples = null;
queriesCache.remove(id);
Runtime.getRuntime().gc();
} catch (IOException e) {
e.printStackTrace();
} catch (JMSException e) {
e.printStackTrace();
}
}
@Override
protected void triggerShutdown() {
synchronized (mutex) {
mutex.notify();
}
super.triggerShutdown();
}
}