Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple profiles routing service #551

Merged
merged 11 commits into from
Feb 14, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
import no.entur.uttu.export.netex.producer.NetexIdProducer;
import no.entur.uttu.export.netex.producer.NetexObjectFactory;
import no.entur.uttu.model.Ref;
import no.entur.uttu.model.VehicleModeEnumeration;
import no.entur.uttu.routing.RouteGeometry;
import no.entur.uttu.routing.RoutingProfile;
import no.entur.uttu.routing.RoutingService;
import no.entur.uttu.routing.RoutingServiceRequestParams;
import no.entur.uttu.stopplace.spi.StopPlaceRegistry;
import org.rutebanken.netex.model.LinkSequenceProjection;
import org.rutebanken.netex.model.Projections_RelStructure;
Expand Down Expand Up @@ -45,12 +48,15 @@ public List<ServiceLink> produce(NetexExportContext context) {
Quay quayFrom = getQuay(serviceLink.quayRefFrom());
Quay quayTo = getQuay(serviceLink.quayRefTo());

RouteGeometry routeGeometry = routingService.getRouteGeometry(
var params = new RoutingServiceRequestParams(
quayFrom.getCentroid().getLocation().getLongitude(),
quayFrom.getCentroid().getLocation().getLatitude(),
quayTo.getCentroid().getLocation().getLongitude(),
quayTo.getCentroid().getLocation().getLatitude()
quayTo.getCentroid().getLocation().getLatitude(),
mapVehicleModeToRoutingProfile(serviceLink.transportMode())
);

RouteGeometry routeGeometry = routingService.getRouteGeometry(params);
List<Double> posListCoordinates = new ArrayList<>();
routeGeometry
.coordinates()
Expand Down Expand Up @@ -115,6 +121,17 @@ public List<ServiceLink> produce(NetexExportContext context) {
.toList();
}

private RoutingProfile mapVehicleModeToRoutingProfile(
VehicleModeEnumeration vehicleModeEnumeration
) {
return switch (vehicleModeEnumeration) {
case BUS, TAXI, COACH -> RoutingProfile.BUS;
case FERRY, WATER -> RoutingProfile.WATER;
case METRO, TRAM, RAIL -> RoutingProfile.RAIL;
testower marked this conversation as resolved.
Show resolved Hide resolved
case AIR, CABLEWAY, FUNICULAR, TROLLEY_BUS, LIFT, OTHER -> null;
};
}

Quay getQuay(String quayRef) {
Optional<StopPlace> stopPlaceOptional = stopPlaceRegistry.getStopPlaceByQuayRef(
quayRef
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import no.entur.uttu.model.StopPointInJourneyPattern;
import no.entur.uttu.model.VehicleModeEnumeration;
import no.entur.uttu.model.job.SeverityEnumeration;
import no.entur.uttu.routing.RoutingProfile;
import no.entur.uttu.routing.RoutingService;
import no.entur.uttu.stopplace.spi.StopPlaceRegistry;
import org.rutebanken.netex.model.BookingAccessEnumeration;
Expand Down Expand Up @@ -103,8 +104,8 @@ public org.rutebanken.netex.model.JourneyPattern produce(
List<LinkInLinkSequence_VersionedChildStructure> linksInSequence;
if (
routingService != null &&
routingService.isEnabled() &&
local.getLine().getTransportMode() == VehicleModeEnumeration.BUS
routingService.isEnabled(RoutingProfile.BUS) &&
local.getLine().getTransportMode() == VehicleModeEnumeration.BUS // TODO skip this or check whitelist?
) {
linksInSequence =
local
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import java.util.Optional;
import no.entur.uttu.graphql.model.ServiceLink;
import no.entur.uttu.routing.RouteGeometry;
import no.entur.uttu.routing.RoutingProfile;
import no.entur.uttu.routing.RoutingService;
import no.entur.uttu.routing.RoutingServiceRequestParams;
import no.entur.uttu.stopplace.spi.StopPlaceRegistry;
import org.rutebanken.netex.model.Quay;
import org.rutebanken.netex.model.StopPlace;
Expand Down Expand Up @@ -37,13 +39,16 @@ public ServiceLink get(DataFetchingEnvironment environment) {
return new ServiceLink(quayRefFrom + "_" + quayRefTo, null, null, null);
}

RouteGeometry routeGeometry = routingService.getRouteGeometry(
var params = new RoutingServiceRequestParams(
quayFrom.getCentroid().getLocation().getLongitude(),
quayFrom.getCentroid().getLocation().getLatitude(),
quayTo.getCentroid().getLocation().getLongitude(),
quayTo.getCentroid().getLocation().getLatitude()
quayTo.getCentroid().getLocation().getLatitude(),
RoutingProfile.BUS // TODO: Get from query
);

RouteGeometry routeGeometry = routingService.getRouteGeometry(params);

return new ServiceLink(
quayRefFrom + "_" + quayRefTo,
quayRefFrom,
Expand Down
15 changes: 6 additions & 9 deletions src/main/java/no/entur/uttu/routing/DefaultRoutingService.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,13 @@ public DefaultRoutingService() {
logger.info("DefaultRoutingService got initialised");
}

public RouteGeometry getRouteGeometry(
BigDecimal longitudeFrom,
BigDecimal latitudeFrom,
BigDecimal longitudeTo,
BigDecimal latitudeTo
) {
return new RouteGeometry(new ArrayList<>(), BigDecimal.ZERO);
@Override
public boolean isEnabled(RoutingProfile routingProfile) {
return false;
}

public boolean isEnabled() {
return false;
@Override
public RouteGeometry getRouteGeometry(RoutingServiceRequestParams request) {
return null;
}
}
7 changes: 7 additions & 0 deletions src/main/java/no/entur/uttu/routing/RoutingProfile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package no.entur.uttu.routing;

public enum RoutingProfile {
BUS,
RAIL,
WATER,
}
22 changes: 13 additions & 9 deletions src/main/java/no/entur/uttu/routing/RoutingService.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package no.entur.uttu.routing;

import java.math.BigDecimal;

/**
* For getting the road geometry - resulting in service links and links in sequence in a journey pattern
*/
public interface RoutingService {
RouteGeometry getRouteGeometry(
BigDecimal longitudeFrom,
BigDecimal latitudeFrom,
BigDecimal longitudeTo,
BigDecimal latitudeTo
);
boolean isEnabled();
/**
* Check if the routing service is enabled for a given {@link RoutingProfile}
* @param routingProfile
* @return
*/
boolean isEnabled(RoutingProfile routingProfile);

/**
* Request route geometry
* @param request The parameters of the request
* @return An instance of {@link RouteGeometry}
*/
RouteGeometry getRouteGeometry(RoutingServiceRequestParams request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package no.entur.uttu.routing;

import java.math.BigDecimal;

public record RoutingServiceRequestParams(
BigDecimal longitudeFrom,
BigDecimal latitudeFrom,
BigDecimal longitudeTo,
BigDecimal latitudeTo,
RoutingProfile routingProfile
) {}
33 changes: 31 additions & 2 deletions src/main/java/no/entur/uttu/routing/osrm/OsrmConfiguration.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package no.entur.uttu.routing.osrm;

import java.util.HashMap;
import java.util.Map;
import no.entur.uttu.routing.RoutingProfile;
import no.entur.uttu.routing.RoutingService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
Expand All @@ -12,8 +15,34 @@ public class OsrmConfiguration {

@Bean
RoutingService routingService(
@Value("${uttu.routing.osrm-api}") String osrmApiEndpoint
@Value("${uttu.routing.osrm-api}") String osrmApiEndpoint,
@Value("${uttu.routing.osrm-api-bus}") String osrmApiBusEndpoint,
@Value("${uttu.routing.osrm-api-rail}") String osrmApiRailEndpoint,
@Value("${uttu.routing.osrm-api-water}") String osrmApiWaterEndpoint
) {
return new OsrmService(osrmApiEndpoint);
if (osrmApiEndpoint != null) {
return createStandaloneBusRoutingService(osrmApiEndpoint);
} else {
return createRoutingService(osrmApiBusEndpoint, osrmApiRailEndpoint, osrmApiWaterEndpoint);
}
}

private RoutingService createRoutingService(String osrmApiBusEndpoint, String osrmApiRailEndpoint, String osrmApiWaterEndpoint) {
var endpointMap = new HashMap<RoutingProfile, String>();

if (osrmApiBusEndpoint != null) {
endpointMap.put(RoutingProfile.BUS, osrmApiBusEndpoint);
}
if (osrmApiRailEndpoint != null) {
endpointMap.put(RoutingProfile.RAIL, osrmApiRailEndpoint);
}
if (osrmApiWaterEndpoint != null) {
endpointMap.put(RoutingProfile.WATER, osrmApiWaterEndpoint);
}
return new OsrmService(endpointMap);
}

private RoutingService createStandaloneBusRoutingService(String osrmApiEndpoint) {
return new OsrmService(Map.of(RoutingProfile.BUS, osrmApiEndpoint));
}
}
82 changes: 42 additions & 40 deletions src/main/java/no/entur/uttu/routing/osrm/OsrmService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,33 @@
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import no.entur.uttu.model.VehicleModeEnumeration;
import no.entur.uttu.routing.RouteGeometry;
import no.entur.uttu.routing.RoutingProfile;
import no.entur.uttu.routing.RoutingServiceRequestParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OsrmService implements no.entur.uttu.routing.RoutingService {

private static final Logger logger = LoggerFactory.getLogger(OsrmService.class);

private final String osrmApiEndpoint;
private final Map<RoutingProfile, String> osrmApiEndpointMap;

private final Methanol httpClient;
private final ObjectMapper objectMapper;

public OsrmService(String osrmApiEndpoint) {
this.osrmApiEndpoint = osrmApiEndpoint;
public OsrmService(Map<RoutingProfile, String> osrmApiEndpointMap) {
this.osrmApiEndpointMap = osrmApiEndpointMap;
this.objectMapper = initializeObjectMapper();
this.httpClient = initializeHttpClient();
logger.info("OsrmService got initialised, osrmApiEndpoint is: {}", osrmApiEndpoint);
logger.info(
"OsrmService got initialised, osrmApiEndpointMap is: {}",
osrmApiEndpointMap
);
}

private static ObjectMapper initializeObjectMapper() {
Expand All @@ -53,45 +61,39 @@ private static Methanol initializeHttpClient() {
.build();
}

public boolean isEnabled() {
return osrmApiEndpoint != null && !osrmApiEndpoint.isBlank();
@Override
public boolean isEnabled(RoutingProfile profile) {
return osrmApiEndpointMap != null && !osrmApiEndpointMap.containsKey(profile);
}

private MutableRequest getRoutingRequest(
BigDecimal longitudeFrom,
BigDecimal latitudeFrom,
BigDecimal longitudeTo,
BigDecimal latitudeTo
) {
@Override
public RouteGeometry getRouteGeometry(RoutingServiceRequestParams requestParams) {
var routingRequest = getRoutingRequest(requestParams);
return getRouteGeometry(requestParams, routingRequest);
}

private MutableRequest getRoutingRequest(RoutingServiceRequestParams requestParams) {
return MutableRequest
.GET(
osrmApiEndpoint +
osrmApiEndpointMap.get(requestParams.routingProfile()) +
"/route/v1/driving/" +
longitudeFrom +
requestParams.longitudeFrom() +
"," +
latitudeFrom +
requestParams.latitudeFrom() +
";" +
longitudeTo +
requestParams.longitudeTo() +
"," +
latitudeTo +
requestParams.latitudeTo() +
"?alternatives=false&steps=false&overview=full&geometries=geojson"
)
.header("Content-Type", "application/json");
}

public RouteGeometry getRouteGeometry(
BigDecimal longitudeFrom,
BigDecimal latitudeFrom,
BigDecimal longitudeTo,
BigDecimal latitudeTo
private RouteGeometry getRouteGeometry(
RoutingServiceRequestParams requestParams,
MutableRequest request
) {
List<List<BigDecimal>> routeCoordinates = new ArrayList<>();
MutableRequest request = getRoutingRequest(
longitudeFrom,
latitudeFrom,
longitudeTo,
latitudeTo
);
try {
HttpResponse<String> response = httpClient.send(
request,
Expand All @@ -103,10 +105,10 @@ public RouteGeometry getRouteGeometry(
logger.warn(
"OSRM route {} error for [{},{}] - [{},{}] : {}",
responseJsonNode.get("code").asText(),
longitudeFrom,
latitudeFrom,
longitudeTo,
latitudeTo,
requestParams.longitudeFrom(),
requestParams.latitudeFrom(),
requestParams.longitudeTo(),
requestParams.latitudeTo(),
responseJsonNode.get("message").asText()
);
return new RouteGeometry(routeCoordinates, BigDecimal.ZERO);
Expand All @@ -126,19 +128,19 @@ public RouteGeometry getRouteGeometry(
} catch (IOException e) {
logger.warn(
"I/O error during OSRM API request for [{},{}] - [{},{}]",
longitudeFrom,
latitudeFrom,
longitudeTo,
latitudeTo,
requestParams.longitudeFrom(),
requestParams.latitudeFrom(),
requestParams.longitudeTo(),
requestParams.latitudeTo(),
e
);
} catch (InterruptedException e) {
logger.warn(
"InterruptedException error during OSRM API request from [{},{}] to [{},{}]",
longitudeFrom,
latitudeFrom,
longitudeTo,
latitudeTo,
requestParams.longitudeFrom(),
requestParams.latitudeFrom(),
requestParams.longitudeTo(),
requestParams.latitudeTo(),
e
);
Thread.currentThread().interrupt();
Expand Down
Loading