commit be6a9856d1782cea5f76253e60c047acc01daac2 Author: Karsten Loesing karsten.loesing@gmx.net Date: Tue Dec 10 12:15:47 2013 +0100
Remove graphs/* URLs returning graph data in JSON format.
The better data for third parties is contained in stats/*.csv files, because it's less specific to our graphs. It's also documented on stats.html which didn't apply to graphs/*. --- etc/web.xml | 11 - .../ernie/web/graphs/GraphDataServlet.java | 279 -------------------- 2 files changed, 290 deletions(-)
diff --git a/etc/web.xml b/etc/web.xml index c8e4935..992de93 100644 --- a/etc/web.xml +++ b/etc/web.xml @@ -263,17 +263,6 @@ <url-pattern>/consensus-health.html</url-pattern> </servlet-mapping>
- <servlet> - <servlet-name>GraphData</servlet-name> - <servlet-class> - org.torproject.ernie.web.graphs.GraphDataServlet - </servlet-class> - </servlet> - <servlet-mapping> - <servlet-name>GraphData</servlet-name> - <url-pattern>/graphs/*</url-pattern> - </servlet-mapping> - <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> diff --git a/src/org/torproject/ernie/web/graphs/GraphDataServlet.java b/src/org/torproject/ernie/web/graphs/GraphDataServlet.java deleted file mode 100644 index 0e35bdc..0000000 --- a/src/org/torproject/ernie/web/graphs/GraphDataServlet.java +++ /dev/null @@ -1,279 +0,0 @@ -/* Copyright 2011, 2012 The Tor Project - * See LICENSE for licensing information */ -package org.torproject.ernie.web.graphs; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.Map; -import java.util.SortedMap; -import java.util.SortedSet; -import java.util.TimeZone; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.logging.Logger; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Servlet that reads an HTTP request for a JSON-formatted graph data - * document, asks the RObjectGenerator to generate the CSV file behind it, - * converts it to a JSON object, and returns it to the client. - */ -public class GraphDataServlet extends HttpServlet { - - private static final long serialVersionUID = 1799558498301134024L; - - private RObjectGenerator rObjectGenerator; - - /* Available graph data files. */ - private SortedMap<String, String> availableGraphDataFiles; - - /* Variable columns in CSV files that are in long form, not wide. */ - private SortedMap<String, String> variableColumns; - - /* Value columns in CSV files if only specific value columns shall be - * included in results. */ - private SortedMap<String, String> valueColumns; - - private Logger logger; - - public void init() { - - /* Initialize logger. */ - this.logger = Logger.getLogger(GraphDataServlet.class.toString()); - - /* Initialize map of available graph data files and corresponding CSV - * files. */ - this.availableGraphDataFiles = new TreeMap<String, String>(); - this.availableGraphDataFiles.put("relays", "networksize"); - this.availableGraphDataFiles.put("bridges", "networksize"); - this.availableGraphDataFiles.put("cloudbridges", "cloudbridges"); - this.availableGraphDataFiles.put("relays-by-country", - "relaycountries"); - this.availableGraphDataFiles.put("relays-by-flags", "relayflags"); - this.availableGraphDataFiles.put("relays-by-version", "versions"); - this.availableGraphDataFiles.put("relays-by-platform", "platforms"); - this.availableGraphDataFiles.put("relay-bandwidth", "bandwidth"); - this.availableGraphDataFiles.put("relay-dir-bandwidth", "dirbytes"); - this.availableGraphDataFiles.put("relay-bandwidth-history-by-flags", - "bwhist-flags"); - this.availableGraphDataFiles.put("relay-bandwidth-by-flags", - "bandwidth-flags"); - this.availableGraphDataFiles.put("direct-users-by-country", - "direct-users"); - this.availableGraphDataFiles.put("bridge-users-by-country", - "bridge-users"); - this.availableGraphDataFiles.put("torperf", "torperf"); - - /* Initialize map of graphs with specific variable columns. */ - this.variableColumns = new TreeMap<String, String>(); - this.variableColumns.put("relays-by-country", "country"); - this.variableColumns.put("relay-bandwidth-history-by-flags", - "isexit,isguard"); - this.variableColumns.put("torperf", "source"); - - /* Initialize map of graphs with specific value columns. */ - this.valueColumns = new TreeMap<String, String>(); - this.valueColumns.put("relays", "relays"); - this.valueColumns.put("bridges", "bridges"); - - /* Get a reference to the R object generator that we need to generate - * CSV files. */ - this.rObjectGenerator = (RObjectGenerator) getServletContext(). - getAttribute("RObjectGenerator"); - } - - public void doGet(HttpServletRequest request, - HttpServletResponse response) throws IOException, - ServletException { - - /* Check if the directory listing was requested. */ - String requestURI = request.getRequestURI(); - if (requestURI.equals("/ernie/graphs/")) { - request.setAttribute("directory", "/graphs"); - request.setAttribute("extension", ""); - request.setAttribute("files", - this.availableGraphDataFiles.keySet()); - request.getRequestDispatcher("/WEB-INF/dir.jsp").forward(request, - response); - return; - } - - /* Find out which JSON file was requested and make sure we know this - * JSON file type. */ - String requestedJsonFile = request.getRequestURI(); - if (requestedJsonFile.contains("/")) { - requestedJsonFile = requestedJsonFile.substring(requestedJsonFile. - lastIndexOf("/") + 1); - } - if (!availableGraphDataFiles.containsKey(requestedJsonFile)) { - logger.info("Did not recognize requested .csv file from request " - + "URI: '" + request.getRequestURI() + "'. Responding with 404 " - + "Not Found."); - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; - } - String requestedCsvFile = this.availableGraphDataFiles.get( - requestedJsonFile); - logger.fine("CSV file '" + requestedCsvFile + ".csv' requested."); - - /* Request CSV file from R object generator, which may ask Rserve to - * generate it. */ - RObject csvFile = this.rObjectGenerator.generateCsv(requestedCsvFile, - true); - - /* Make sure that we have a CSV to convert into JSON. */ - if (csvFile == null) { - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - return; - } - - /* Look up if we converted this CSV to JSON format before. If not, - * convert it now. */ - String jsonString; - if (!this.lastConvertedCsvFile.containsKey(requestedJsonFile) || - this.lastConvertedCsvFile.get(requestedJsonFile) < - csvFile.getLastModified()) { - jsonString = this.convertCsvToJson(requestedJsonFile, - new String(csvFile.getBytes())); - this.lastConvertedCsvFile.put(requestedJsonFile, - csvFile.getLastModified()); - this.convertedCsvFiles.put(requestedJsonFile, jsonString); - } else { - jsonString = this.convertedCsvFiles.get(requestedJsonFile); - } - - /* Make sure we have a JSON string to return. */ - if (jsonString == null) { - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - return; - } - - /* Write JSON string to response. */ - response.setHeader("Access-Control-Allow-Origin", "*"); - response.setContentType("application/json"); - response.setCharacterEncoding("utf-8"); - response.getWriter().print(jsonString); - } - - private Map<String, Long> lastConvertedCsvFile = - new HashMap<String, Long>(); - private Map<String, String> convertedCsvFiles = - new HashMap<String, String>(); - private String convertCsvToJson(String requestedJsonFile, - String csvFileContent) { - String jsonString = null; - try { - BufferedReader br = new BufferedReader(new StringReader( - csvFileContent)); - String line; - String[] columns = null; - int dateCol = -1; - SortedSet<Integer> variableCols = new TreeSet<Integer>(); - SortedSet<Integer> valueCols = new TreeSet<Integer>(); - if ((line = br.readLine()) != null) { - columns = line.split(","); - for (int i = 0; i < columns.length; i++) { - if (columns[i].equals("date")) { - dateCol = i; - } else if (this.variableColumns.containsKey(requestedJsonFile) - && this.variableColumns.get(requestedJsonFile).contains( - columns[i])) { - variableCols.add(i); - } else if (!this.valueColumns.containsKey(requestedJsonFile) || - this.valueColumns.get(requestedJsonFile).contains( - columns[i])) { - valueCols.add(i); - } - } - } - if (columns == null || dateCol < 0 || valueCols.isEmpty()) { - return null; - } - SortedMap<String, SortedSet<String>> graphs = - new TreeMap<String, SortedSet<String>>(); - while ((line = br.readLine()) != null) { - String[] elements = line.split(","); - if (elements.length != columns.length) { - return null; - } - String date = elements[dateCol]; - String variable = ""; - if (!variableCols.isEmpty()) { - for (int variableCol : variableCols) { - String variableString = elements[variableCol]; - if (variableString.equals("TRUE")) { - variable += columns[variableCol] + "_"; - } else if (variableString.equals("FALSE")) { - variable += "not" + columns[variableCol] + "_"; - } else { - variable += variableString + "_"; - } - } - } - for (int valueCol : valueCols) { - if (elements[valueCol].equals("NA")) { - continue; - } - String graphName = variable + columns[valueCol]; - if (!graphs.containsKey(graphName)) { - graphs.put(graphName, new TreeSet<String>()); - } - String dateAndValue = date + "=" + elements[valueCol]; - graphs.get(graphName).add(dateAndValue); - } - } - StringBuilder sb = new StringBuilder(); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - for (Map.Entry<String, SortedSet<String>> e : graphs.entrySet()) { - String graphName = e.getKey(); - SortedSet<String> datesAndValues = e.getValue(); - if (datesAndValues.isEmpty()) { - continue; - } - String[] firstDateAndValue = datesAndValues.first().split("="); - String firstDate = firstDateAndValue[0]; - String lastDate = datesAndValues.last().split("=")[0]; - sb.append(",\n"" + graphName + "":{" - + ""first":"" + firstDate + ""," - + ""last":"" + lastDate + ""," - + ""values":["); - int written = 0; - String previousDate = firstDate; - long previousDateMillis = dateFormat.parse(previousDate). - getTime(); - for (String dateAndValue : datesAndValues) { - String parts[] = dateAndValue.split("="); - String date = parts[0]; - long dateMillis = dateFormat.parse(date).getTime(); - String value = parts[1]; - while (dateMillis - 86400L * 1000L > previousDateMillis) { - sb.append((written++ > 0 ? "," : "") + "null"); - previousDateMillis += 86400L * 1000L; - previousDate = dateFormat.format(previousDateMillis); - } - sb.append((written++ > 0 ? "," : "") + value); - previousDate = date; - previousDateMillis = dateMillis; - } - sb.append("]}"); - } - br.close(); - jsonString = "[" + sb.toString().substring(1) + "\n]"; - } catch (IOException e) { - return null; - } catch (ParseException e) { - return null; - } - return jsonString; - } -} -
tor-commits@lists.torproject.org