Skip to content
Snippets Groups Projects
Commit 584ad782 authored by theiled00's avatar theiled00
Browse files

Merge branch 'last_changes_to_make_it_run' into 'main'

Adjusted RoutingController to support error code and additional information in...

See merge request !19
parents 94b22652 5fc04320
Branches
No related tags found
1 merge request!19Adjusted RoutingController to support error code and additional information in...
Showing
with 293 additions and 132 deletions
FROM eclipse-temurin:19-jdk-alpine
ADD target/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
\ No newline at end of file
COPY src/main/resources/config.properties /data/configuration/config.properties
ENTRYPOINT ["java","-jar","-Xmx10G","/app.jar"]
\ No newline at end of file
......@@ -10,7 +10,7 @@
</parent>
<groupId>de.fuberlin.navigator</groupId>
<artifactId>routing-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>1.00.00</version>
<name>routing-server</name>
<description>Routing service in the Microservices backend application</description>
<properties>
......@@ -50,7 +50,7 @@
<dependency>
<groupId>de.fuberlin.navigator</groupId>
<artifactId>proto</artifactId>
<version>1.00.05</version>
<version>1.00.08</version>
</dependency>
</dependencies>
......
package de.fuberlin.navigator.routingserver;
import de.fuberlin.navigator.routingserver.utility.Config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
......@@ -9,6 +10,7 @@ import org.springframework.web.bind.annotation.RestController;
public class RoutingServerApplication {
public static void main(String[] args) {
Config.load();
SpringApplication.run(RoutingServerApplication.class, args);
}
......
package de.fuberlin.navigator.routingserver.controller;
import java.io.IOException;
import java.util.List;
import org.jgrapht.GraphPath;
import org.springframework.beans.factory.annotation.Autowired;
import de.fuberlin.navigator.routingserver.model.AddressMatchingResponse;
import de.fuberlin.navigator.routingserver.model.RoutingResponse;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import de.fuberlin.navigator.protos.map_builder.Coordinates;
import de.fuberlin.navigator.routingserver.model.AdressRequest;
import de.fuberlin.navigator.routingserver.model.Point;
import de.fuberlin.navigator.routingserver.model.AddressMatchingRequest;
import de.fuberlin.navigator.routingserver.model.RoutingRequest;
import de.fuberlin.navigator.routingserver.model.shortestPath.ExtendedEdge;
import de.fuberlin.navigator.routingserver.utility.ApplyShortestPath;
import de.fuberlin.navigator.routingserver.utility.MapMatcher;
@RestController
public class RoutingController {
@Autowired
private ObjectMapper mapper;
/**
* Method is a dummy for now. Answers with a list of coordinates, where each
* coordinate is a list of two elements
* Answers with a list of coordinates, where each
* coordinate is a list of two elements. Also
* contains duration, date and distance of the
* found route. Will send an error code if
* anything went wrong
*
* @return JSON of list of coordinates
*/
@PostMapping(value = "/route", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ArrayNode route(@RequestBody RoutingRequest routingRequest) {
public String route(@RequestBody RoutingRequest routingRequest) {
log("/route", RequestMethod.POST, MediaType.APPLICATION_JSON, routingRequest);
// route generation
//route generation
GraphPath<Long, ExtendedEdge> path = ApplyShortestPath.getShortestPathInTime(routingRequest);
List<Point> coordinateList = ApplyShortestPath.covertToCoordinates(path.getVertexList());
RoutingResponse response = ApplyShortestPath.generateRoutingResponse(routingRequest);
ArrayNode arrayNode = mapper.createArrayNode();
for (Point coordinate : coordinateList) {
arrayNode.add(
mapper.createArrayNode()
.add(coordinate.getLat())
.add(coordinate.getLon()));
}
/*
* arrayNode.add(
* mapper.createArrayNode()
* .add(50.34565)
* .add(8.14056)
* );
* arrayNode.add(
* mapper.createArrayNode()
* .add(50.34551)
* .add(8.13901)
* );
* arrayNode.add(
* mapper.createArrayNode()
* .add(50.34551)
* .add(8.13901)
* );
*/
return arrayNode;
return response.toJson().toString();
}
/**
* Method is a dummy for now. Answers with a coordinate pair
* Answers with a coordinate pair. Sends an error_code if anything
* went wrong
*
* @return JSON coordinate pair
* @throws IOException
*/
@PostMapping(value = "/adressmatching", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ObjectNode adressmatching(@RequestBody AdressRequest adressRequest) throws IOException {
log("/adressmatching", RequestMethod.POST, MediaType.APPLICATION_JSON, adressRequest);
// resolve adress with map matching method
Coordinates coordinates = MapMatcher.getCoordinates(adressRequest.getAdress());
@PostMapping(value = "/addressmatching", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public String addressmatching(@RequestBody AddressMatchingRequest addressRequest) {
log("/addressmatching", RequestMethod.POST, MediaType.APPLICATION_JSON, addressRequest);
ObjectNode objectNode = mapper.createObjectNode();
objectNode.set("coordinates",
mapper.createObjectNode()
.put("lat", coordinates.getLat())
.put("lon", coordinates.getLon()));
objectNode.put("error_code", 0);
// resolve address with map matching method
AddressMatchingResponse response = MapMatcher.generateAddressMatchingResponse(addressRequest);
return objectNode;
return response.toJson().toString();
}
private void log(String endpoint, RequestMethod method, MediaType type, Object requestBody) {
......
package de.fuberlin.navigator.routingserver.model;
public class AddressMatchingRequest {
String address;
public AddressMatchingRequest(String address) {
this.address = address;
}
public AddressMatchingRequest() {
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "{\"address\":" + address + "}";
}
}
package de.fuberlin.navigator.routingserver.model;
import org.json.JSONObject;
public class AddressMatchingResponse {
Point coordinate;
// 0 -> okay
// 1 -> address is not in our road network
// 2 -> address not found
int errorCode;
private AddressMatchingResponse(Point coordinate, int errorCode) {
this.coordinate = coordinate;
this.errorCode = errorCode;
}
public static AddressMatchingResponse of(Point coordinate) {
return new AddressMatchingResponse(coordinate, 0);
}
public static AddressMatchingResponse addressNotInRoadNetwork() {
return new AddressMatchingResponse(null, 1);
}
public static AddressMatchingResponse addressNotFound() {
return new AddressMatchingResponse(null, 2);
}
public JSONObject toJson() {
JSONObject jsonObject = new JSONObject();
if (this.errorCode != 0) {
jsonObject.put("coordinate", "");
jsonObject.put("error_code", this.errorCode);
return jsonObject;
}
jsonObject.put("coordinate",
new JSONObject().put("lat", this.coordinate.getLat())
.put("lon", this.coordinate.getLon())
);
jsonObject.put("error_code", 0);
return jsonObject;
}
}
package de.fuberlin.navigator.routingserver.model;
public class AdressRequest {
String adress;
public AdressRequest(String adress) {
this.adress = adress;
}
public AdressRequest() {
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
@Override
public String toString() {
return "{\"adress\":" + adress + "}";
}
}
......@@ -19,12 +19,6 @@ public class RoutingRequest {
private int startDayAfterToday;
private int endDayAfterToday;
public RoutingRequest(Point startNode, Point endNode, Set<WeatherTag> forbidden) {
this.startNode = startNode;
this.endNode = endNode;
this.forbidden = forbidden;
}
public RoutingRequest(Point startNode, Point endNode, Set<WeatherTag> forbidden, int startDayAfterToday, int endDayAfterToday) {
this.startNode = startNode;
this.endNode = endNode;
......@@ -78,7 +72,9 @@ public class RoutingRequest {
String forbiddenStr = "\"forbidden\": [" + forbidden.stream()
.map(WeatherTag::toString)
.collect(joining(",")) + "]";
String startDayAfterTodayStr = "\"startDayAfterToday\": " + startDayAfterToday;
String endDayAfterTodayStr = "\"endDayAfterToday\": " + endDayAfterToday;
return String.format("{%s, %s, %s}", startNodeStr, endNodeStr, forbiddenStr);
return String.format("{%s, %s, %s, %s, %s}", startNodeStr, endNodeStr, forbiddenStr, startDayAfterTodayStr, endDayAfterTodayStr);
}
}
package de.fuberlin.navigator.routingserver.model;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.List;
public class RoutingResponse {
private List<Point> coordinates;
//distance in meter
private int distance;
//duration in minutes
private int duration;
//difference to day of optimal route
private int daysAfterToday;
// 0 -> everything okay
// 1 -> no route was found
private int errorCode;
private RoutingResponse(List<Point> coordinates, int distance, int duration, int daysAfterToday, int errorCode) {
this.coordinates = coordinates;
this.distance = distance;
this.duration = duration;
this.daysAfterToday = daysAfterToday;
this.errorCode = errorCode;
}
public static RoutingResponse of(List<Point> coordinates, int distance, int duration, int daysAfterToday) {
return new RoutingResponse(coordinates, distance, duration, daysAfterToday, 0);
}
public static RoutingResponse noPathFound() {
return new RoutingResponse(null, -1, -1, -1, 1);
}
public JSONObject toJson() {
JSONObject jsonObject = new JSONObject();
if (errorCode == 1) {
jsonObject.put("route", new JSONArray());
jsonObject.put("distance", -1);
jsonObject.put("duration", -1);
jsonObject.put("days_after_today", -1);
jsonObject.put("error_code", 1);
return jsonObject;
}
JSONArray route = new JSONArray();
for (Point coordinate : this.coordinates) {
route.put(
new JSONArray().put(coordinate.getLat())
.put(coordinate.getLon()));
}
jsonObject.put("route", route);
jsonObject.put("duration", this.duration);
jsonObject.put("distance", this.distance);
jsonObject.put("days_after_today", this.daysAfterToday);
jsonObject.put("error_code", 0);
return jsonObject;
}
}
......@@ -45,6 +45,9 @@ public class RoutingRequestDeserializer extends StdDeserializer<RoutingRequest>
forbidden.add(WeatherTag.findByCode(arrNode.textValue()));
}
return new RoutingRequest(startNode, endNode, forbidden);
int startAfterToday = node.get("start_after_today").asInt();
int endAfterToday = node.get("end_after_today").asInt();
return new RoutingRequest(startNode, endNode, forbidden, startAfterToday, endAfterToday);
}
}
\ No newline at end of file
package de.fuberlin.navigator.routingserver.utility;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
......@@ -9,20 +8,16 @@ import java.util.Random;
import java.util.Set;
import java.util.Map.Entry;
import de.fuberlin.navigator.routingserver.model.*;
import org.jgrapht.graph.SimpleDirectedWeightedGraph;
import org.jgrapht.GraphPath;
import org.jgrapht.alg.shortestpath.AStarShortestPath;
import de.fuberlin.navigator.protos.map_builder.RoadNetwork;
import de.fuberlin.navigator.routingserver.model.Point;
import de.fuberlin.navigator.routingserver.model.RoutingRequest;
import de.fuberlin.navigator.routingserver.model.WeatherTag;
import de.fuberlin.navigator.routingserver.model.shortestPath.ExtendedEdge;
import de.fuberlin.navigator.routingserver.model.shortestPath.Heuristic;
import de.fuberlin.navigator.protos.map_builder.Coordinates;
import de.fuberlin.navigator.protos.map_builder.Segment;
import de.fuberlin.navigator.routingserver.model.MatchedPoint;
public class ApplyShortestPath {
......@@ -67,7 +62,35 @@ public class ApplyShortestPath {
System.out.println("length of path: " + length + " meter");
}
public static GraphPath<Long, ExtendedEdge> getShortestPathInTime(RoutingRequest routingRequest){
public static RoutingResponse generateRoutingResponse(RoutingRequest request) {
GraphPath<Long, ExtendedEdge> path = null;
int start = request.getStartDayAfterToday();
int end = request.getEndDayAfterToday();
int daysAfterToday = -1;
for (int i = start; i <= end; i++ ){
path = getShortestPath(request, i);
if (path != null) {
System.out.println("Path found in " + i + " days!");
daysAfterToday = i;
break;
}
System.out.println("No path with desired conditions could be found in " +i+ " days!");
}
if (path == null) {
return RoutingResponse.noPathFound();
}
//in minutes
int duration = calculateDuration(path);
//in meters
int distance = (int) calculateLength(path);
return RoutingResponse.of(covertToCoordinates(path.getVertexList()), distance, duration, daysAfterToday);
}
private static GraphPath<Long, ExtendedEdge> getShortestPathInTime(RoutingRequest routingRequest){
int start = routingRequest.getStartDayAfterToday();
int end = routingRequest.getEndDayAfterToday();
......@@ -85,7 +108,7 @@ public class ApplyShortestPath {
}
public static GraphPath<Long, ExtendedEdge> getShortestPath(RoutingRequest routingRequest, int dayAfterToday){
private static GraphPath<Long, ExtendedEdge> getShortestPath(RoutingRequest routingRequest, int dayAfterToday){
graph = new ProtobufToGraph(NetworkReader.readRoadNetwork()).getGraphFromProto(dayAfterToday);
......@@ -184,7 +207,7 @@ public class ApplyShortestPath {
* After the algorithm has executed, remove the point with the matched
* start and end nodes from the graph.
*/
public static void removeNodeFromGraph(MatchedPoint point) {
private static void removeNodeFromGraph(MatchedPoint point) {
Set<ExtendedEdge> edges = graph.edgesOf(point.getSegmentId());
for (ExtendedEdge edge : edges) {
// cleanup
......@@ -206,7 +229,6 @@ public class ApplyShortestPath {
double lat = Point.getLat();
double lon = Point.getLon();
double epsilon = 0.0001; // 14m difference
for (Entry<Long, Coordinates> node : mapper.getNodeMap().entrySet()) {
......@@ -220,7 +242,7 @@ public class ApplyShortestPath {
return 0;
}
public static double calculateLength(GraphPath<Long, ExtendedEdge> path){
private static double calculateLength(GraphPath<Long, ExtendedEdge> path){
double length = 0;
for (ExtendedEdge edge : path.getEdgeList()) {
......@@ -234,14 +256,14 @@ public class ApplyShortestPath {
return length;
}
public static int calculateDuration(GraphPath<Long, ExtendedEdge> path){
private static int calculateDuration(GraphPath<Long, ExtendedEdge> path){
double durationH = path.getWeight();
int durationMin = (int) (durationH * 60);
return durationMin;
}
public static List<Point> covertToCoordinates(List<Long> vertexList){
private static List<Point> covertToCoordinates(List<Long> vertexList){
// convert path consisting of node ids into path of Coordinates
List<Point> coordinateList = new ArrayList<>();
for (Long nodeId : vertexList) {
......
package de.fuberlin.navigator.routingserver.utility;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
public class Config {
private Config() {
}
private static Properties props = new Properties();
/**
* Path under which the road network file is stored
*/
public static String ROAD_NETWORK_INPUT_PATH = "debug-tool/proto/sample/roadnetwork_sample.proto";
/**
* Path under which the metrics file is stored
*/
public static String METRICS_INPUT_PATH = "routing-server/src/main/resources/metrics.proto";
public static void load() {
//The config is used for running the application in a Docker container
String configFilePath = "/data/configuration/config.properties";
try (FileInputStream is = new FileInputStream(configFilePath)){
props.load(is);
ROAD_NETWORK_INPUT_PATH = props.getProperty("ROAD_NETWORK_INPUT_PATH", ROAD_NETWORK_INPUT_PATH);
METRICS_INPUT_PATH = props.getProperty("METRICS_INPUT_PATH", METRICS_INPUT_PATH);
System.out.println("Config loaded.");
} catch (FileNotFoundException e) {
// Either way the Docker image was build wrong or this is not
// run in a Docker environment
System.out.println("No config file found. Using default settings!");
} catch (IOException e) {
// Something else went wrong, but we will
// not let this escalate
e.printStackTrace();
}
}
}
......@@ -8,6 +8,9 @@ import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import de.fuberlin.navigator.routingserver.model.AddressMatchingRequest;
import de.fuberlin.navigator.routingserver.model.AddressMatchingResponse;
import de.fuberlin.navigator.routingserver.model.Point;
import org.json.JSONObject;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
......@@ -36,30 +39,53 @@ public class MapMatcher {
matcher.matchLocationToRoadnetwork(51.756329, 14.325981);
}
public static Coordinates getCoordinates(String address) throws IOException {
public static AddressMatchingResponse generateAddressMatchingResponse(AddressMatchingRequest request) {
Point coordinate = getCoordinate(request.getAddress());
if (coordinate == null) {
return AddressMatchingResponse.addressNotFound();
}
//TODO check if address is in our road network
return AddressMatchingResponse.of(coordinate);
}
public static Point getCoordinate(String address) {
String addressParam = address.replaceAll(" ", "%20");
// Construct the request URL
String requestUrl = NOMINATIM_ENDPOINT + "q=" + address + "&" + FORMAT_PARAM;
String requestUrl = NOMINATIM_ENDPOINT + "q=" + addressParam + "&" + FORMAT_PARAM;
// Send the request and parse the response
String responseString = null;
try {
URL url = new URL(requestUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
HttpURLConnection connection = null;
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
InputStream responseStream = connection.getInputStream();
String responseString = new String(responseStream.readAllBytes(), StandardCharsets.UTF_8);
responseString = new String(responseStream.readAllBytes(), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return null;
}
// Removing first and last character
// because response is in []
responseString = responseString.substring(1, responseString.length() - 1);
if (responseString.isEmpty()) {
return null;
}
// Extract the latitude and longitude from the response
JSONObject responseJson = new JSONObject(responseString);
if (!responseJson.has("lat") || !responseJson.has("lon")) {
return null;
}
double latitude = Double.parseDouble(responseJson.getString("lat"));
double longitude = Double.parseDouble(responseJson.getString("lon"));
Coordinates coordinates = Coordinates.newBuilder().setLat((float) latitude).setLon((float) longitude).build();
return coordinates;
return new Point(latitude, longitude);
}
public static String getAddress(Double lat, Double lon) throws IOException {
......
......@@ -21,18 +21,13 @@ public class MetricReader {
public static Metrics readMetrics(){
Builder builder = Metrics.newBuilder();
String PathToFile = "routing-server/src/main/resources/metrics.proto";
try {
FileInputStream input = new FileInputStream(PathToFile);
FileInputStream input = new FileInputStream(Config.METRICS_INPUT_PATH);
Metrics metrics = builder.mergeFrom(input).build();
return metrics;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
......
......@@ -19,17 +19,13 @@ public class NetworkReader{
public static RoadNetwork readRoadNetwork(){
Builder builder = RoadNetwork.newBuilder();
String PathToFile = "debug-tool/proto/sample/roadnetwork_sample.proto";
try {
FileInputStream input = new FileInputStream(PathToFile);
FileInputStream input = new FileInputStream(Config.ROAD_NETWORK_INPUT_PATH);
RoadNetwork roadnetwork = builder.mergeFrom(input).build();
return roadnetwork;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
......
# Standard config for Docker
ROAD_NETWORK_INPUT_PATH = /data/road_network/roadnetwork.proto
METRICS_INPUT_PATH = /data/metrics/metrics.proto
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment