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; } }