diff --git a/back-end/src/main/java/index/AutoDDInMemoryIndexer.java b/back-end/src/main/java/index/AutoDDInMemoryIndexer.java index 0a537d84..c4350b00 100644 --- a/back-end/src/main/java/index/AutoDDInMemoryIndexer.java +++ b/back-end/src/main/java/index/AutoDDInMemoryIndexer.java @@ -11,9 +11,11 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.Locale; import main.Config; import main.DbConnector; import main.Main; @@ -105,8 +107,8 @@ public int compare(RTreeData o1, RTreeData o2) { int zColId = autoDD.getColumnNames().indexOf(zCol); String zOrder = autoDD.getzOrder(); - float v1 = Float.valueOf(rawRows.get(o1.rowId).get(zColId)); - float v2 = Float.valueOf(rawRows.get(o2.rowId).get(zColId)); + float v1 = parseFloat(rawRows.get(o1.rowId).get(zColId)); + float v2 = parseFloat(rawRows.get(o2.rowId).get(zColId)); if (v1 == v2) return 0; if (zOrder.equals("asc")) return v1 < v2 ? -1 : 1; else return v1 < v2 ? 1 : -1; @@ -188,6 +190,9 @@ private void setCommonVariables() throws SQLException, ClassNotFoundException { // store raw query results into memory rawRows = DbConnector.getQueryResult(autoDD.getDb(), autoDD.getQuery()); + for (int i = 0; i < rawRows.size(); i++) + for (int j = 0; j < numRawColumns; j++) + if (rawRows.get(i).get(j) == null) rawRows.get(i).set(j, ""); // add row number as a BGRP Main.getProject().addBGRP("roughN", String.valueOf(rawRows.size())); @@ -233,12 +238,12 @@ private void computeClusterAggs() throws SQLException, ClassNotFoundException { double cx = autoDD.getCanvasCoordinate( i - 1, - Double.valueOf(rawRows.get(rd.rowId).get(autoDD.getXColId())), + parseFloat(rawRows.get(rd.rowId).get(autoDD.getXColId())), true); double cy = autoDD.getCanvasCoordinate( i - 1, - Double.valueOf(rawRows.get(rd.rowId).get(autoDD.getYColId())), + parseFloat(rawRows.get(rd.rowId).get(autoDD.getYColId())), false); double minx = cx - autoDD.getBboxW() * overlappingThreshold / 2; double miny = cy - autoDD.getBboxH() * overlappingThreshold / 2; @@ -255,13 +260,13 @@ private void computeClusterAggs() throws SQLException, ClassNotFoundException { double curCx = autoDD.getCanvasCoordinate( i - 1, - Double.valueOf( + parseFloat( rawRows.get(neighborRd.rowId).get(autoDD.getXColId())), true); double curCy = autoDD.getCanvasCoordinate( i - 1, - Double.valueOf( + parseFloat( rawRows.get(neighborRd.rowId).get(autoDD.getYColId())), false); double curDistance = @@ -452,10 +457,11 @@ private void setInitialClusterAgg(RTreeData rd) { // convexHull double cx = autoDD.getCanvasCoordinate( - autoDD.getNumLevels(), Double.valueOf(row.get(autoDD.getXColId())), true); + autoDD.getNumLevels(), parseFloat(row.get(autoDD.getXColId())), true); double cy = autoDD.getCanvasCoordinate( - autoDD.getNumLevels(), Double.valueOf(row.get(autoDD.getYColId())), false); + autoDD.getNumLevels(), parseFloat(row.get(autoDD.getYColId())), false); + float minx = (float) (cx - autoDD.getBboxW() / 2.0), maxx = (float) (cx + autoDD.getBboxW() / 2.0); float miny = (float) (cy - autoDD.getBboxH() / 2.0), @@ -491,7 +497,7 @@ private void setInitialClusterAgg(RTreeData rd) { float curValue = (curMeasureFunction.equals("count") ? 1.0f - : Float.valueOf( + : parseFloat( row.get(autoDD.getColumnNames().indexOf(curMeasureField)))); if (curMeasureFunction.equals("sqrsum")) @@ -537,8 +543,8 @@ else if (childIter >= childTopk.length) else { int parentHead = parentTopk[parentIter]; int childHead = childTopk[childIter]; - double parentValue = Double.valueOf(rawRows.get(parentHead).get(zColId)); - double childValue = Double.valueOf(rawRows.get(childHead).get(zColId)); + double parentValue = parseFloat(rawRows.get(parentHead).get(zColId)); + double childValue = parseFloat(rawRows.get(childHead).get(zColId)); if ((parentValue <= childValue && zOrder.equals("asc")) || (parentValue >= childValue && zOrder.equals("desc"))) { mergedTopk[mergedIter++] = parentHead; @@ -622,4 +628,13 @@ private float[][] getCoordsListOfGeometry(Geometry geometry) { } return coordsList; } + + private float parseFloat(String s) { + NumberFormat nf = NumberFormat.getInstance(Locale.US); + try { + return nf.parse(s).floatValue(); + } catch (Exception e) { + return 0; + } + } } diff --git a/back-end/src/main/java/main/DbConnector.java b/back-end/src/main/java/main/DbConnector.java index f92a7353..bbe4e906 100644 --- a/back-end/src/main/java/main/DbConnector.java +++ b/back-end/src/main/java/main/DbConnector.java @@ -149,4 +149,11 @@ public static void closeConnection(String dbName) throws SQLException { connections.remove(dbName + "_batch"); } } + + public static void closeAllConnections() throws SQLException { + for (String connName : connections.keySet()) { + connections.get(connName).close(); + } + connections.clear(); + } } diff --git a/back-end/src/main/java/main/Main.java b/back-end/src/main/java/main/Main.java index f204878e..9bd2368d 100644 --- a/back-end/src/main/java/main/Main.java +++ b/back-end/src/main/java/main/Main.java @@ -39,7 +39,8 @@ public static Project getProject() { public static void setProject(Project newProject) { - System.out.println("Current project set to: " + newProject.getName()); + System.out.println( + "Current project set to: " + (newProject != null ? newProject.getName() : "null")); project = newProject; // clear cache whenever there is a project switch diff --git a/back-end/src/main/java/project/AutoDD.java b/back-end/src/main/java/project/AutoDD.java index 719a4028..68de8711 100644 --- a/back-end/src/main/java/project/AutoDD.java +++ b/back-end/src/main/java/project/AutoDD.java @@ -19,7 +19,7 @@ public class AutoDD { private int numLevels, topLevelWidth, topLevelHeight; private double overlap; private double zoomFactor; - private int xColId = -1, yColId = -1; + private int xColId = -1, yColId = -1, zColId = -1; private double loX = Double.NaN, loY, hiX, hiY; private String mergeClusterAggs, getCitusSpatialHashKeyBody, @@ -78,7 +78,7 @@ public int getXColId() { if (xColId < 0) { ArrayList colNames = getColumnNames(); - for (int i = 0; i < colNames.size(); i++) if (colNames.get(i).equals(xCol)) xColId = i; + xColId = colNames.indexOf(xCol); } return xColId; } @@ -87,11 +87,20 @@ public int getYColId() { if (yColId < 0) { ArrayList colNames = getColumnNames(); - for (int i = 0; i < colNames.size(); i++) if (colNames.get(i).equals(yCol)) yColId = i; + yColId = colNames.indexOf(yCol); } return yColId; } + public int getZColId() { + + if (zColId < 0) { + ArrayList colNames = getColumnNames(); + zColId = colNames.indexOf(zCol); + } + return zColId; + } + public ArrayList getColumnNames() { // if it is specified already, return diff --git a/back-end/src/main/java/server/BoxRequestHandler.java b/back-end/src/main/java/server/BoxRequestHandler.java index d23a4f64..36c23a4a 100644 --- a/back-end/src/main/java/server/BoxRequestHandler.java +++ b/back-end/src/main/java/server/BoxRequestHandler.java @@ -34,96 +34,99 @@ public void handle(HttpExchange httpExchange) throws IOException { // TODO: this method should be thread safe, allowing concurrent requests System.out.println("\nServing /dynamic Box"); - // get data of the current request - // variable definitions - String response; - String canvasId, viewId; - double minx, miny; - BoxandData data = null; - - // check if this is a POST request - if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); - return; - } - - // get data of the current request - String query = httpExchange.getRequestURI().getQuery(); - Map queryMap = Server.queryToMap(query); - // print - for (String s : queryMap.keySet()) System.out.println(s + " : " + queryMap.get(s)); - - // check parameters, if not pass, send a bad request response - response = checkParameters(queryMap); - if (response.length() > 0) { - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_REQUEST, response); - return; - } - // get parameters - canvasId = queryMap.get("id"); - viewId = queryMap.get("viewId"); - minx = Double.valueOf(queryMap.get("x")); - miny = Double.valueOf(queryMap.get("y")); - Canvas c = null; try { + // get data of the current request + // variable definitions + String response; + String canvasId, viewId; + double minx, miny; + BoxandData data = null; + + // check if this is a POST request + if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); + return; + } + + // get data of the current request + String query = httpExchange.getRequestURI().getQuery(); + Map queryMap = Server.queryToMap(query); + // print + for (String s : queryMap.keySet()) System.out.println(s + " : " + queryMap.get(s)); + + // check parameters, if not pass, send a bad request response + response = checkParameters(queryMap); + if (response.length() > 0) { + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_REQUEST, response); + return; + } + // get parameters + canvasId = queryMap.get("id"); + viewId = queryMap.get("viewId"); + minx = Double.valueOf(queryMap.get("x")); + miny = Double.valueOf(queryMap.get("y")); + Canvas c = null; c = Main.getProject().getCanvas(canvasId).deepCopy(); - } catch (Exception e) { - e.printStackTrace(); - } - View v = Main.getProject().getView(viewId); - if (queryMap.containsKey("canvasw")) c.setW(Integer.valueOf(queryMap.get("canvasw"))); - if (queryMap.containsKey("canvash")) c.setH(Integer.valueOf(queryMap.get("canvash"))); - ArrayList predicates = new ArrayList<>(); - for (int i = 0; i < c.getLayers().size(); i++) - predicates.add(queryMap.get("predicate" + i)); - double oMinX = Double.valueOf(queryMap.get("oboxx")); - double oMinY = Double.valueOf(queryMap.get("oboxy")); - double oMaxX = oMinX + Double.valueOf(queryMap.get("oboxw")); - double oMaxY = oMinY + Double.valueOf(queryMap.get("oboxh")); - Box oldBox = new Box(oMinX, oMinY, oMaxX, oMaxY); - Boolean isJumping = Boolean.valueOf(queryMap.get("isJumping")); - - // get box data - long st = System.currentTimeMillis(); - try { + View v = Main.getProject().getView(viewId); + if (queryMap.containsKey("canvasw")) c.setW(Integer.valueOf(queryMap.get("canvasw"))); + if (queryMap.containsKey("canvash")) c.setH(Integer.valueOf(queryMap.get("canvash"))); + ArrayList predicates = new ArrayList<>(); + for (int i = 0; i < c.getLayers().size(); i++) + predicates.add(queryMap.get("predicate" + i)); + double oMinX = Double.valueOf(queryMap.get("oboxx")); + double oMinY = Double.valueOf(queryMap.get("oboxy")); + double oMaxX = oMinX + Double.valueOf(queryMap.get("oboxw")); + double oMaxY = oMinY + Double.valueOf(queryMap.get("oboxh")); + Box oldBox = new Box(oMinX, oMinY, oMaxX, oMaxY); + Boolean isJumping = Boolean.valueOf(queryMap.get("isJumping")); + + // get box data + long st = System.currentTimeMillis(); data = boxGetter.getBox(c, v, minx, miny, oldBox, predicates); + double fetchTime = System.currentTimeMillis() - st; + int intersectingRows = 0; + for (int i = 0; i < data.data.size(); i++) { + intersectingRows += data.data.get(i).size(); + } + System.out.println("Fetch data time: " + fetchTime + "ms."); + System.out.println("number of intersecting rows in result: " + intersectingRows); + + // TODO: improve this by not sending insert query every time there is a user + // interaction, + // instead, store in prepare statement (idk if that would work?) + // or in-memory data structure and flush to db in batches + if (isJumping) { + Server.sendStats( + Main.getProject().getName(), + c.getId(), + "jump", + fetchTime, + intersectingRows); + } else { + Server.sendStats( + Main.getProject().getName(), c.getId(), "pan", fetchTime, intersectingRows); + } + + // send data and box back + Map respMap = new HashMap<>(); + respMap.put("renderData", BoxandData.getDictionaryFromData(data.data, c)); + respMap.put("minx", data.box.getMinx()); + respMap.put("miny", data.box.getMiny()); + respMap.put("boxH", data.box.getHeight()); + respMap.put("boxW", data.box.getWidth()); + respMap.put("canvasId", canvasId); + response = gson.toJson(respMap); + + // send back response + st = System.currentTimeMillis(); + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, response); + System.out.println("Send response time: " + (System.currentTimeMillis() - st) + "ms."); + System.out.println(); } catch (Exception e) { e.printStackTrace(); + System.out.println("\n\n" + e.getMessage() + "\n"); + Server.printServingErrorMessage(); } - double fetchTime = System.currentTimeMillis() - st; - int intersectingRows = 0; - for (int i = 0; i < data.data.size(); i++) { - intersectingRows += data.data.get(i).size(); - } - System.out.println("Fetch data time: " + fetchTime + "ms."); - System.out.println("number of intersecting rows in result: " + intersectingRows); - - // TODO: improve this by not sending insert query every time there is a user interaction, - // instead, store in prepare statement (idk if that would work?) - // or in-memory data structure and flush to db in batches - if (isJumping) { - Server.sendStats( - Main.getProject().getName(), c.getId(), "jump", fetchTime, intersectingRows); - } else { - Server.sendStats( - Main.getProject().getName(), c.getId(), "pan", fetchTime, intersectingRows); - } - - // send data and box back - Map respMap = new HashMap<>(); - respMap.put("renderData", BoxandData.getDictionaryFromData(data.data, c)); - respMap.put("minx", data.box.getMinx()); - respMap.put("miny", data.box.getMiny()); - respMap.put("boxH", data.box.getHeight()); - respMap.put("boxW", data.box.getWidth()); - respMap.put("canvasId", canvasId); - response = gson.toJson(respMap); - - // send back response - st = System.currentTimeMillis(); - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, response); - System.out.println("Send response time: " + (System.currentTimeMillis() - st) + "ms."); - System.out.println(); } private String checkParameters(Map queryMap) { diff --git a/back-end/src/main/java/server/CanvasRequestHandler.java b/back-end/src/main/java/server/CanvasRequestHandler.java index 3b99fc74..1c821b47 100644 --- a/back-end/src/main/java/server/CanvasRequestHandler.java +++ b/back-end/src/main/java/server/CanvasRequestHandler.java @@ -33,66 +33,58 @@ public void handle(HttpExchange httpExchange) throws IOException { System.out.println("Serving /canvas"); - // check if this is a POST request - if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); - return; - } + try { + // check if this is a POST request + if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); + return; + } - // get data of the current request - String query = httpExchange.getRequestURI().getQuery(); - Map queryMap = Server.queryToMap(query); - String canvasId = queryMap.get("id"); + // get data of the current request + String query = httpExchange.getRequestURI().getQuery(); + Map queryMap = Server.queryToMap(query); + String canvasId = queryMap.get("id"); - // get the current canvas - Canvas c = null; - try { + // get the current canvas + Canvas c = null; c = Main.getProject().getCanvas(canvasId).deepCopy(); - } catch (Exception e) { - e.printStackTrace(); - } - // list of predicates - ArrayList predicates = new ArrayList<>(); - for (int i = 0; i < c.getLayers().size(); i++) - predicates.add(queryMap.get("predicate" + i)); - - // calculate w or h if they are not pre-determined - if (c.getwSql().length() > 0) { - String predicate = queryMap.get("predicate" + c.getwLayerId()); - String sql = c.getwSql() + (predicate.length() > 0 ? " and " + predicate : ""); - String db = c.getDbByLayerId(c.getwLayerId()); - try { + // list of predicates + ArrayList predicates = new ArrayList<>(); + for (int i = 0; i < c.getLayers().size(); i++) + predicates.add(queryMap.get("predicate" + i)); + + // calculate w or h if they are not pre-determined + if (c.getwSql().length() > 0) { + String predicate = queryMap.get("predicate" + c.getwLayerId()); + String sql = c.getwSql() + (predicate.length() > 0 ? " and " + predicate : ""); + String db = c.getDbByLayerId(c.getwLayerId()); c.setW(getWidthOrHeightBySql(sql, db)); - } catch (Exception e) { } - } - if (c.gethSql().length() > 0) { - String predicate = queryMap.get("predicate" + c.gethLayerId()); - String sql = c.gethSql() + (predicate.length() > 0 ? " and " + predicate : ""); - String db = c.getDbByLayerId(c.gethLayerId()); - try { + if (c.gethSql().length() > 0) { + String predicate = queryMap.get("predicate" + c.gethLayerId()); + String sql = c.gethSql() + (predicate.length() > 0 ? " and " + predicate : ""); + String db = c.getDbByLayerId(c.gethLayerId()); c.setH(getWidthOrHeightBySql(sql, db)); - } catch (Exception e) { } - } - // get static data - ArrayList>> staticData = null; - try { + // get static data + ArrayList>> staticData = null; staticData = getStaticData(c, predicates); + + // construct the response object + Map respMap = new HashMap<>(); + respMap.put("canvas", c); + respMap.put("staticData", BoxandData.getDictionaryFromData(staticData, c)); + String response = gson.toJson(respMap); + + // send the response back + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, response); } catch (Exception e) { e.printStackTrace(); + System.out.println("\n\n" + e.getMessage() + "\n"); + Server.printServingErrorMessage(); } - - // construct the response object - Map respMap = new HashMap<>(); - respMap.put("canvas", c); - respMap.put("staticData", BoxandData.getDictionaryFromData(staticData, c)); - String response = gson.toJson(respMap); - - // send the response back - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, response); } private int getWidthOrHeightBySql(String sql, String db) diff --git a/back-end/src/main/java/server/FirstRequestHandler.java b/back-end/src/main/java/server/FirstRequestHandler.java index 53423830..09f4d407 100644 --- a/back-end/src/main/java/server/FirstRequestHandler.java +++ b/back-end/src/main/java/server/FirstRequestHandler.java @@ -27,23 +27,29 @@ public void handle(HttpExchange httpExchange) throws IOException { System.out.println("Serving /first"); - // check if this is a POST request - if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); - return; + try { + // check if this is a POST request + if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); + return; + } + + // get the project + Project project = Main.getProject(); + + // construct a response map + Map respMap = new HashMap<>(); + respMap.put("project", project); + respMap.put("tileH", Config.tileH); + respMap.put("tileW", Config.tileW); + + // convert the response to a json object and send it back + String response = gson.toJson(respMap); + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, response); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("\n\n" + e.getMessage() + "\n"); + Server.printServingErrorMessage(); } - - // get the project - Project project = Main.getProject(); - - // construct a response map - Map respMap = new HashMap<>(); - respMap.put("project", project); - respMap.put("tileH", Config.tileH); - respMap.put("tileW", Config.tileW); - - // convert the response to a json object and send it back - String response = gson.toJson(respMap); - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, response); } } diff --git a/back-end/src/main/java/server/IndexHandler.java b/back-end/src/main/java/server/IndexHandler.java index 643e4f91..072367d2 100644 --- a/back-end/src/main/java/server/IndexHandler.java +++ b/back-end/src/main/java/server/IndexHandler.java @@ -14,32 +14,39 @@ public class IndexHandler implements HttpHandler { public void handle(HttpExchange httpExchange) throws IOException { System.out.println("Serving /"); - System.out.println(httpExchange.getRequestURI().getPath()); - // check if it is GET request - if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); - return; - } + try { + System.out.println(httpExchange.getRequestURI().getPath()); - String path = httpExchange.getRequestURI().getPath(); - if (path.equals("/")) path = "/" + Config.indexFileName; + // check if it is GET request + if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); + return; + } - // read the frontend file and return - FileInputStream fs = new FileInputStream(Config.webRoot + path); - final byte[] content = new byte[0x1000000]; - int len = fs.read(content); + String path = httpExchange.getRequestURI().getPath(); + if (path.equals("/")) path = "/" + Config.indexFileName; - // send back a ok response - if (path.contains(".svg")) // todo: better file checking for the index handler - Server.sendResponse( - httpExchange, HttpsURLConnection.HTTP_OK, content, len, "image/svg+xml"); - else if (path.contains(".png")) - Server.sendResponse( - httpExchange, HttpsURLConnection.HTTP_OK, content, len, "image/png"); - else if (path.contains(".jpg")) + // read the frontend file and return + FileInputStream fs = new FileInputStream(Config.webRoot + path); + final byte[] content = new byte[0x1000000]; + int len = fs.read(content); + + // send back a ok response + if (path.contains(".svg")) // todo: better file checking for the index handler Server.sendResponse( - httpExchange, HttpsURLConnection.HTTP_OK, content, len, "image/jpg"); - else Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, content, len); + httpExchange, HttpsURLConnection.HTTP_OK, content, len, "image/svg+xml"); + else if (path.contains(".png")) + Server.sendResponse( + httpExchange, HttpsURLConnection.HTTP_OK, content, len, "image/png"); + else if (path.contains(".jpg")) + Server.sendResponse( + httpExchange, HttpsURLConnection.HTTP_OK, content, len, "image/jpg"); + else Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, content, len); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("\n\n" + e.getMessage() + "\n"); + Server.printServingErrorMessage(); + } } } diff --git a/back-end/src/main/java/server/ProjectRequestHandler.java b/back-end/src/main/java/server/ProjectRequestHandler.java index 97f770f4..ed76a507 100644 --- a/back-end/src/main/java/server/ProjectRequestHandler.java +++ b/back-end/src/main/java/server/ProjectRequestHandler.java @@ -44,9 +44,9 @@ private void addProjectObject(Project proj) { @Override public void handle(HttpExchange httpExchange) throws IOException { - try { - System.out.println("\n\nServing /project\n New project definition coming..."); + System.out.println("\n\nServing /project\n New project definition coming..."); + try { // check if this is a POST request if (!httpExchange.getRequestMethod().equalsIgnoreCase("POST")) { Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); @@ -104,6 +104,8 @@ public void handle(HttpExchange httpExchange) throws IOException { } } catch (Exception e) { e.printStackTrace(); + System.out.println("\n\n" + e.getMessage() + "\n"); + Server.printServingErrorMessage(); } } diff --git a/back-end/src/main/java/server/Server.java b/back-end/src/main/java/server/Server.java index 1819f934..0b5d408e 100644 --- a/back-end/src/main/java/server/Server.java +++ b/back-end/src/main/java/server/Server.java @@ -40,13 +40,56 @@ public static void startServer(int portNumber) throws Exception { while (!terminated) terminationLock.wait(); } Server.stopServer(); - DbConnector.closeConnection(Config.databaseName); - Indexer.precompute(); - Main.setProjectClean(); - System.out.println("Completed recomputing indexes. Server restarting..."); + try { + DbConnector.closeConnection(Config.databaseName); + Indexer.precompute(); + Main.setProjectClean(); + System.out.println("Completed recomputing indexes. Server restarting..."); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("\n\n" + e.getMessage() + "\n"); + printIndexingErrorMessage(); + Main.setProject(null); + DbConnector.closeAllConnections(); + System.out.println("Server restarting...."); + } Server.startServer(Config.portNumber); } + public static void printIndexingErrorMessage() { + System.out.println( + "+---------------------------------------------------------+\n" + + "|ERROR!!! An exception occurred while indexing. |\n" + + "|This is likely due to errors in database related things, |\n" + + "|e.g. a mis-formed SQL query in the specification, a non- |\n" + + "|existent column you specified, or the data isn't loaded |\n" + + "|into the database. |\n" + + "| |\n" + + "|Indexing is now terminated and the server is restarted. |\n" + + "|Please inspect your spec and database, and then recompile|\n" + + "|the project.If you can't figure out the issue, feel free |\n" + + "|to contact Kyrix maintainers. |\n" + + "| |\n" + + "|Github: https://github.com/tracyhenry/kyrix |\n" + + "+---------------------------------------------------------+"); + } + + public static void printServingErrorMessage() { + System.out.println( + "+-------------------------------------------------------------+\n" + + "|ERROR!!! An exception occurred while serving an HTTP request.|\n" + + "|This is likely due to errors in database related things, |\n" + + "|e.g. a non-existent column you specified, or deleted/- |\n" + + "|corrupted database indexes. |\n" + + "| |\n" + + "|The server will continue running, but the error will likely |\n" + + "|occur again. You can recompile the project to recompute the |\n" + + "|indexes, or reach out to the kyrix maintainers for help. |\n" + + "| |\n" + + "|Github: https://github.com/tracyhenry/kyrix |\n" + + "+-------------------------------------------------------------+"); + } + public static void terminate() { terminated = true; diff --git a/back-end/src/main/java/server/TileRequestHandler.java b/back-end/src/main/java/server/TileRequestHandler.java index 068f8370..476ac540 100644 --- a/back-end/src/main/java/server/TileRequestHandler.java +++ b/back-end/src/main/java/server/TileRequestHandler.java @@ -32,74 +32,80 @@ public void handle(HttpExchange httpExchange) throws IOException { // TODO: this method should be thread safe, allowing concurrent requests System.out.println("\nServing /tile"); - // variable definitions - String response; - String canvasId; - int minx, miny; - ArrayList>> data = null; - - // check if this is a POST request - if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); - return; - } - - // get data of the current request - String query = httpExchange.getRequestURI().getQuery(); - Map queryMap = Server.queryToMap(query); - // print - for (String s : queryMap.keySet()) System.out.println(s + " : " + queryMap.get(s)); - - // check parameters, if not pass, send a bad request response - response = checkParameters(queryMap); - if (response.length() > 0) { - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_REQUEST, response); - return; - } - - // get data - canvasId = queryMap.get("id"); - minx = Integer.valueOf(queryMap.get("x")); - miny = Integer.valueOf(queryMap.get("y")); - Canvas c = Main.getProject().getCanvas(canvasId); - ArrayList predicates = new ArrayList<>(); - for (int i = 0; i < c.getLayers().size(); i++) - predicates.add(queryMap.get("predicate" + i)); - Boolean isJumping = Boolean.valueOf(queryMap.get("isJumping")); - long st = System.currentTimeMillis(); try { + // variable definitions + String response; + String canvasId; + int minx, miny; + ArrayList>> data = null; + + // check if this is a POST request + if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); + return; + } + + // get data of the current request + String query = httpExchange.getRequestURI().getQuery(); + Map queryMap = Server.queryToMap(query); + // print + for (String s : queryMap.keySet()) System.out.println(s + " : " + queryMap.get(s)); + + // check parameters, if not pass, send a bad request response + response = checkParameters(queryMap); + if (response.length() > 0) { + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_REQUEST, response); + return; + } + + // get data + canvasId = queryMap.get("id"); + minx = Integer.valueOf(queryMap.get("x")); + miny = Integer.valueOf(queryMap.get("y")); + Canvas c = Main.getProject().getCanvas(canvasId); + ArrayList predicates = new ArrayList<>(); + for (int i = 0; i < c.getLayers().size(); i++) + predicates.add(queryMap.get("predicate" + i)); + Boolean isJumping = Boolean.valueOf(queryMap.get("isJumping")); + long st = System.currentTimeMillis(); data = TileCache.getTile(c, minx, miny, predicates); + + double fetchTime = System.currentTimeMillis() - st; + int intersectingRows = 0; + for (int i = 0; i < data.size(); i++) { + intersectingRows += data.get(i).size(); + } + System.out.println("Fetch data time: " + fetchTime + "ms."); + System.out.println("number of intersecting rows in result: " + intersectingRows); + + if (isJumping) { + Server.sendStats( + Main.getProject().getName(), + c.getId(), + "jump", + fetchTime, + intersectingRows); + } else { + Server.sendStats( + Main.getProject().getName(), c.getId(), "pan", fetchTime, intersectingRows); + } + + // construct response + Map respMap = new HashMap<>(); + respMap.put("renderData", BoxandData.getDictionaryFromData(data, c)); + respMap.put("minx", minx); + respMap.put("miny", miny); + respMap.put("canvasId", canvasId); + response = gson.toJson(respMap); + + // send back response + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, response); + System.out.println(); } catch (Exception e) { e.printStackTrace(); + System.out.println("\n\n" + e.getMessage() + "\n"); + Server.printServingErrorMessage(); } - - double fetchTime = System.currentTimeMillis() - st; - int intersectingRows = 0; - for (int i = 0; i < data.size(); i++) { - intersectingRows += data.get(i).size(); - } - System.out.println("Fetch data time: " + fetchTime + "ms."); - System.out.println("number of intersecting rows in result: " + intersectingRows); - - if (isJumping) { - Server.sendStats( - Main.getProject().getName(), c.getId(), "jump", fetchTime, intersectingRows); - } else { - Server.sendStats( - Main.getProject().getName(), c.getId(), "pan", fetchTime, intersectingRows); - } - - // construct response - Map respMap = new HashMap<>(); - respMap.put("renderData", BoxandData.getDictionaryFromData(data, c)); - respMap.put("minx", minx); - respMap.put("miny", miny); - respMap.put("canvasId", canvasId); - response = gson.toJson(respMap); - - // send back response - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, response); - System.out.println(); } // check paramters diff --git a/back-end/src/main/java/server/ViewportRequestHandler.java b/back-end/src/main/java/server/ViewportRequestHandler.java index 6e937f66..1e86afb1 100644 --- a/back-end/src/main/java/server/ViewportRequestHandler.java +++ b/back-end/src/main/java/server/ViewportRequestHandler.java @@ -33,57 +33,59 @@ public void handle(HttpExchange httpExchange) throws IOException { // TODO: this method should be thread safe, allowing concurrent requests System.out.println("Serving /viewport"); - // variable definitions - String response; - String canvasId; - ArrayList predicates = new ArrayList<>(); - ArrayList data = null; - - // check if this is a POST request - if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); - return; - } + try { + // variable definitions + String response; + String canvasId; + ArrayList predicates = new ArrayList<>(); + ArrayList data = null; + + // check if this is a POST request + if (!httpExchange.getRequestMethod().equalsIgnoreCase("GET")) { + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_METHOD, ""); + return; + } - // get data of the current request - String query = httpExchange.getRequestURI().getQuery(); - Map queryMap = Server.queryToMap(query); - // print - for (String s : queryMap.keySet()) System.out.println(s + " : " + queryMap.get(s)); - System.out.println(); - - // check parameters, if not pass, send a bad request response - response = checkParameters(queryMap); - if (response.length() > 0) { - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_REQUEST, response); - return; - } + // get data of the current request + String query = httpExchange.getRequestURI().getQuery(); + Map queryMap = Server.queryToMap(query); + // print + for (String s : queryMap.keySet()) System.out.println(s + " : " + queryMap.get(s)); + System.out.println(); + + // check parameters, if not pass, send a bad request response + response = checkParameters(queryMap); + if (response.length() > 0) { + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_BAD_REQUEST, response); + return; + } - // get data - canvasId = queryMap.get("canvasId"); - Canvas c = Main.getProject().getCanvas(canvasId); - for (int i = 0; i < c.getLayers().size(); i++) - predicates.add(queryMap.get("predicate" + i)); - try { + // get data + canvasId = queryMap.get("canvasId"); + Canvas c = Main.getProject().getCanvas(canvasId); + for (int i = 0; i < c.getLayers().size(); i++) + predicates.add(queryMap.get("predicate" + i)); data = getData(canvasId, predicates); - } catch (Exception e) { - e.printStackTrace(); - } - if (data == null) { - Server.sendResponse( - httpExchange, HttpsURLConnection.HTTP_BAD_REQUEST, "Bad predicates."); - return; - } + if (data == null) { + Server.sendResponse( + httpExchange, HttpsURLConnection.HTTP_BAD_REQUEST, "Bad predicates."); + return; + } - // construct response - Map respMap = new HashMap<>(); - respMap.put("cx", data.get(0)); - respMap.put("cy", data.get(1)); - response = gson.toJson(respMap); + // construct response + Map respMap = new HashMap<>(); + respMap.put("cx", data.get(0)); + respMap.put("cy", data.get(1)); + response = gson.toJson(respMap); - // send back response - Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, response); + // send back response + Server.sendResponse(httpExchange, HttpsURLConnection.HTTP_OK, response); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("\n\n" + e.getMessage() + "\n"); + Server.printServingErrorMessage(); + } } private String checkParameters(Map queryMap) {