package com.zenquery.api;
import au.com.bytecode.opencsv.CSVWriter;
import com.hp.gagawa.java.elements.Strong;
import com.hp.gagawa.java.elements.Table;
import com.hp.gagawa.java.elements.Td;
import com.hp.gagawa.java.elements.Tr;
import com.hp.gagawa.java.elements.Th;
import com.hp.gagawa.java.elements.Div;
import com.hp.gagawa.java.elements.A;
import com.thoughtworks.xstream.XStream;
import com.zenquery.model.DatabaseConnection;
import com.zenquery.model.Query;
import com.zenquery.model.dao.DatabaseConnectionDAO;
import com.zenquery.model.dao.QueryDAO;
import com.zenquery.util.BasicDataSourceFactory;
import com.zenquery.util.MapEntryConverter;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.io.StringWriter;
import java.util.*;
@Controller
@RequestMapping("/api/v1/resultSetForQuery")
public class ResultSetController {
private static final Logger logger = Logger.getLogger(ResultSetController.class);
@Autowired
private DatabaseConnectionDAO databaseConnectionDAO;
@Autowired
private QueryDAO queryDAO;
@Autowired
private BasicDataSourceFactory dataSourceFactory;
@RequestMapping(
value = "/{id}",
method = RequestMethod.GET,
produces = { "application/json; charset=utf-8" })
public @ResponseBody
List<Map<String, Object>> currentQuery(
@PathVariable Integer id
) {
List<Map<String, Object>> rows = getRows(id, null, null);
return rows;
}
@RequestMapping(
value = "/{id}/{variables}",
method = RequestMethod.GET,
produces = { "application/json; charset=utf-8" })
public @ResponseBody
List<Map<String, Object>> currentQuery(
@PathVariable Integer id,
@PathVariable String variables
) {
List<Map<String, Object>> rows = getRows(id, variables, null);
return rows;
}
@RequestMapping(
value = "/{id}/size/{size}",
method = RequestMethod.GET,
produces = { "application/json; charset=utf-8" })
public @ResponseBody
List<Map<String, Object>> currentQuery(
@PathVariable Integer id,
@PathVariable Integer size
) {
List<Map<String, Object>> rows = getRows(id, null, size);
return rows;
}
@RequestMapping(
value = "/{id}/{variables}/size/{size}",
method = RequestMethod.GET,
produces = { "application/json; charset=utf-8" })
public @ResponseBody
List<Map<String, Object>> currentQuery(
@PathVariable Integer id,
@PathVariable String variables,
@PathVariable Integer size
) {
List<Map<String, Object>> rows = getRows(id, variables, size);
return rows;
}
@RequestMapping(
value = "/{id}",
method = RequestMethod.GET,
produces = { "text/csv; charset=utf-8" })
public @ResponseBody
String currentQueryAsCSV(
@PathVariable Integer id
) {
List<Map<String, Object>> rows = getRows(id, null, null);
return getCsvResults(rows);
}
@RequestMapping(
value = "/{id}/{variables}",
method = RequestMethod.GET,
produces = { "text/csv; charset=utf-8" })
public @ResponseBody
String currentQueryAsCSV(
@PathVariable Integer id,
@PathVariable String variables
) {
List<Map<String, Object>> rows = getRows(id, variables, null);
return getCsvResults(rows);
}
@RequestMapping(
value = "/{id}/size/{size}",
method = RequestMethod.GET,
produces = { "text/csv; charset=utf-8" })
public @ResponseBody
String currentQueryAsCSV(
@PathVariable Integer id,
@PathVariable Integer size
) {
List<Map<String, Object>> rows = getRows(id, null, size);
return getCsvResults(rows);
}
@RequestMapping(
value = "/{id}/{variables}/size/{size}",
method = RequestMethod.GET,
produces = { "text/csv; charset=utf-8" })
public @ResponseBody
String currentQueryAsCSV(
@PathVariable Integer id,
@PathVariable String variables,
@PathVariable Integer size
) {
List<Map<String, Object>> rows = getRows(id, variables, size);
return getCsvResults(rows);
}
@RequestMapping(
value = "/{id}",
method = RequestMethod.GET,
produces = { "application/xml; charset=utf-8" })
public @ResponseBody
String currentQueryAsXML(
@PathVariable Integer id
) {
List<Map<String, Object>> rows = getRows(id, null, null);
XStream stream = getXMLStream();
return stream.toXML(rows.toArray());
}
@RequestMapping(
value = "/{id}/{variables}",
method = RequestMethod.GET,
produces = { "application/xml; charset=utf-8" })
public @ResponseBody
String currentQueryAsXML(
@PathVariable Integer id,
@PathVariable String variables
) {
List<Map<String, Object>> rows = getRows(id, variables, null);
XStream stream = getXMLStream();
return stream.toXML(rows.toArray());
}
@RequestMapping(
value = "/{id}/size/{size}",
method = RequestMethod.GET,
produces = { "application/xml; charset=utf-8" })
public @ResponseBody
String currentQueryAsXML(
@PathVariable Integer id,
@PathVariable Integer size
) {
List<Map<String, Object>> rows = getRows(id, null, size);
XStream stream = getXMLStream();
return stream.toXML(rows.toArray());
}
@RequestMapping(
value = "/{id}/{variables}/size/{size}",
method = RequestMethod.GET,
produces = { "application/xml; charset=utf-8" })
public @ResponseBody
String currentQueryAsXML(
@PathVariable Integer id,
@PathVariable String variables,
@PathVariable Integer size
) {
List<Map<String, Object>> rows = getRows(id, variables, size);
XStream stream = getXMLStream();
return stream.toXML(rows.toArray());
}
@RequestMapping(
value = "/{mode}/{complete}/{id}",
method = RequestMethod.GET,
produces = { "text/html; charset=utf-8" })
public @ResponseBody
String currentQueryAsHTML(
@PathVariable Integer id,
@PathVariable String mode,
@PathVariable Boolean complete
) {
List<Map<String, Object>> rows = getRows(id, null, null);
String html = getHTML(mode, complete, rows);
return html;
}
@RequestMapping(
value = "/{mode}/{complete}/{id}/{variables}",
method = RequestMethod.GET,
produces = { "text/html; charset=utf-8" })
public @ResponseBody
String currentQueryAsHTML(
@PathVariable Integer id,
@PathVariable String variables,
@PathVariable String mode,
@PathVariable Boolean complete
) {
List<Map<String, Object>> rows = getRows(id, variables, null);
String html = getHTML(mode, complete, rows);
return html;
}
@RequestMapping(
value = "/{id}",
method = RequestMethod.GET,
produces = { "text/html; charset=utf-8" })
public @ResponseBody
String currentQueryAsHTML(
@PathVariable Integer id
) {
List<Map<String, Object>> rows = getRows(id, null, null);
String html = getHTML("vertical", true, rows);
return html;
}
@RequestMapping(
value = "/{id}/{variables}",
method = RequestMethod.GET,
produces = { "text/html; charset=utf-8" })
public @ResponseBody
String currentQueryAsHTML(
@PathVariable Integer id,
@PathVariable String variables
) {
List<Map<String, Object>> rows = getRows(id, variables, null);
String html = getHTML("vertical", true, rows);
return html;
}
@RequestMapping(
value = "/{mode}/{complete}/{id}/size/{size}",
method = RequestMethod.GET,
produces = { "text/html; charset=utf-8" })
public @ResponseBody
String currentQueryAsHTML(
@PathVariable Integer id,
@PathVariable String mode,
@PathVariable Boolean complete,
@PathVariable Integer size
) {
List<Map<String, Object>> rows = getRows(id, null, size);
String html = getHTML(mode, complete, rows);
return html;
}
@RequestMapping(
value = "/{mode}/{complete}/{id}/{variables}/size/{size}",
method = RequestMethod.GET,
produces = { "text/html; charset=utf-8" })
public @ResponseBody
String currentQueryAsHTML(
@PathVariable Integer id,
@PathVariable String variables,
@PathVariable String mode,
@PathVariable Boolean complete,
@PathVariable Integer size
) {
List<Map<String, Object>> rows = getRows(id, variables, size);
String html = getHTML(mode, complete, rows);
return html;
}
@RequestMapping(
value = "/{id}/size/{size}",
method = RequestMethod.GET,
produces = { "text/html; charset=utf-8" })
public @ResponseBody
String currentQueryAsHTML(
@PathVariable Integer id,
@PathVariable Integer size
) {
List<Map<String, Object>> rows = getRows(id, null, size);
String html = getHTML("vertical", true, rows);
return html;
}
@RequestMapping(
value = "/{id}/{variables}/size/{size}",
method = RequestMethod.GET,
produces = { "text/html; charset=utf-8" })
public @ResponseBody
String currentQueryAsHTML(
@PathVariable Integer id,
@PathVariable String variables,
@PathVariable Integer size
) {
List<Map<String, Object>> rows = getRows(id, variables, size);
String html = getHTML("vertical", true, rows);
return html;
}
private List<Map<String, Object>> getResultRows(Integer id, String variables) {
Query query = queryDAO.find(id);
DatabaseConnection databaseConnection = databaseConnectionDAO.find(query.getDatabaseConnectionId());
List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
try {
BasicDataSource dataSource = dataSourceFactory.getBasicDataSource(
databaseConnection.getUrl(),
databaseConnection.getUsername(),
databaseConnection.getPassword()
);
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
if (variables != null) {
List<Object> arguments = new ArrayList<Object>();
String[] extractedVariables = variables.split(",");
for (String variable : extractedVariables) {
try {
arguments.add(Long.parseLong(variable));
} catch(NumberFormatException noLong) {
try {
arguments.add(Double.parseDouble(variable));
} catch(NumberFormatException noDouble) {
arguments.add(variable);
}
}
}
rows = jdbcTemplate.queryForList(query.getContent(), arguments.toArray());
} else {
rows = jdbcTemplate.queryForList(query.getContent());
}
} catch (Exception e) {
logger.debug(e);
}
return rows;
}
private String getCsvResults(List<Map<String, Object>> rows) {
List<String[]> outputRows = new ArrayList<String[]>();
Boolean first = true;
StringWriter stringWriter = new StringWriter();
CSVWriter csvWriter = new CSVWriter(stringWriter);
for (Map<String, Object> row : rows) {
if (first) {
Set<String> keys = row.keySet();
String[] columnTitles = new String[keys.size()];
columnTitles = keys.toArray(columnTitles);
outputRows.add(columnTitles);
first = false;
}
Collection<Object> values = row.values();
Object[] columnValues = new Object[values.size()];
columnValues = values.toArray(columnValues);
Integer numberOfValues = values.size();
String[] columnOutputValues = new String[numberOfValues];
for (int i = 0; i < numberOfValues; i++) {
Object columnValue = columnValues[i];
if (columnValue != null) {
columnOutputValues[i] = columnValue.toString();
} else {
columnOutputValues[i] = "";
}
}
outputRows.add(columnOutputValues);
}
csvWriter.writeAll(outputRows);
return stringWriter.toString();
}
private XStream getXMLStream() {
XStream stream = new XStream();
stream.registerConverter(new MapEntryConverter());
stream.alias("root", Map.class);
return stream;
}
private String getHTML(String mode, Boolean complete, List<Map<String, Object>> rows) {
String html;
if (mode.equals("horizontal")) {
if (complete) {
html = getHorizontalResultListHTML(rows);
} else {
html = getHorizontalTableHTML(rows);
}
} else {
if (complete) {
html = getVerticalResultListHTML(rows);
} else {
html = getVerticalListHTML(rows);
}
}
return html;
}
private String getHorizontalTableHTML(List<Map<String, Object>> rows) {
Table table = new Table();
table.setCSSClass("table table-striped table-bordered table-hover");
Tr tableHeader = new Tr();
Boolean firstRow = true;
for (Map<String, Object> row : rows) {
Tr tableRow = new Tr();
for (String key : row.keySet()) {
if (firstRow) {
Th th = new Th();
th.appendText(key);
tableHeader.appendChild(th);
}
Td td = new Td();
tableRow.appendChild(td);
Object value = row.get(key);
if (value != null) {
appendValueToTd(td, value);
}
}
if (firstRow) {
table.appendChild(tableHeader);
firstRow = false;
}
table.appendChild(tableRow);
}
return table.write();
}
private String getVerticalListHTML(List<Map<String, Object>> rows) {
Div resultSetList = new Div();
resultSetList.setCSSClass("row");
for (Map<String, Object> row : rows) {
Div entry = new Div();
entry.setCSSClass("col-lg-12");
resultSetList.appendChild(entry);
Table entryTable = new Table();
entryTable.setCSSClass("table table-striped table-bordered table-hover");
entry.appendChild(entryTable);
for (String key : row.keySet()) {
Tr attributeRow = new Tr();
Td tdKey = new Td();
Strong strong = new Strong();
tdKey.appendChild(strong);
strong.appendText(key);
attributeRow.appendChild(tdKey);
Td tdValue = new Td();
attributeRow.appendChild(tdValue);
Object value = row.get(key);
if (value != null) {
appendValueToTd(tdValue, value);
}
entryTable.appendChild(attributeRow);
}
}
return resultSetList.write();
}
private String getHorizontalResultListHTML(List<Map<String, Object>> rows) {
String html = "<!doctype html><!--[if lt IE 7]> <html class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endif]--><!--[if IE 7]> <html class=\"no-js lt-ie9 lt-ie8\"> <![endif]--><!--[if IE 8]> <html class=\"no-js lt-ie9\"> <![endif]--><!--[if gt IE 8]><!--> <html class=\"no-js\"> <!--<![endif]--><head><meta charset=\"utf-8\"><title>禅宗 - ZenQuery</title><meta name=\"description\" content=\"\"><meta name=\"viewport\" content=\"width=device-width\"><link rel=\"stylesheet\" href=\"//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css\"><link rel=\"stylesheet\" href=\"//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css\"><script src=\"//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js\"></script></head><body><div class=\"container\">";
html += getHorizontalTableHTML(rows);
html += "</div></body></html>";
return html;
}
private String getVerticalResultListHTML(List<Map<String, Object>> rows) {
String html = "<!doctype html><!--[if lt IE 7]> <html class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endif]--><!--[if IE 7]> <html class=\"no-js lt-ie9 lt-ie8\"> <![endif]--><!--[if IE 8]> <html class=\"no-js lt-ie9\"> <![endif]--><!--[if gt IE 8]><!--> <html class=\"no-js\"> <!--<![endif]--><head><meta charset=\"utf-8\"><title>禅宗 - ZenQuery</title><meta name=\"description\" content=\"\"><meta name=\"viewport\" content=\"width=device-width\"><link rel=\"stylesheet\" href=\"//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css\"><link rel=\"stylesheet\" href=\"//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css\"><script src=\"//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js\"></script></head><body><div class=\"container\">";
html += getVerticalListHTML(rows);
html += "</div></body></html>";
return html;
}
private void appendValueToTd(Td td, Object value) {
String text = value.toString();
if (text.startsWith("/api/")) {
A a = new A();
a.setHref(text + ".html");
a.appendText(text);
text = a.write();
}
td.appendText(text);
}
private List<Map<String, Object>> getRows(Integer id, String variables, Integer size) {
List<Map<String, Object>> rows = getResultRows(id, variables);
if (size != null && size != 0 && size < rows.size()) {
rows = rows.subList(0, size);
}
return rows;
}
}