From 4712d0c15819127615a9c6bc69c89b78487967e3 Mon Sep 17 00:00:00 2001 From: Nikolaus Krismer <niko@krismer.de> Date: Wed, 19 Mar 2014 16:14:27 +0100 Subject: [PATCH] changed method order changed getAdjLinks method (a little) --- .../it/unibz/inf/isochrone/db/Database.java | 846 +++++++++--------- .../it/unibz/inf/isoga/db/DatabaseWeb.java | 236 ++--- 2 files changed, 542 insertions(+), 540 deletions(-) diff --git a/src/main/java/it/unibz/inf/isochrone/db/Database.java b/src/main/java/it/unibz/inf/isochrone/db/Database.java index 6e901b89..36508592 100644 --- a/src/main/java/it/unibz/inf/isochrone/db/Database.java +++ b/src/main/java/it/unibz/inf/isochrone/db/Database.java @@ -65,6 +65,8 @@ public class Database<T extends ConfigDataset> { protected boolean isIncoming; protected Connection connection; + // Constructor + public Database(final T config, final Mode mode, final Direction direction) { this.config = config; this.isIncoming = (direction == Direction.INCOMING); @@ -73,212 +75,265 @@ public class Database<T extends ConfigDataset> { connection = ConfigIsochrone.getInstance().getConnection(); pstmtsCacheMap = new HashMap<String, PreparedStatement>(); + final String configDatecodes = config.getTableDatecodes(); + final String configEdges = config.getTableEdges(); + final String configSchedule = config.getTableSchedule(); + final String configVertex = config.getTableVertex(); + final String configVertexDensity = config.getTableVertexDensity(); + queryLatestDepartureTimeHomo = "SELECT TIME_D, TIME_A, ROUTE_ID FROM (" + " SELECT TIME_D,TIME_A,ROUTE_ID FROM " - + config.getTableSchedule() + + configSchedule + " WHERE SOURCE = ? AND TARGET = ? AND ROUTE_ID IN (%S) AND TIME_A>=? AND TIME_A<=? AND SERVICE_ID IN (%S)) C WHERE TIME_D >= ?"; queryEarliestArrivalTimeHomo = "SELECT TIME_D, TIME_A, ROUTE_ID FROM (" + " SELECT TIME_D, TIME_A, ROUTE_ID FROM " - + config.getTableSchedule() + + configSchedule + " WHERE SOURCE = ? AND TARGET = ? AND ROUTE_ID IN (%S) AND TIME_D>=? AND TIME_D<=?" + " AND SERVICE_ID IN (%S)) C WHERE TIME_A <= ?"; - queryGetAllEdges = "SELECT ID, SOURCE, TARGET, LENGTH, EDGE_MODE, ROUTE_ID FROM " + config.getTableEdges(); + queryGetAllEdges = "SELECT ID, SOURCE, TARGET, LENGTH, EDGE_MODE, ROUTE_ID FROM " + configEdges; - queryGetContinuousEdges = "SELECT ID, SOURCE, TARGET, LENGTH, EDGE_MODE, ROUTE_ID FROM " + config.getTableEdges() + " WHERE EDGE_MODE=" + NW_MODE_CONTINUOUS; + queryGetContinuousEdges = "SELECT ID, SOURCE, TARGET, LENGTH, EDGE_MODE, ROUTE_ID FROM " + configEdges + " WHERE EDGE_MODE=" + NW_MODE_CONTINUOUS; queryGetDateCodes = "SELECT DISTINCT SERVICE_ID " + " FROM " - + config.getTableDaymarker() + + configDatecodes + " WHERE (((MONDAY::int::bit || TUESDAY::int::bit || WEDNESDAY::int::bit || THURSDAY::int::bit" + " || FRIDAY::int::bit || SATURDAY::int::bit || SUNDAY::int::bit) & ?::bit(7))::int) > 0" + " AND START_DATE <= ? AND END_DATE >= ? " + " ORDER BY SERVICE_ID"; - queryGetCoordinatesFromNode = "SELECT ID,ST_X(GEOMETRY) X, ST_Y(GEOMETRY) Y FROM " + config.getTableVertex() + " WHERE ID=?"; + queryGetCoordinatesFromNode = "SELECT ID,ST_X(GEOMETRY) X, ST_Y(GEOMETRY) Y FROM " + configVertex + " WHERE ID=?"; queryGetRange = "select D0.DENSITY s0, D0.E_DISTANCE ed0, D1.DENSITY s1, D1.E_DISTANCE ed1 from " + "(SELECT ID,DENSITY,E_DISTANCE FROM " - + config.getTableVertexDensity() + + configVertexDensity + " WHERE ID=? AND DENSITY<? ORDER BY DENSITY DESC LIMIT 1) D0 FULL JOIN " + "(SELECT ID,DENSITY,E_DISTANCE FROM " - + config.getTableVertexDensity() + + configVertexDensity + " WHERE ID=? AND DENSITY>=? ORDER BY DENSITY ASC LIMIT 1) D1 ON D0.ID=D1.ID"; queryLoadLinksFromIER = "SELECT L.ID, L.SOURCE,L.SOURCE_MODE,L.TARGET,L.TARGET_MODE,L.LENGTH,L.EDGE_MODE,L.ROUTE_ID," + (isIncoming ? "L.SOURCE_OUTDEGREE" : "L.TARGET_INDEGREE") - + " DEGREE FROM " + config.getTableEdges() + " L, " - + config.getTableVertex() + " N " + + " DEGREE FROM " + configEdges + " L, " + + configVertex + " N " + " WHERE L." + (isIncoming ? "TARGET" : "SOURCE") + "=N.ID" + " AND ST_DWITHIN(ST_PointFromText(?,?),N.GEOMETRY,?)='TRUE'"; queryGetLink = "SELECT SOURCE, TARGET, " + (isIncoming ? "SOURCE_OUTDEGREE" : "TARGET_INDEGREE") - + " NODE_DEGREE, LENGTH FROM " + config.getTableEdges() + + " NODE_DEGREE, LENGTH FROM " + configEdges + " WHERE ID = ? AND EDGE_MODE=" + NW_MODE_CONTINUOUS; queryGetContinuousLink = "SELECT SOURCE, TARGET, " + (isIncoming ? "SOURCE_C_OUTDEGREE" : "TARGET_C_INDEGREE") - + " NODE_DEGREE, LENGTH FROM " + config.getTableEdges() + + " NODE_DEGREE, LENGTH FROM " + configEdges + " WHERE ID = ? AND EDGE_MODE=" + NW_MODE_CONTINUOUS; queryGetContinuousNode = "SELECT " + (isIncoming ? "SOURCE_C_OUTDEGREE" : "TARGET_C_INDEGREE") - + " NODE_DEGREE FROM " + config.getTableEdges() + + " NODE_DEGREE FROM " + configEdges + (isIncoming ? "SOURCE=?" : "TARGET=?") + "AND EDGE_MODE=" + NW_MODE_CONTINUOUS; queryGetMrneXNode = "SELECT " + (isIncoming ? "OUTDEGREE" : "INDEGREE") - + " NODE_DEGREE, ST_X(GEOMETRY) X, ST_Y(GEOMETRY) Y FROM " + config.getTableVertex() + " WHERE ID=?"; + + " NODE_DEGREE, ST_X(GEOMETRY) X, ST_Y(GEOMETRY) Y FROM " + configVertex + " WHERE ID=?"; queryGetLinksInRange = "SELECT L.ID,L.SOURCE,L.SOURCE_MODE,L.TARGET,L.TARGET_MODE,L.LENGTH,L.EDGE_MODE,L.ROUTE_ID," - + (isIncoming ? "L.SOURCE_OUTDEGREE" : "L.TARGET_INDEGREE") + " DEGREE FROM " + config.getTableEdges() - + " L, " + config.getTableVertex() + " N WHERE L." + (isIncoming ? "TARGET" : "SOURCE") + + (isIncoming ? "L.SOURCE_OUTDEGREE" : "L.TARGET_INDEGREE") + " DEGREE FROM " + configEdges + + " L, " + configVertex + " N WHERE L." + (isIncoming ? "TARGET" : "SOURCE") + "=N.ID AND st_intersects(N.GEOMETRY,%S)"; if (isIncoming) { - queryGetAdjLinks = "SELECT ID,SOURCE NODE_ID,SOURCE_OUTDEGREE NODE_DEGREE,LENGTH,EDGE_MODE,ROUTE_ID FROM " + config.getTableEdges() + " WHERE TARGET=?"; - queryGetAdjContinuousLinks = "SELECT ID,SOURCE NODE_ID,SOURCE_C_OUTDEGREE NODE_DEGREE,LENGTH,EDGE_MODE,ROUTE_ID FROM " + config.getTableEdges() - + " WHERE TARGET=? AND EDGE_MODE=" + NW_MODE_CONTINUOUS; + queryGetAdjLinks = "SELECT ID, SOURCE NODE_ID, SOURCE_OUTDEGREE NODE_DEGREE, LENGTH, EDGE_MODE, ROUTE_ID FROM " + + configEdges + " WHERE TARGET=?"; + queryGetAdjContinuousLinks = "SELECT ID, SOURCE NODE_ID, SOURCE_C_OUTDEGREE NODE_DEGREE, LENGTH, EDGE_MODE, ROUTE_ID FROM " + + configEdges + " WHERE TARGET=? AND EDGE_MODE=" + NW_MODE_CONTINUOUS; + } else { + queryGetAdjLinks = "SELECT ID, TARGET NODE_ID, TARGET_INDEGREE NODE_DEGREE, LENGTH, EDGE_MODE, ROUTE_ID FROM " + + configEdges + " WHERE SOURCE=?"; + queryGetAdjContinuousLinks = "SELECT ID, TARGET NODE_ID, TARGET_C_INDEGREE NODE_DEGREE, LENGTH FROM " + + configEdges + " WHERE TARGET=? AND EDGE_MODE="; + } + } + + // Public methods + + public void addLink(final Link link, final short degree, final Map<Integer, Node> nodes, final Map<Integer, List<Link>> adjList) { + int n1, n2; + if (isIncoming) { + n1 = link.getStartNode(); + n2 = link.getEndNode(); } else { - queryGetAdjLinks = "SELECT ID,TARGET NODE_ID,TARGET_INDEGREE NODE_DEGREE, LENGTH,EDGE_MODE,ROUTE_ID FROM " + config.getTableEdges() + " WHERE SOURCE=?"; - queryGetAdjContinuousLinks = "SELECT ID,TARGET NODE_ID, TARGET_C_INDEGREE NODE_DEGREE,LENGTH FROM " + config.getTableEdges() + " WHERE TARGET=? AND EDGE_MODE="; + n1 = link.getEndNode(); + n2 = link.getStartNode(); + } + + addNode(n1, degree, nodes); + addNode(n2, nodes); + if (!adjList.containsKey(n2)) { + adjList.put(n2, new ArrayList<Link>()); } + + adjList.get(n2).add(link); } /** - * Gets a prepared statement and caches it in a map. This - * is much more efficient than creating a new prepared statement - * each time a query needs to be called, and recalculating the - * queryplan each time. + * Closes all the open prepared statements and the database connection. + * This should be called once you're done with the database. + */ + public void close() { + for (final PreparedStatement pstmt : pstmtsCacheMap.values()) { + DbUtils.closeQuietly(pstmt); + } + } + + /** + * Gets all links adjacent to a given node. * - * @param query The prepared statement that is needed - * @return the cached prepared statement object + * @param nodeId the node to which the links should be adjacent + * @param nodes the nodes HashMap to which eventual new nodes should be added + * @return a list of links adjacent to the given nodeId */ - // FIXME: Find a fix for prepared statements with parameters - // (we should NOT set strings in preparedStatemens just because we want to cache something) - protected PreparedStatement getPstmt(final String query) { + public Collection<Link> getAdjLinks(final int nodeId, final Map<Integer, Node> nodes) { + final PreparedStatement stmt = getPstmt((mode == Mode.UNIMODAL) ? queryGetAdjContinuousLinks : queryGetAdjLinks); + final Collection<Link> adjLinks = new ArrayList<Link>(); + + ResultSet rs = null; try { - if (pstmtsCacheMap.containsKey(query) && !pstmtsCacheMap.get(query).isClosed()) { - return pstmtsCacheMap.get(query); + stmt.setInt(1, nodeId); + rs = stmt.executeQuery(); + while (rs.next()) { + final int adjNodeId = rs.getInt("NODE_ID"); + final short degree = rs.getShort("NODE_DEGREE"); + addNode(adjNodeId, degree, nodes); + adjLinks.add(createLinkFromResultSet(nodeId, adjNodeId, rs)); } - - final PreparedStatement pstmt = connection.prepareStatement(query); - pstmtsCacheMap.put(query, pstmt); - return pstmt; } catch (final SQLException e) { e.printStackTrace(); + } finally { + DbUtils.closeQuietly(rs); } - return null; + return adjLinks; } /** - * Reads the whole network for the MDijkstra Algorithm. - * The given maps have to be initialized and will be filled up with - * the nodes and links in the network. + * Gets the cost to go from one node to another node. * - * @param nodes A map in which all the nodes should be stored. - * @param links A map in which all the links should be stored. + * @param node the node from which we should start calculating + * @param adjNode the node to which we want to calculate the cost + * @param routeIds the routeIds that should be taken into consideration + * @param dateCodes the days that should be taken into the account + * @param fromTime the earliest time for which we want to calculate the departure time + * @param toTime the latest time for which we want to calculate the departure time + * @return the cost of for traveling from the start node to the end node */ - public void readNetwork(final Map<Integer, Node> nodes, final Map<Integer, Link> links) { + public double getAdjNodeCost(final Node node, final Node adjNode, final Set<Short> routeIds, final Set<Integer> dateCodes, final long fromTime, final long toTime) { + double minDistance = Double.POSITIVE_INFINITY; + ResultSet rs = null; try { - PreparedStatement stmt; - if (mode == Mode.MULTIMODAL) { - stmt = getPstmt(queryGetAllEdges); - } else { - stmt = getPstmt(queryGetContinuousEdges); - } - rs = stmt.executeQuery(); - while (rs.next()) { - final int linkId = rs.getInt("ID"); - final int startNodeId = rs.getInt("SOURCE"); - final int endNodeId = rs.getInt("TARGET"); - final double length = rs.getDouble("LENGTH"); - final short routeId = rs.getShort("ROUTE_ID"); - final byte linkType = rs.getByte("EDGE_MODE"); - - int start, end; - if (isIncoming) { - start = startNodeId; - end = endNodeId; - } else { - start = endNodeId; - end = startNodeId; - } - Node node; - if (!nodes.containsKey(end)) { - node = new Node(end); - nodes.put(end, node); - } else { - node = nodes.get(end); - } - if (node.getAdjLinks() == null) { - node.setAdjLinks(new ArrayList<Link>()); - } - Link link; - - if (linkType == NW_MODE_CONTINUOUS) { - link = new Link(linkId, startNodeId, endNodeId, length); - } else { - link = new Link(linkId, startNodeId, endNodeId, routeId); + if (isIncoming) { + rs = getLatestDepartureTime(adjNode.getID(), node.getID(), routeIds, dateCodes, fromTime, Math.round(toTime - node.getDistance())); + while (rs.next()) { + final long departureTime = rs.getLong("TIME_D"); + final long arrivalTime = rs.getLong("TIME_A"); + final short routeId = rs.getShort("ROUTE_ID"); + adjNode.setDepartureTime(routeId, departureTime); + node.setArrivalTime(routeId, arrivalTime); + final double distance = toTime - departureTime; + if (distance < minDistance) { + minDistance = distance; + adjNode.setCheapestReachedRouteId(routeId); + } } - node.addAdjLink(link); - links.put(linkId, link); - if (!nodes.containsKey(start)) { - nodes.put(start, new Node(start)); + } else { + rs = getEarliestArrivalTime(node.getID(), adjNode.getID(), routeIds, dateCodes, Math.round(fromTime + node.getDistance()), toTime); + while (rs.next()) { + final long departureTime = rs.getLong("TIME_D"); + final long arrivalTime = rs.getLong("TIME_A"); + final short routeId = rs.getShort("ROUTE_ID"); + adjNode.setArrivalTime(routeId, arrivalTime); + node.setDepartureTime(routeId, departureTime); + final double distance = arrivalTime > 0 ? arrivalTime - fromTime : Double.POSITIVE_INFINITY; + if (distance < minDistance) { + minDistance = distance; + adjNode.setCheapestReachedRouteId(routeId); + } } } } catch (final SQLException e) { - throw new RuntimeException("Error reading the Network: " + e); + e.printStackTrace(); } finally { DbUtils.closeQuietly(rs); } + + return minDistance; } /** - * Prepares a number of place holders for a prepared statement. + * Gets the coordinates of a node. * - * @param length The number of placeholders that is needed - * @return a string with the placeholders plugged in to a - * statement. + * @param nodeId the nodeId of the node for which we should find the coordinates + * @return a point with the coordinates of the node */ - protected final String preparePlaceHolders(final int length) { - final StringBuilder builder = new StringBuilder(); - for (int i = 0; i < length; ++i) { - builder.append("?"); - if ((i + 1) < length) { - builder.append(","); + public Point getCoordinates(final int nodeId) { + final PreparedStatement stmt = getPstmt(queryGetCoordinatesFromNode); + + Point gp = null; + ResultSet rs = null; + try { + stmt.setInt(1, nodeId); + rs = stmt.executeQuery(); + if (rs.next()) { + gp = new Point(rs.getDouble("X"), rs.getDouble("Y")); } + } catch (final SQLException e) { + e.printStackTrace(); + } finally { + DbUtils.closeQuietly(rs); } - return builder.toString(); + return gp; } /** - * Sets the values in the placeholders in a prepared statement, generated by - * the {@link #preparePlaceHolders(int)} method. + * Gets date codes for a given time. * - * @see #preparePlaceHolders(int) - * @param startIdx the start index where the first object should be placed in the prepared statement - * @param preparedStatement the prepared statement in which the values should be inserted. - * @param values the values that should be inserted into the prepared statement - * @throws SQLException thrown if a parameter could not be set into the prepared statement - * @return the index of the first position that was being left unfilled by the method + * @param time the given + * @return returns a set of date codes */ - protected final int setValues(final int startIdx, final PreparedStatement preparedStatement, final Object... values) throws SQLException { - for (int i = 0; i < values.length; ++i) { - preparedStatement.setObject(startIdx + i, values[i]); + public Set<Integer> getDateCodes(final Calendar time) { + final PreparedStatement stmt = getPstmt(queryGetDateCodes); + final Set<Integer> codes = new HashSet<Integer>(); + + ResultSet rs = null; + try { + final Date date = new Date(time.getTimeInMillis()); + // CHECKSTYLE:OFF MagicNumber + stmt.setString(1, getWeekDayMask(time)); + stmt.setDate(2, date); + stmt.setDate(3, date); + // CHECKSTYLE:ON MagicNumber + + rs = stmt.executeQuery(); + while (rs.next()) { + codes.add(rs.getInt("SERVICE_ID")); + } + } catch (final SQLException e) { + e.printStackTrace(); + } finally { + DbUtils.closeQuietly(rs); } - return startIdx + values.length; + return codes; } /** - * Gets the latest departure time to start from source, to arrive at the target in time. + * Gets the earliest arrival time at the target when traveled from the source. * * @param sourceId the id of the source node * @param targetId the id of the target node @@ -289,8 +344,8 @@ public class Database<T extends ConfigDataset> { * @throws SQLException thrown is the DB update statement can not be executed (or the prepared statement parameters could not be set) * @return a resultSet with all the times that come into consideration */ - public ResultSet getLatestDepartureTime(final int sourceId, final int targetId, final Set<Short> routeIds, final Set<Integer> dateCodes, final long from, final long to) throws SQLException { - final String sql = String.format(queryLatestDepartureTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dateCodes.size())); + public ResultSet getEarliestArrivalTime(final int sourceId, final int targetId, final Set<Short> routeIds, final Set<Integer> dateCodes, final long from, final long to) throws SQLException { + final String sql = String.format(queryEarliestArrivalTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dateCodes.size())); final PreparedStatement statement = getPstmt(sql); // CHECKSTYLE:OFF MagicNumber @@ -300,14 +355,14 @@ public class Database<T extends ConfigDataset> { statement.setLong(idx++, from); statement.setLong(idx++, to); idx = setValues(idx, statement, dateCodes.toArray()); - statement.setLong(idx, from); + statement.setLong(idx, to); // CHECKSTYLE:ON MagicNumber return statement.executeQuery(); } /** - * Gets the earliest arrival time at the target when traveled from the source. + * Gets the latest departure time to start from source, to arrive at the target in time. * * @param sourceId the id of the source node * @param targetId the id of the target node @@ -318,8 +373,8 @@ public class Database<T extends ConfigDataset> { * @throws SQLException thrown is the DB update statement can not be executed (or the prepared statement parameters could not be set) * @return a resultSet with all the times that come into consideration */ - public ResultSet getEarliestArrivalTime(final int sourceId, final int targetId, final Set<Short> routeIds, final Set<Integer> dateCodes, final long from, final long to) throws SQLException { - final String sql = String.format(queryEarliestArrivalTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dateCodes.size())); + public ResultSet getLatestDepartureTime(final int sourceId, final int targetId, final Set<Short> routeIds, final Set<Integer> dateCodes, final long from, final long to) throws SQLException { + final String sql = String.format(queryLatestDepartureTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dateCodes.size())); final PreparedStatement statement = getPstmt(sql); // CHECKSTYLE:OFF MagicNumber @@ -329,117 +384,26 @@ public class Database<T extends ConfigDataset> { statement.setLong(idx++, from); statement.setLong(idx++, to); idx = setValues(idx, statement, dateCodes.toArray()); - statement.setLong(idx, to); + statement.setLong(idx, from); // CHECKSTYLE:ON MagicNumber return statement.executeQuery(); } /** - * Gets the cost to go from one node to another node. + * Get a single link from the network and and add the source + * node to the nodes table if necessary. * - * @param node the node from which we should start calculating - * @param adjNode the node to which we want to calculate the cost - * @param routeIds the routeIds that should be taken into consideration - * @param dateCodes the days that should be taken into the account - * @param fromTime the earliest time for which we want to calculate the departure time - * @param toTime the latest time for which we want to calculate the departure time - * @return the cost of for traveling from the start node to the end node + * @param linkId the id of the link that should be returned + * @param nodes the nodes table to which the node should be added (can only be null if the link is needed) + * @return the link with id linkId */ - public double getAdjNodeCost(final Node node, final Node adjNode, final Set<Short> routeIds, final Set<Integer> dateCodes, final long fromTime, final long toTime) { - double minDistance = Double.POSITIVE_INFINITY; + public Link getLink(final int linkId, final Map<Integer, Node> nodes) { + final PreparedStatement stmt = getPstmt((mode == Mode.UNIMODAL) ? queryGetContinuousLink : queryGetLink); + + Link link = null; ResultSet rs = null; try { - if (isIncoming) { - rs = getLatestDepartureTime(adjNode.getID(), node.getID(), routeIds, dateCodes, fromTime, Math.round(toTime - node.getDistance())); - while (rs.next()) { - final long departureTime = rs.getLong("TIME_D"); - final long arrivalTime = rs.getLong("TIME_A"); - final short routeId = rs.getShort("ROUTE_ID"); - adjNode.setDepartureTime(routeId, departureTime); - node.setArrivalTime(routeId, arrivalTime); - final double distance = toTime - departureTime; - if (distance < minDistance) { - minDistance = distance; - adjNode.setCheapestReachedRouteId(routeId); - } - } - } else { - rs = getEarliestArrivalTime(node.getID(), adjNode.getID(), routeIds, dateCodes, Math.round(fromTime + node.getDistance()), toTime); - while (rs.next()) { - final long departureTime = rs.getLong("TIME_D"); - final long arrivalTime = rs.getLong("TIME_A"); - final short routeId = rs.getShort("ROUTE_ID"); - adjNode.setArrivalTime(routeId, arrivalTime); - node.setDepartureTime(routeId, departureTime); - final double distance = arrivalTime > 0 ? arrivalTime - fromTime : Double.POSITIVE_INFINITY; - if (distance < minDistance) { - minDistance = distance; - adjNode.setCheapestReachedRouteId(routeId); - } - } - } - } catch (final SQLException e) { - e.printStackTrace(); - } finally { - DbUtils.closeQuietly(rs); - } - - return minDistance; - } - - /** - * Adds a node to the network. - * - * @param nodeId The nodeId of the node that should be added - * @param nrAdjLinks The number of links adjacent to the node - * @param nodes The nodes HashMap to which the node should be added - */ - private void addNode(final int nodeId, final short nrAdjLinks, final Map<Integer, Node> nodes) { - if (nodes == null) { - return; // Just for safety - } - - final Node node = nodes.get(nodeId); - if (node == null) { - nodes.put(nodeId, new Node(nodeId, nrAdjLinks)); - } else if (node.getNrAdjacentLinks() == -1) { - node.setNrAdjacentLinks(nrAdjLinks); - } - } - - /** - * Adds a node to the network. - * - * @param nodeId The nodeId of the node that should be added - * @param nodes The HashMap to which the node should be added - */ - private void addNode(final int nodeId, final Map<Integer, Node> nodes) { - if (nodes != null && !nodes.containsKey(nodeId)) { - nodes.put(nodeId, new Node(nodeId)); - } - } - - /** - * Get a single link from the network and and add the source - * node to the nodes table if necessary. - * - * @param linkId The id of the link that should be returned - * @param nodes The nodes table to which the node should be - * added. Can be null if only the link is needed. - * @return The link with id linkId - */ - public Link getLink(final int linkId, final Map<Integer, Node> nodes) { - Link link = null; - PreparedStatement stmt = null; - ResultSet rs = null; - try { - if (mode == Mode.UNIMODAL) { - stmt = getPstmt(queryGetContinuousLink); - } else { - stmt = getPstmt(queryGetLink); - } - stmt.setInt(1, linkId); rs = stmt.executeQuery(); if (rs.next()) { @@ -447,12 +411,13 @@ public class Database<T extends ConfigDataset> { final int targetId = rs.getInt("TARGET"); final short degree = rs.getShort("NODE_DEGREE"); final double length = rs.getDouble("LENGTH"); - link = new Link(linkId, sourceId, targetId, length); if (isIncoming) { addNode(sourceId, degree, nodes); } else { addNode(targetId, degree, nodes); } + + link = new Link(linkId, sourceId, targetId, length); } } catch (final SQLException e) { e.printStackTrace(); @@ -466,21 +431,15 @@ public class Database<T extends ConfigDataset> { /** * Gets a node from the database. * - * @param nodeId The id of the node that should be read from - * the database. + * @param nodeId the id of the node that should be read from the database * @return the node from the database */ public Node getNode(final int nodeId) { + final PreparedStatement stmt = getPstmt((mode == Mode.UNIMODAL) ? queryGetContinuousNode : queryGetMrneXNode); + Node node = null; ResultSet rs = null; try { - PreparedStatement stmt; - if (mode == Mode.UNIMODAL) { - stmt = getPstmt(queryGetContinuousNode); - } else { - stmt = getPstmt(queryGetMrneXNode); - } - stmt.setInt(1, nodeId); rs = stmt.executeQuery(); if (rs.next()) { @@ -499,163 +458,160 @@ public class Database<T extends ConfigDataset> { } /** - * Gets all links adjacent to a given node. + * Returns the maximal range for the given vertex with a maximal number of specified vertices. + * The database query used finds the last two tuples having a memory size smaller than the specified memorySize and then interpolates the range. * - * @param nodeId The node to which the links should be - * adjacent. - * @param nodes The nodes HashMap to which eventual new nodes - * should be added. - * @return a list of links adjacent to the given nodeid + * @param nodeId the vertex identifier + * @param memorySize the maximal number of vertices + * @return the available range as the euclidean distance */ - public Collection<Link> getAdjLinks(final int nodeId, final Map<Integer, Node> nodes) { - final Collection<Link> adjLinks = new ArrayList<Link>(); + public double getRange(final int nodeId, final int memorySize) { + final PreparedStatement stmt = getPstmt(queryGetRange); + ResultSet rs = null; - PreparedStatement stmt = null; try { - if (mode == Mode.UNIMODAL) { - stmt = getPstmt(queryGetAdjContinuousLinks); - } else { - stmt = getPstmt(queryGetAdjLinks); - } + // CHECKSTYLE:OFF MagicNumber stmt.setInt(1, nodeId); + stmt.setInt(2, memorySize); + stmt.setInt(3, nodeId); + stmt.setInt(4, memorySize); + // CHECKSTYLE:ON MagicNumber rs = stmt.executeQuery(); - while (rs.next()) { - Link link; - final int linkId = rs.getInt("ID"); - final byte linkType = rs.getByte("EDGE_MODE"); - final int adjNodeId = rs.getInt("NODE_ID"); - final short degree = rs.getShort("NODE_DEGREE"); - final double length = rs.getDouble("LENGTH"); - final short routeId = rs.getShort("ROUTE_ID"); - int start, end; - if (isIncoming) { - start = adjNodeId; - end = nodeId; - } else { - start = nodeId; - end = adjNodeId; - } - - if (linkType == NW_MODE_CONTINUOUS) { - link = new Link(linkId, start, end, length); - } else { - link = new Link(linkId, start, end, routeId); - } - addNode(adjNodeId, degree, nodes); - adjLinks.add(link); + int s0 = 0, s1 = 0; + double ed0 = 0, ed1 = 0; + if (rs.next()) { + s0 = rs.getInt("s0"); + ed0 = rs.getDouble("ed0"); + s1 = rs.getInt("s1"); + ed1 = rs.getDouble("ed1"); } + return ed0 + (ed1 - ed0) / (s1 - s0) * (memorySize - s0); } catch (final SQLException e) { e.printStackTrace(); } finally { DbUtils.closeQuietly(rs); } - return adjLinks; + return 0; } /** - * Gets date codes for a given time. - * - * @param time the given - * @return returns a set of date codes + * Loads the links in a circle from the database (for better explanation see the MrneX algorithm). */ - public Set<Integer> getDateCodes(final Calendar time) { - final Set<Integer> codes = new HashSet<Integer>(); - final PreparedStatement stmt = getPstmt(queryGetDateCodes); + public void loadLinksFromIER(final Node node, final Collection<Node> intersections, final Map<Integer, Node> nodes, final Map<Integer, List<Link>> adjList) { + PreparedStatement stmt = null; ResultSet rs = null; + final Point g = node.getCoordinates(); + final String pointString = "POINT( " + g.getX() + " " + g.getY() + ")"; try { - final Date date = new Date(time.getTimeInMillis()); - // CHECKSTYLE:OFF MagicNumber - stmt.setString(1, getWeekDayMask(time)); - stmt.setDate(2, date); - stmt.setDate(3, date); - // CHECKSTYLE:ON MagicNumber - + if (intersections.isEmpty()) { + stmt = getPstmt(queryLoadLinksFromIER); + // CHECKSTYLE:OFF MagicNumber + stmt.setString(1, pointString); + stmt.setInt(2, config.getServerSRID()); + stmt.setDouble(3, node.getRadius()); + // CHECKSTYLE:ON MagicNumber + } else { + final Node[] loadedAreas = intersections.toArray(new Node[0]); + final String disjunctAreaString = "st_difference(st_buffer(st_pointfromtext('" + pointString + "'," + + config.getServerSRID() + ")," + node.getRadius() + ")," + subQuery(loadedAreas, loadedAreas.length - 1, config.getServerSRID()) + ")"; + stmt = getPstmt(String.format(queryGetLinksInRange, disjunctAreaString)); + } rs = stmt.executeQuery(); + while (rs.next()) { - codes.add(rs.getInt("SERVICE_ID")); + final int linkId = rs.getInt("ID"); + final int sourceId = rs.getInt("SOURCE"); + final short degree = rs.getShort("DEGREE"); + final int targetId = rs.getInt("TARGET"); + final byte edgeMode = rs.getByte("EDGE_MODE"); + Link l = null; + if (edgeMode == NW_MODE_CONTINUOUS) { + final double length = rs.getDouble("LENGTH"); + l = new Link(linkId, sourceId, targetId, length); + } else { + final short routeId = rs.getShort("ROUTE_ID"); + l = new Link(linkId, sourceId, targetId, routeId); + } + addLink(l, degree, nodes, adjList); } } catch (final SQLException e) { + System.err.println("Problems with node:" + node); e.printStackTrace(); } finally { DbUtils.closeQuietly(rs); } - - return codes; } /** - * Transforms the day into something machine-readable. + * Reads the whole network for the MDijkstra Algorithm. + * The given maps have to be initialized and will be filled up with + * the nodes and links in the network. * - * @param time the calendar object to get the machine-readable week day from - * @return the machine-readable string (binary form) + * @param nodes A map in which all the nodes should be stored. + * @param links A map in which all the links should be stored. */ - private String getWeekDayMask(final Calendar time) { - switch (time.get(Calendar.DAY_OF_WEEK)) { - case Calendar.MONDAY: - return "1000000"; - case Calendar.TUESDAY: - return "0100000"; - case Calendar.WEDNESDAY: - return "0010000"; - case Calendar.THURSDAY: - return "0001000"; - case Calendar.FRIDAY: - return "0000100"; - case Calendar.SATURDAY: - return "0000010"; - case Calendar.SUNDAY: - return "0000001"; - default: - return "1000000"; - } - } + public void readNetwork(final Map<Integer, Node> nodes, final Map<Integer, Link> links) { + final PreparedStatement stmt = getPstmt((mode == Mode.UNIMODAL) ? queryGetContinuousEdges : queryGetAllEdges); - /** - * Gets the coordinates of a node. - * - * @param nodeId The nodeId of the node for which we should - * find the coordinates. - * @return a point with the coordinates of the node - */ - public Point getCoordinates(final int nodeId) { - Point gp = null; ResultSet rs = null; try { - final PreparedStatement stmt = getPstmt(queryGetCoordinatesFromNode); - stmt.setInt(1, nodeId); rs = stmt.executeQuery(); - if (rs.next()) { - gp = new Point(rs.getDouble("X"), rs.getDouble("Y")); + while (rs.next()) { + final int linkId = rs.getInt("ID"); + final int startNodeId = rs.getInt("SOURCE"); + final int endNodeId = rs.getInt("TARGET"); + final double length = rs.getDouble("LENGTH"); + final short routeId = rs.getShort("ROUTE_ID"); + final byte linkType = rs.getByte("EDGE_MODE"); + + int start, end; + if (isIncoming) { + start = startNodeId; + end = endNodeId; + } else { + start = endNodeId; + end = startNodeId; + } + Node node; + if (!nodes.containsKey(end)) { + node = new Node(end); + nodes.put(end, node); + } else { + node = nodes.get(end); + } + if (node.getAdjLinks() == null) { + node.setAdjLinks(new ArrayList<Link>()); + } + Link link; + + if (linkType == NW_MODE_CONTINUOUS) { + link = new Link(linkId, startNodeId, endNodeId, length); + } else { + link = new Link(linkId, startNodeId, endNodeId, routeId); + } + node.addAdjLink(link); + links.put(linkId, link); + if (!nodes.containsKey(start)) { + nodes.put(start, new Node(start)); + } } } catch (final SQLException e) { - e.printStackTrace(); + throw new RuntimeException("Error reading the Network: " + e); } finally { DbUtils.closeQuietly(rs); } - - return gp; - } - - /** - * Close all the open prepared statements and the database - * connection. Call this method once you're done with the - * database. - */ - public void close() { - for (final PreparedStatement pstmt : pstmtsCacheMap.values()) { - DbUtils.closeQuietly(pstmt); - } } /** - * If close() is not called, make sure the database connections + * If {@link #close()} is not called, make sure the database connections * are still closed. This method is just a security guard and * should not be relied on and is not an excuse for a lazy * programmer not to call the close method. * This method is not guaranteed to be called!! * + * @see #close() * @throws Throwable the {@code Exception} raised by this method */ @Override @@ -664,121 +620,163 @@ public class Database<T extends ConfigDataset> { close(); } + // Protected methods + /** - * Method getRange returns the maximal range for the given - * vertex with a maximal number of specified vertices. Query - * find the last two tuples having a memory size smaller than - * memorySize and then interpolates the range. + * Gets a prepared statement and caches it in a map. This + * is much more efficient than creating a new prepared statement + * each time a query needs to be called, and recalculating the + * queryplan each time. * - * @param nodeId the vertex identifier - * @param memorySize the maximal number of vertices - * @return the available range as the euclidean distance + * @param query The prepared statement that is needed + * @return the cached prepared statement object */ - public double getRange(final int nodeId, final int memorySize) { - ResultSet rs = null; + // FIXME: Find a fix for prepared statements with parameters + // (we should NOT set strings in preparedStatemens just because we want to cache something) + protected PreparedStatement getPstmt(final String query) { try { - final PreparedStatement stmt = getPstmt(queryGetRange); - // CHECKSTYLE:OFF MagicNumber - stmt.setInt(1, nodeId); - stmt.setInt(2, memorySize); - stmt.setInt(3, nodeId); - stmt.setInt(4, memorySize); - // CHECKSTYLE:ON MagicNumber - rs = stmt.executeQuery(); - int s0 = 0, s1 = 0; - double ed0 = 0, ed1 = 0; - if (rs.next()) { - s0 = rs.getInt("s0"); - ed0 = rs.getDouble("ed0"); - s1 = rs.getInt("s1"); - ed1 = rs.getDouble("ed1"); + if (pstmtsCacheMap.containsKey(query) && !pstmtsCacheMap.get(query).isClosed()) { + return pstmtsCacheMap.get(query); } - return ed0 + (ed1 - ed0) / (s1 - s0) * (memorySize - s0); + + final PreparedStatement pstmt = connection.prepareStatement(query); + pstmtsCacheMap.put(query, pstmt); + return pstmt; } catch (final SQLException e) { e.printStackTrace(); - } finally { - DbUtils.closeQuietly(rs); } - return 0; + return null; } - public void addLink(final Link link, final short degree, final Map<Integer, Node> nodes, final Map<Integer, List<Link>> adjList) { - int n1, n2; + // Private methods + + private Link createLinkFromResultSet(final int nodeId, final int adjNodeId, final ResultSet rs) throws SQLException { + int start, end; if (isIncoming) { - n1 = link.getStartNode(); - n2 = link.getEndNode(); + start = adjNodeId; + end = nodeId; } else { - n1 = link.getEndNode(); - n2 = link.getStartNode(); + start = nodeId; + end = adjNodeId; } - addNode(n1, degree, nodes); - addNode(n2, nodes); - if (!adjList.containsKey(n2)) { - adjList.put(n2, new ArrayList<Link>()); + final int linkId = rs.getInt("ID"); + if (rs.getByte("EDGE_MODE") == NW_MODE_CONTINUOUS) { + final double length = rs.getDouble("LENGTH"); + return new Link(linkId, start, end, length); } - adjList.get(n2).add(link); + final short routeId = rs.getShort("ROUTE_ID"); + return new Link(linkId, start, end, routeId); } - private String subQuery(final Node[] loaded, final int idx, final int srid) { - if (idx == 0) { - return "st_buffer(st_pointfromtext('POINT(" + loaded[idx].getCoordinates().getX() + " " - + loaded[idx].getCoordinates().getY() + ")'," + srid + ")," + loaded[idx].getRadius() + ")"; - } else { - return "st_union(" + "st_buffer(st_pointfromtext('POINT(" + loaded[idx].getCoordinates().getX() + " " - + loaded[idx].getCoordinates().getY() + ")'," + srid + ")," + loaded[idx].getRadius() + ")," - + subQuery(loaded, idx - 1, srid) + ")"; + // Private static methods + + /** + * Prepares a number of place holders for a prepared statement. + * + * @param length The number of placeholders that is needed + * @return a string with the placeholders plugged in to a statement. + */ + private static String preparePlaceHolders(final int length) { + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < length; ++i) { + builder.append("?"); + if ((i + 1) < length) { + builder.append(","); + } } + + return builder.toString(); } /** - * Loads the links in a circle from the database (for better explanation see the MrneX algorithm). + * Sets the values in the placeholders in a prepared statement, generated by + * the {@link #preparePlaceHolders(int)} method. + * + * @see #preparePlaceHolders(int) + * @param startIdx the start index where the first object should be placed in the prepared statement + * @param preparedStatement the prepared statement in which the values should be inserted. + * @param values the values that should be inserted into the prepared statement + * @throws SQLException thrown if a parameter could not be set into the prepared statement + * @return the index of the first position that was being left unfilled by the method */ - public void loadLinksFromIER(final Node node, final Collection<Node> intersections, final Map<Integer, Node> nodes, final Map<Integer, List<Link>> adjList) { - ResultSet rs = null; + protected static final int setValues(final int startIdx, final PreparedStatement preparedStatement, final Object... values) throws SQLException { + for (int i = 0; i < values.length; ++i) { + preparedStatement.setObject(startIdx + i, values[i]); + } - final Point g = node.getCoordinates(); - final String pointString = "POINT( " + g.getX() + " " + g.getY() + ")"; - try { - PreparedStatement stmt = null; - if (intersections.isEmpty()) { - stmt = getPstmt(queryLoadLinksFromIER); - // CHECKSTYLE:OFF MagicNumber - stmt.setString(1, pointString); - stmt.setInt(2, config.getServerSRID()); - stmt.setDouble(3, node.getRadius()); - // CHECKSTYLE:ON MagicNumber - } else { - final Node[] loadedAreas = intersections.toArray(new Node[0]); - final String disjunctAreaString = "st_difference(st_buffer(st_pointfromtext('" + pointString + "'," - + config.getServerSRID() + ")," + node.getRadius() + ")," + subQuery(loadedAreas, loadedAreas.length - 1, config.getServerSRID()) + ")"; - stmt = getPstmt(String.format(queryGetLinksInRange, disjunctAreaString)); - } - rs = stmt.executeQuery(); + return startIdx + values.length; + } - while (rs.next()) { - final int linkId = rs.getInt("ID"); - final int sourceId = rs.getInt("SOURCE"); - final short degree = rs.getShort("DEGREE"); - final int targetId = rs.getInt("TARGET"); - final byte edgeMode = rs.getByte("EDGE_MODE"); - Link l = null; - if (edgeMode == NW_MODE_CONTINUOUS) { - final double length = rs.getDouble("LENGTH"); - l = new Link(linkId, sourceId, targetId, length); - } else { - final short routeId = rs.getShort("ROUTE_ID"); - l = new Link(linkId, sourceId, targetId, routeId); - } - addLink(l, degree, nodes, adjList); - } - } catch (final SQLException e) { - System.err.println("Problems with node:" + node); - e.printStackTrace(); - } finally { - DbUtils.closeQuietly(rs); + /** + * Adds a node to the network. + * + * @param nodeId The nodeId of the node that should be added + * @param nodes The HashMap to which the node should be added + */ + private static void addNode(final int nodeId, final Map<Integer, Node> nodes) { + if (nodes != null && !nodes.containsKey(nodeId)) { + nodes.put(nodeId, new Node(nodeId)); + } + } + + /** + * Adds a node to the network. + * + * @param nodeId The nodeId of the node that should be added + * @param nrAdjLinks The number of links adjacent to the node + * @param nodes The nodes HashMap to which the node should be added + */ + private static void addNode(final int nodeId, final short nrAdjLinks, final Map<Integer, Node> nodes) { + if (nodes == null) { + return; // Just for safety + } + + final Node node = nodes.get(nodeId); + if (node == null) { + nodes.put(nodeId, new Node(nodeId, nrAdjLinks)); + } else if (node.getNrAdjacentLinks() == -1) { + node.setNrAdjacentLinks(nrAdjLinks); + } + } + + /** + * Transforms the day into something machine-readable. + * + * @param time the calendar object to get the machine-readable week day from + * @return the machine-readable string (binary form) + */ + private static String getWeekDayMask(final Calendar time) { + switch (time.get(Calendar.DAY_OF_WEEK)) { + case Calendar.MONDAY: + return "1000000"; + case Calendar.TUESDAY: + return "0100000"; + case Calendar.WEDNESDAY: + return "0010000"; + case Calendar.THURSDAY: + return "0001000"; + case Calendar.FRIDAY: + return "0000100"; + case Calendar.SATURDAY: + return "0000010"; + case Calendar.SUNDAY: + return "0000001"; + default: + return "1000000"; + } + } + + private static String subQuery(final Node[] loaded, final int idx, final int srid) { + if (idx == 0) { + return "st_buffer(st_pointfromtext('POINT(" + loaded[idx].getCoordinates().getX() + " " + + loaded[idx].getCoordinates().getY() + ")'," + srid + ")," + loaded[idx].getRadius() + ")"; + } else { + return "st_union(" + "st_buffer(st_pointfromtext('POINT(" + loaded[idx].getCoordinates().getX() + " " + + loaded[idx].getCoordinates().getY() + ")'," + srid + ")," + loaded[idx].getRadius() + ")," + + subQuery(loaded, idx - 1, srid) + ")"; } } } diff --git a/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java b/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java index fecf7bd7..426e2431 100644 --- a/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java +++ b/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java @@ -49,12 +49,14 @@ public class DatabaseWeb extends Database<ConfigClient> { private final String queryInsertVertexAnnotation; private final String queryUpdateVertices; + // Constructor + public DatabaseWeb(final ConfigClient config, final Mode mode, final Direction direction) { super(config, mode, direction); - final String cfgEdges = config.getTableEdges(); - final String cfgRoutes = config.getTableRoutes(); - final String cfgVertex = config.getTableVertex(); + final String configEdges = config.getTableEdges(); + final String configRoutes = config.getTableRoutes(); + final String configVertex = config.getTableVertex(); final String edgeTableName = config.getEdgeTableEntry().getTableName(); final String vertexTableName = config.getVertexTableEntry().getTableName(); final String vertexAnnotationTableName = config.getVertexAnnotatedTableEntry().getTableName(); @@ -65,41 +67,33 @@ public class DatabaseWeb extends Database<ConfigClient> { queryStoreLinks = "INSERT INTO " + edgeTableName + " (\"ID\",\"SOURCE\",\"TARGET\",\"OFFSET\",\"LENGTH\",\"GEOMETRY\") (SELECT ID, SOURCE, TARGET, ?, LENGTH," - + " GEOMETRY FROM " + cfgEdges + " WHERE ID=?)"; + + " GEOMETRY FROM " + configEdges + " WHERE ID=?)"; queryStorePartialLinks = "INSERT INTO " + edgeTableName + " (\"ID\",\"SOURCE\",\"TARGET\",\"OFFSET\",\"LENGTH\",\"GEOMETRY\") (SELECT ID,SOURCE,TARGET,?,LENGTH," - + " ST_LINE_SUBSTRING(GEOMETRY,?,?) FROM " + cfgEdges + " WHERE ID = ?)"; + + " ST_LINE_SUBSTRING(GEOMETRY,?,?) FROM " + configEdges + " WHERE ID = ?)"; queryInsertVertex = "INSERT INTO " + vertexTableName - + " (\"ID\",\"DISTANCE\",\"ROUTE_ID\",\"STATE\",\"GEOMETRY\") (SELECT ?,?,?,?,GEOMETRY FROM " + cfgVertex + + " (\"ID\",\"DISTANCE\",\"ROUTE_ID\",\"STATE\",\"GEOMETRY\") (SELECT ?,?,?,?,GEOMETRY FROM " + configVertex + " WHERE ID=?)"; queryInsertVertexAnnotation = "INSERT INTO " + vertexAnnotationTableName + " (\"ID\", \"ROUTE_ID\",\"TIME_A\",\"TIME_D\") VALUES (?,?,?,?)"; queryUpdateVertices = "UPDATE " + vertexTableName - + " SET \"T_TYPE\"=R.ROUTE_TYPE FROM " + cfgRoutes + " R WHERE R.ROUTE_ID = " + + " SET \"T_TYPE\"=R.ROUTE_TYPE FROM " + configRoutes + " R WHERE R.ROUTE_ID = " + vertexTableName + ".\"ROUTE_ID\" AND " + vertexTableName + ".\"ROUTE_ID\">=0"; } - public Point transform(final Point p) { - final String query = "SELECT ST_X(P.GEO) X, ST_Y(P.GEO) Y FROM (SELECT ST_Transform(ST_PointFromText(?,?),?) GEO ) P"; - return DatabaseWeb.transform(config, p, getPstmt(query)); - } - - public Connection getConnection() { - return connection; - } + // Public methods public void createBuffer(final String bufferTable, final String edgeTable, final double bufferSize) { - final String query = "INSERT INTO " + bufferTable + " " - + "SELECT 1,ST_Multi(ST_UNION(ST_BUFFER(\"GEOMETRY\", " - + bufferSize + "))) \"GEOMETRY\" FROM " + edgeTable; + final StringBuilder b = new StringBuilder("INSERT INTO ").append(bufferTable); + b.append(" SELECT 1,ST_Multi(ST_UNION(ST_BUFFER(\"GEOMETRY\", ").append(bufferSize).append("))) \"GEOMETRY\" FROM ").append(edgeTable); PreparedStatement statement = null; try { - statement = getPstmt(query); + statement = getPstmt(b.toString()); statement.executeUpdate(); connection.commit(); } catch (final SQLException e) { @@ -114,6 +108,36 @@ public class DatabaseWeb extends Database<ConfigClient> { } } + public List<Integer> edgesInArea(final int areaId) { + final List<Integer> edges = new ArrayList<Integer>(); + final StringBuilder b = new StringBuilder("SELECT L.\"ID\" FROM "); + b.append(config.getEdgeTableEntry().getTableName()).append(" L, "); + b.append(config.getAreaBufferTableEntry().getTableName()).append(" A "); + b.append("WHERE A.\"ID\"=? AND ST_Within(L.\"GEOMETRY\",A.\"GEOMETRY\")=TRUE"); + + PreparedStatement statement = null; + ResultSet rs = null; + try { + statement = getPstmt(b.toString()); + statement.setInt(1, areaId); + rs = statement.executeQuery(); + while (rs.next()) { + edges.add(rs.getInt(1)); + } + } catch (final SQLException e) { + e.printStackTrace(); + } finally { + DbUtils.closeQuietly(rs); + DbUtils.closeQuietly(statement); + } + + return edges; + } + + public Connection getConnection() { + return connection; + } + @SuppressFBWarnings( value = "DLS_DEAD_LOCAL_STORE", justification = "False positiv in DLS_DEAD_LOCAL_STORE check" @@ -179,58 +203,64 @@ public class DatabaseWeb extends Database<ConfigClient> { return isoEdges; } - public void storeArea(final int areaId, final List<Point> points, final double bufferSize) { - final Geometry geometry = PgHelper.asPgGeometry(points); - final String geometryString = geometry.getTypeString() + geometry.getValue(); + public Set<Location> projectOnLinks(final QueryNode qNode) { + Set<Location> locations = QueryNodeCache.getCachedQueryPoint(qNode); + if (locations != null) { + return locations; + } - final StringBuilder b = new StringBuilder(); - b.append("INSERT INTO ").append(config.getAreaBufferTableEntry().getTableName()); - b.append("(\"ID\",\"GEOMETRY\") VALUES(?,ST_MULTI(ST_Buffer(ST_MakeValid(ST_GeomFromText(?," + config.getServerSRID() + ")),?,'endcap=round join=round')))"); - PreparedStatement statement = null; + final int clientSRID = ConfigIsochrone.getInstance().getClientSRID(); + final String point = "POINT(" + qNode.getX() + " " + qNode.getY() + ")"; + final StringBuilder sb = new StringBuilder(); + sb.append("SELECT L.ID, ST_Line_Locate_Point(L.EDGE_GEO,L.POINT_GEO)*L.LENGTH AS OFFSET "); + sb.append("FROM (SELECT E.ID, E.GEOMETRY EDGE_GEO, E.LENGTH, P.GEOMETRY POINT_GEO FROM "); + sb.append(config.getTableEdges()).append(" E, "); + sb.append(" (SELECT "); + if (clientSRID == config.getServerSRID()) { + sb.append("ST_PointFromText(?,?) "); + } else { + sb.append("ST_Transform(ST_PointFromText(?,?),?)"); + } + sb.append(" GEOMETRY) P"); + sb.append(" WHERE E.EDGE_MODE=").append(NW_MODE_CONTINUOUS).append(" AND st_dwithin(E.GEOMETRY,P.GEOMETRY, ?)"); // tolerance + sb.append(" ORDER BY st_distance(E.GEOMETRY,P.GEOMETRY) LIMIT 2) L"); + + PreparedStatement statement = null; + ResultSet rSet = null; try { - statement = getPstmt(b.toString()); + statement = getPstmt(sb.toString()); + statement.setString(1, point); + statement.setInt(2, clientSRID); + // CHECKSTYLE:OFF MagicNumber - statement.setInt(1, areaId); - statement.setString(2, geometryString); - statement.setDouble(3, bufferSize); + final int tolerance = config.getDistanceTolerance(); + if (clientSRID != config.getServerSRID()) { + statement.setInt(3, config.getServerSRID()); + statement.setInt(4, tolerance); + } else { + statement.setInt(3, tolerance); + } // CHECKSTYLE:ON MagicNumber - statement.executeUpdate(); - connection.commit(); - } catch (final SQLException e) { - e.printStackTrace(); - } finally { - DbUtils.closeQuietly(statement); - } - } - - public List<Integer> edgesInArea(final int areaId) { - final List<Integer> edges = new ArrayList<Integer>(); - final StringBuilder b1 = new StringBuilder(); - b1.append("SELECT L.\"ID\" FROM "); - b1.append(config.getEdgeTableEntry().getTableName()).append(" L, "); - b1.append(config.getAreaBufferTableEntry().getTableName()).append(" A "); - b1.append("WHERE A.\"ID\"=? AND ST_Within(L.\"GEOMETRY\",A.\"GEOMETRY\")=TRUE"); - PreparedStatement statement = null; - ResultSet rs = null; - try { - statement = getPstmt(b1.toString()); - statement.setInt(1, areaId); - rs = statement.executeQuery(); - while (rs.next()) { - edges.add(rs.getInt(1)); + rSet = statement.executeQuery(); + locations = new HashSet<Location>(); + while (rSet.next()) { + final int link = rSet.getInt("ID"); + final double offset = rSet.getDouble("OFFSET"); + locations.add(new Location(link, offset)); } + QueryNodeCache.addQueryNode(qNode, locations); } catch (final SQLException e) { e.printStackTrace(); } finally { - DbUtils.closeQuietly(rs); + DbUtils.closeQuietly(rSet); DbUtils.closeQuietly(statement); } - return edges; + return locations; } -/* + /* public int reachedInhabitants() { int reachedInhabitants = 0; final StringBuilder b = new StringBuilder(); @@ -278,7 +308,32 @@ public class DatabaseWeb extends Database<ConfigClient> { return totalInhabitants; } -*/ + */ + + public void storeArea(final int areaId, final List<Point> points, final double bufferSize) { + final Geometry geometry = PgHelper.asPgGeometry(points); + final String geometryString = geometry.getTypeString() + geometry.getValue(); + + final StringBuilder b = new StringBuilder(); + b.append("INSERT INTO ").append(config.getAreaBufferTableEntry().getTableName()); + b.append("(\"ID\",\"GEOMETRY\") VALUES(?,ST_MULTI(ST_Buffer(ST_MakeValid(ST_GeomFromText(?," + config.getServerSRID() + ")),?,'endcap=round join=round')))"); + PreparedStatement statement = null; + try { + statement = getPstmt(b.toString()); + // CHECKSTYLE:OFF MagicNumber + statement.setInt(1, areaId); + statement.setString(2, geometryString); + statement.setDouble(3, bufferSize); + // CHECKSTYLE:ON MagicNumber + statement.executeUpdate(); + connection.commit(); + } catch (final SQLException e) { + e.printStackTrace(); + } finally { + DbUtils.closeQuietly(statement); + } + } + public final void storeLinks(final Collection<Link> links, final Direction direction) { final boolean isIncoming = direction == Direction.INCOMING; PreparedStatement statementPartial = null; @@ -330,63 +385,6 @@ public class DatabaseWeb extends Database<ConfigClient> { } } - public Set<Location> projectOnLinks(final QueryNode qNode) { - Set<Location> locations = QueryNodeCache.getCachedQueryPoint(qNode); - if (locations != null) { - return locations; - } - - final int clientSRID = ConfigIsochrone.getInstance().getClientSRID(); - final String point = "POINT(" + qNode.getX() + " " + qNode.getY() + ")"; - final StringBuilder sb = new StringBuilder(); - sb.append("SELECT L.ID, ST_Line_Locate_Point(L.EDGE_GEO,L.POINT_GEO)*L.LENGTH AS OFFSET "); - sb.append("FROM (SELECT E.ID, E.GEOMETRY EDGE_GEO, E.LENGTH, P.GEOMETRY POINT_GEO FROM "); - sb.append(config.getTableEdges()).append(" E, "); - sb.append(" (SELECT "); - if (clientSRID == config.getServerSRID()) { - sb.append("ST_PointFromText(?,?) "); - } else { - sb.append("ST_Transform(ST_PointFromText(?,?),?)"); - } - sb.append(" GEOMETRY) P"); - sb.append(" WHERE E.EDGE_MODE=").append(NW_MODE_CONTINUOUS).append(" AND st_dwithin(E.GEOMETRY,P.GEOMETRY, ?)"); // tolerance - sb.append(" ORDER BY st_distance(E.GEOMETRY,P.GEOMETRY) LIMIT 2) L"); - - PreparedStatement statement = null; - ResultSet rSet = null; - try { - statement = getPstmt(sb.toString()); - statement.setString(1, point); - statement.setInt(2, clientSRID); - - // CHECKSTYLE:OFF MagicNumber - final int tolerance = config.getDistanceTolerance(); - if (clientSRID != config.getServerSRID()) { - statement.setInt(3, config.getServerSRID()); - statement.setInt(4, tolerance); - } else { - statement.setInt(3, tolerance); - } - // CHECKSTYLE:ON MagicNumber - - rSet = statement.executeQuery(); - locations = new HashSet<Location>(); - while (rSet.next()) { - final int link = rSet.getInt("ID"); - final double offset = rSet.getDouble("OFFSET"); - locations.add(new Location(link, offset)); - } - QueryNodeCache.addQueryNode(qNode, locations); - } catch (final SQLException e) { - e.printStackTrace(); - } finally { - DbUtils.closeQuietly(rSet); - DbUtils.closeQuietly(statement); - } - - return locations; - } - public void storeVertices(final Set<Node> nodes) { PreparedStatement insertVerticesStatement = null; PreparedStatement insertVertexAnnotationStatement = null; @@ -425,6 +423,11 @@ public class DatabaseWeb extends Database<ConfigClient> { } } + public Point transform(final Point p) { + final String query = "SELECT ST_X(P.GEO) X, ST_Y(P.GEO) Y FROM (SELECT ST_Transform(ST_PointFromText(?,?),?) GEO ) P"; + return DatabaseWeb.transform(config, p, getPstmt(query)); + } + public void updateVertexTable() { PreparedStatement statement = null; try { @@ -438,13 +441,14 @@ public class DatabaseWeb extends Database<ConfigClient> { } } - // Public static methods public static Point transform(final ConfigDataset config, final Point p) { return transform(config, p, null); } + // Private static methods + private static Point transform(final ConfigDataset config, final Point p, final PreparedStatement preparedStatement) { final ConfigIsochrone configIso = ConfigIsochrone.getInstance(); final boolean openNewStatement = (preparedStatement == null); -- GitLab