From dcf0b2cd012d827e4e382817da2bece49cd3e9c9 Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 7 Feb 2024 14:59:24 +0100 Subject: [PATCH] Corrected format, removed API key --- .../random/adapters/RecreationIDB.java | 80 +- .../random/adapters/RecreationIDBAdapter.java | 213 ++-- .../RecreationIDBOutputDeserializer.java | 170 ++-- .../RecreationIDBRuntimeEnvironment.java | 300 +++--- .../components/geospace/routing/Valhalla.java | 25 +- .../geospace/routing/ValhallaException.java | 18 +- .../routing/ValhallaOutputDeserializer.java | 909 +++++++++--------- .../routing/ValhallaRuntimeEnvironment.java | 348 ++++--- .../components/network/model/Network.java | 139 +-- .../services/CommunityInstantiator.java | 229 +++-- .../RoutingRelationshipInstantiator.java | 572 +++++------ 11 files changed, 1508 insertions(+), 1495 deletions(-) diff --git a/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDB.java b/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDB.java index 88467f403..d7e7f265e 100644 --- a/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDB.java +++ b/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDB.java @@ -1,60 +1,36 @@ package org.integratedmodelling.random.adapters; -import java.util.List; -import java.util.Map; - import org.integratedmodelling.klab.exceptions.KlabException; public class RecreationIDB { - private boolean isOnline = false; - RecreationIDBRuntimeEnvironment ribd; - RecreationIDBOutputDeserializer deserializer; - public String service = ""; - - public RecreationIDB(){ - this("https://ridb.recreation.gov/api/v1"); - } - - public RecreationIDB(String serviceUrl){ - this.service = serviceUrl; - ribd = new RecreationIDBRuntimeEnvironment(service); - isOnline = ribd.isOnline(); - deserializer = new RecreationIDBOutputDeserializer(); - - } - - public boolean isOnline() { - return isOnline; - } - - public RecreationIDBOutputDeserializer.RecreationAreas recreationAreas(String input, String apiKey) throws KlabException{ - String response = ribd.recreationIDBSendRequest(input, RecreationIDBRuntimeEnvironment.RecreationIDBRequestType.RecAreas, apiKey); - deserializer.setJson(response); - return deserializer.deserializeRecAreasData(); - } - - public static void main(String[] args) throws KlabException { - - RecreationIDB ridb = new RecreationIDB(); - -// String input = "limit=1&offset=0&state=CO&activity=6,BOATING&radius=9.75"; - -// String input = "offset=0&activity=1&limit=10&state=CO&radius=10.0"; - - String input = "offset=0&state=CO&radius=20"; - - final String apiKey = "82b00cad-58b5-40e8-9d77-77caba299473"; - - RecreationIDBOutputDeserializer.RecreationAreas recreationAreas = ridb.recreationAreas(input,apiKey); - - List> list = recreationAreas.getData(); - System.out.println(list); - System.out.println(list.size()); - - } - - - + private boolean isOnline = false; + RecreationIDBRuntimeEnvironment ribd; + RecreationIDBOutputDeserializer deserializer; + public String service = ""; + + public RecreationIDB() { + this("https://ridb.recreation.gov/api/v1"); + } + + public RecreationIDB(String serviceUrl) { + this.service = serviceUrl; + ribd = new RecreationIDBRuntimeEnvironment(service); + isOnline = ribd.isOnline(); + deserializer = new RecreationIDBOutputDeserializer(); + + } + + public boolean isOnline() { + return isOnline; + } + + public RecreationIDBOutputDeserializer.RecreationAreas recreationAreas(String input, String apiKey) + throws KlabException { + String response = ribd.recreationIDBSendRequest(input, + RecreationIDBRuntimeEnvironment.RecreationIDBRequestType.RecAreas, apiKey); + deserializer.setJson(response); + return deserializer.deserializeRecAreasData(); + } } \ No newline at end of file diff --git a/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBAdapter.java b/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBAdapter.java index 5e24378f6..260fc44a7 100644 --- a/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBAdapter.java +++ b/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBAdapter.java @@ -31,141 +31,138 @@ public class RecreationIDBAdapter implements IUrnAdapter { public static final String NAME = "ridb"; - + public static final String RECAREAS = "recreation.areas"; - + public static final String SITES = "sites"; - + public static final String LIMIT = "limit"; public static final String OFFSET = "offset"; public static final String STATE = "state"; public static final String ACTIVITY = "activity"; public static final String RADIUS = "radius"; - - public static final String APIKEY = "apikey"; - + + public static final String APIKEY = "apikey"; + // TODO: complete other possible namespaces. public static String[] namespace_ids = new String[] { RECAREAS }; - public static String[] area_attribute_ids = new String[] { LIMIT, OFFSET, STATE, ACTIVITY, RADIUS}; - - public RecreationIDBAdapter() { + public static String[] area_attribute_ids = new String[] { LIMIT, OFFSET, STATE, ACTIVITY, RADIUS }; + + public RecreationIDBAdapter() { Arrays.sort(area_attribute_ids); Arrays.sort(namespace_ids); } - + @Override public String getName() { return NAME; } - + @Override public boolean isOnline(Urn urn) { - //TODO + // TODO return true; } - + @Override - public void encodeData(Urn urn, Builder builder, IGeometry geometry, IContextualizationScope scope) { - - Map parameters = new HashMap<>(); - if (urn.getParameters().containsKey(LIMIT)){ - parameters.put(LIMIT,urn.getParameters().get(LIMIT)); - } + public void encodeData(Urn urn, Builder builder, IGeometry geometry, IContextualizationScope scope) { + + Map parameters = new HashMap<>(); + if (urn.getParameters().containsKey(LIMIT)) { + parameters.put(LIMIT, urn.getParameters().get(LIMIT)); + } if (urn.getParameters().containsKey(OFFSET)) { parameters.put(OFFSET, urn.getParameters().get(OFFSET)); - } + } if (urn.getParameters().containsKey(STATE)) { - parameters.put(STATE,urn.getParameters().get(STATE)); - } + parameters.put(STATE, urn.getParameters().get(STATE)); + } if (urn.getParameters().containsKey(ACTIVITY)) { - parameters.put(ACTIVITY,urn.getParameters().get(ACTIVITY)) ; - } - if (urn.getParameters().containsKey(RADIUS) ) { - parameters.put(RADIUS,urn.getParameters().get(RADIUS)); + parameters.put(ACTIVITY, urn.getParameters().get(ACTIVITY)); + } + if (urn.getParameters().containsKey(RADIUS)) { + parameters.put(RADIUS, urn.getParameters().get(RADIUS)); } else { - parameters.put(RADIUS,"0.0"); + parameters.put(RADIUS, "0.0"); } - - String apiKey = urn.getParameters().containsKey(APIKEY) - ? urn.getParameters().get(APIKEY) - : "82b00cad-58b5-40e8-9d77-77caba299473"; - - IScale scale = geometry instanceof IScale ? (IScale) geometry : Scale.create(geometry); - - if (scale.getSpace() != null) { - RecreationIDB ridb = new RecreationIDB(); - List inputs = buildRecreationIDBInput(parameters); - List> data = new ArrayList>(); - inputs.forEach(input -> data.addAll(ridb.recreationAreas(input,apiKey).getData())); - - IShape shape; - - for (Map area : data) { - - double lat = (double) area.get("lat"); - double lon = (double) area.get("lon"); - String siteName = (String) area.get("name"); - - // Create the point. - // TODO: in the general case recreation areas should be polygons while entrances to the areas are points. - shape = Shape.create(lon,lat,(Projection) scope.getScale().getSpace().getProjection()); - - Builder obuilder = builder.startObject(scope.getTargetName(), siteName, makeScale(urn, shape, scope)); - - // Add attributes to each recreation area like the name and id. - for (Map.Entry entry : area.entrySet()) { - if (entry.getKey()!="lat" || entry.getKey()!="lon" || entry.getKey()!="name") { - obuilder.withMetadata(entry.getKey(), entry.getValue()); - } - } - obuilder.finishObject(); - - } - - } - + + // API key must be defined as parameter in the URN + String apiKey = urn.getParameters().containsKey(APIKEY) ? urn.getParameters().get(APIKEY) : null; + + IScale scale = geometry instanceof IScale ? (IScale) geometry : Scale.create(geometry); + + if (scale.getSpace() != null) { + RecreationIDB ridb = new RecreationIDB(); + List inputs = buildRecreationIDBInput(parameters); + List> data = new ArrayList>(); + inputs.forEach(input -> data.addAll(ridb.recreationAreas(input, apiKey).getData())); + + IShape shape; + + for (Map area : data) { + + double lat = (double) area.get("lat"); + double lon = (double) area.get("lon"); + String siteName = (String) area.get("name"); + + // Create the point. + // TODO: in the general case recreation areas should be polygons while entrances + // to the areas are points. + shape = Shape.create(lon, lat, (Projection) scope.getScale().getSpace().getProjection()); + + Builder obuilder = builder.startObject(scope.getTargetName(), siteName, makeScale(urn, shape, scope)); + + // Add attributes to each recreation area like the name and id. + for (Map.Entry entry : area.entrySet()) { + if (entry.getKey() != "lat" || entry.getKey() != "lon" || entry.getKey() != "name") { + obuilder.withMetadata(entry.getKey(), entry.getValue()); + } + } + obuilder.finishObject(); + + } + + } + } - - // TODO: There's a limit of 1000 entries hardcoded in the API. To make sure that we retrieve everything and with the ad hoc knowledge that - // there's always less than 1000 recreation sites per US state, when there are N states passed as arguments create N different GET calls to - // the API one per each state and assemble later all the responses. In the case no state parameter is specified default is retrieving from - // the entire US territory, in that case have a list of all the states hardcoded and create one GET message per state. Eventually it would - // be ideal to identify automatically the states involved and also reject responses out of the geographical scope of the context. - private final List USA_STATES = Arrays.asList("AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", - "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", - "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY"); - private List buildRecreationIDBInput(Map parameters) { - ArrayList query = new ArrayList<>(); - List states = parameters.containsKey(STATE) ? Arrays.asList(parameters.get(STATE).split(",")) : USA_STATES; - for(Map.Entry entry : parameters.entrySet()) { - if (entry.getKey().equals(STATE)) { - continue; - } - query.add(entry.getKey()+"="+entry.getValue()); - } - String finalQuery = String.join("&", query); - return states.stream().map(state -> finalQuery + "&" + STATE + "=" + state).toList(); - } - - + + private final List USA_STATES = Arrays.asList("AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", + "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", + "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", + "WA", "WV", "WI", "WY"); + + private List buildRecreationIDBInput(Map parameters) { + ArrayList query = new ArrayList<>(); + List states = parameters.containsKey(STATE) ? Arrays.asList(parameters.get(STATE).split(",")) + : USA_STATES; + for (Map.Entry entry : parameters.entrySet()) { + if (entry.getKey().equals(STATE)) { + continue; + } + query.add(entry.getKey() + "=" + entry.getValue()); + } + String finalQuery = String.join("&", query); + return states.stream().map(state -> finalQuery + "&" + STATE + "=" + state).toList(); + } + private IGeometry makeScale(Urn urn, IShape shape, IContextualizationScope scope) { - List extents = new ArrayList<>(); - extents.add(scope.getContextSubject().getScale().getTime()); - extents.add(shape); - return Scale.create(extents).asGeometry(); - } - + List extents = new ArrayList<>(); + extents.add(scope.getContextSubject().getScale().getTime()); + extents.add(shape); + return Scale.create(extents).asGeometry(); + } + @Override public IResource getResource(String urn) { Urn kurn = new Urn(urn); - ResourceReference ref = new ResourceReference(); - ref.setUrn(urn.toString()); - ref.setAdapterType(getName()); - ref.setLocalName(kurn.getResourceId()); - ref.setGeometry("#S2"); - ref.setVersion(Version.CURRENT); - ref.setType(getType(kurn)); - return new Resource(ref); + ResourceReference ref = new ResourceReference(); + ref.setUrn(urn.toString()); + ref.setAdapterType(getName()); + ref.setLocalName(kurn.getResourceId()); + ref.setGeometry("#S2"); + ref.setVersion(Version.CURRENT); + ref.setType(getType(kurn)); + return new Resource(ref); } @Override @@ -173,10 +170,9 @@ public IResource contextualize(IResource resource, IGeometry scale, IGeometry ov return resource; } - @Override public Type getType(Urn urn) { - // Instances of recreation areas are all bounded objects: polygons or points. + // Instances of recreation areas are all bounded objects: polygons or points. return Type.OBJECT; } @@ -194,9 +190,8 @@ public String getDescription() { @Override public Collection getResourceUrns() { List ret = new ArrayList<>(); - // TODO - return ret; + // TODO + return ret; } - - + } \ No newline at end of file diff --git a/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBOutputDeserializer.java b/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBOutputDeserializer.java index 1662d835f..d9f2b1a1b 100644 --- a/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBOutputDeserializer.java +++ b/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBOutputDeserializer.java @@ -1,6 +1,5 @@ package org.integratedmodelling.random.adapters; - import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -14,90 +13,89 @@ public class RecreationIDBOutputDeserializer { - public String json; - - public RecreationIDBOutputDeserializer(String json){ - this.json = json; - } - - public RecreationIDBOutputDeserializer(){ - this.json = ""; - } - - public void setJson(String json){ - this.json = json; - } - - public RecreationAreas deserializeRecAreasData(){ - ObjectMapper mapper = new ObjectMapper(); - try { - return mapper.readValue(this.json, RecreationAreas.class); - } catch (JsonProcessingException e) { - e.printStackTrace(); - return null; - } - } - - - @JsonIgnoreProperties(ignoreUnknown = true) - static public class RecreationAreas{ - - // TODO: there's more potentially interesting information that is not gathered for the time being. Only gathering coordinates, id and name. - public Collection areas; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public RecreationAreas( - @JsonProperty("RECDATA") Collection areas){ - this.areas = areas; - } - - public List> getData(){ - return this.areas.stream().map(AreaData::exportAsMap).collect(Collectors.toList()); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class AreaData{ - - public double lon; - public double lat; - public String id; - public String name; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public AreaData( - @JsonProperty("RecAreaLatitude") double lat, - @JsonProperty("RecAreaLongitude") double lon, - @JsonProperty("RecAreaID") String id, - @JsonProperty("RecAreaName") String name){ - this.lat = lat; - this.lon = lon; - this.id = id; - this.name = name; - } - - @JsonProperty("lat") - public double lat() { - return lat; - } - @JsonProperty("lon") - public double lon() { - return lon; - } - @JsonProperty("id") - public String id() { - return id; - } - @JsonProperty("name") - public String name() { - return name; - } - - public Map exportAsMap(){ - return Map.of("lat",lat,"lon",lon,"id",id,"name",name); - } - - } - - } + public String json; + + public RecreationIDBOutputDeserializer(String json) { + this.json = json; + } + + public RecreationIDBOutputDeserializer() { + this.json = ""; + } + + public void setJson(String json) { + this.json = json; + } + + public RecreationAreas deserializeRecAreasData() { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.readValue(this.json, RecreationAreas.class); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + static public class RecreationAreas { + + // TODO: there's more potentially interesting information that is not gathered + // for the time being. Only gathering coordinates, id and name. + public Collection areas; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public RecreationAreas(@JsonProperty("RECDATA") Collection areas) { + this.areas = areas; + } + + public List> getData() { + return this.areas.stream().map(AreaData::exportAsMap).collect(Collectors.toList()); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class AreaData { + + public double lon; + public double lat; + public String id; + public String name; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public AreaData(@JsonProperty("RecAreaLatitude") double lat, @JsonProperty("RecAreaLongitude") double lon, + @JsonProperty("RecAreaID") String id, @JsonProperty("RecAreaName") String name) { + this.lat = lat; + this.lon = lon; + this.id = id; + this.name = name; + } + + @JsonProperty("lat") + public double lat() { + return lat; + } + + @JsonProperty("lon") + public double lon() { + return lon; + } + + @JsonProperty("id") + public String id() { + return id; + } + + @JsonProperty("name") + public String name() { + return name; + } + + public Map exportAsMap() { + return Map.of("lat", lat, "lon", lon, "id", id, "name", name); + } + + } + + } } \ No newline at end of file diff --git a/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBRuntimeEnvironment.java b/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBRuntimeEnvironment.java index fec13ae04..fc03f82af 100644 --- a/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBRuntimeEnvironment.java +++ b/components/klab.component.random/src/main/java/org/integratedmodelling/random/adapters/RecreationIDBRuntimeEnvironment.java @@ -13,153 +13,157 @@ public class RecreationIDBRuntimeEnvironment { - public enum HTTPStatusCode { - OK(200), Unauthorized(401); - - private final int code; - - HTTPStatusCode(int code){ - this.code = code; - } - - final public int getCode() { - return this.code; - } - - static public HTTPStatusCode getStatus(int code){ - HTTPStatusCode status = null; - switch (code){ - case 200: status = HTTPStatusCode.OK; break; - case 400: status = HTTPStatusCode.Unauthorized; break; - } - return status; - } - } - - public enum RecreationIDBRequestType{ - - // TODO: think of best ways to include all the requests. - RecAreas, PermitEntrances, Facilities, Activities; - - static public String getURLSchema(RecreationIDBRequestType requestType) throws KlabException { - String urlSchema; - switch (requestType) { - case RecAreas: - urlSchema = "/recareas?"; - break; - case PermitEntrances: - urlSchema = "/permitentrances?"; - break; - case Facilities: - urlSchema = "/facilities?"; - break; - case Activities: - urlSchema = "/activities?"; - break; - default: - throw new KlabException("Request type does not exist: " + requestType +"."); - } - return urlSchema; - } - } - - private boolean isOnline = true; - - private URI baseURI; - - - - private static Logger logger = Logger.getLogger(RecreationIDBRuntimeEnvironment.class.getName()); - - public RecreationIDBRuntimeEnvironment() throws URISyntaxException { - this.setBaseURI(new URI("https://ridb.recreation.gov/api/v1")); - } - - public RecreationIDBRuntimeEnvironment(String baseURI) { - try { - this.setBaseURI(new URI(baseURI)); - } catch (URISyntaxException e) { - isOnline = false; - } - } - - public boolean isOnline(){ - return isOnline; - } - - public URI getBaseURI() { - return this.baseURI; - } - public void setBaseURI(URI baseURI) { - this.baseURI = baseURI; - } - - private GetRequest buildRequest(String URL, String input, String apiKey) { - return Unirest.get(URL+input) - .header("accept", "application/json") - .header("apikey", apiKey); - } - - private String recreationIDBResponseHandler(HttpResponse response) throws KlabException { - - // Get the response status code: - int statusCode = response.getStatus(); - HTTPStatusCode status = HTTPStatusCode.getStatus(statusCode); - - // Check the response status code and act accordingly. Note that we don't expect a 201 code - // as JSON I/O RPC is producing plain 200 with the result in the response body. - if (status == HTTPStatusCode.OK) { - logger.info("Request to Recreation Information Data Base was successful."); - - // Get the HTTP entity: - String body = response.getBody(); - - // Check the HTTP entity: - if (body == null) { - logger.severe("No content received from the Recreation Information Data Base."); - throw new KlabException("No content received from the Recreation Information Data Base."); - } - - return body; - - } else { - - if (Objects.requireNonNull(status) == HTTPStatusCode.Unauthorized) { - logger.severe(" Unauthorized access. Request failed."); - } else { - logger.severe("Request failed with code: " + statusCode); - throw new KlabException("Request failed with code: " + statusCode); - } - - String message; - String body = response.getBody(); - if (body == null) { - logger.severe("No content received from the Recreation Information Data Base."); - message = "No content received from the Recreation Information Data Base."; - } else { - try { - message = body; - } catch (RuntimeException e) { - logger.severe("Cannot read the output from the Recreation Information Data Base response."); - throw new KlabException("Cannot read the output from the Recreation Information Data Base response.", e); - } - } - logger.severe("Bad request: " + message); - throw new KlabException("Bad Request: " + message); - } - } - - public String recreationIDBSendRequest(String input, RecreationIDBRequestType requestType, String apiKey) throws KlabException{ - - String url = this.getBaseURI().toString() + RecreationIDBRequestType.getURLSchema(requestType); - GetRequest request = buildRequest(url, input, apiKey); - - logger.info("Sending synchronous request to the Recreation Information Data Base server (" + url + ")."); - - HttpResponse response; - response = request.asString(); - - return recreationIDBResponseHandler(response); - } + public enum HTTPStatusCode { + OK(200), Unauthorized(401); + + private final int code; + + HTTPStatusCode(int code) { + this.code = code; + } + + final public int getCode() { + return this.code; + } + + static public HTTPStatusCode getStatus(int code) { + HTTPStatusCode status = null; + switch (code) { + case 200: + status = HTTPStatusCode.OK; + break; + case 400: + status = HTTPStatusCode.Unauthorized; + break; + } + return status; + } + } + + public enum RecreationIDBRequestType { + + // TODO: think of best ways to include all the requests. + RecAreas, PermitEntrances, Facilities, Activities; + + static public String getURLSchema(RecreationIDBRequestType requestType) throws KlabException { + String urlSchema; + switch (requestType) { + case RecAreas: + urlSchema = "/recareas?"; + break; + case PermitEntrances: + urlSchema = "/permitentrances?"; + break; + case Facilities: + urlSchema = "/facilities?"; + break; + case Activities: + urlSchema = "/activities?"; + break; + default: + throw new KlabException("Request type does not exist: " + requestType + "."); + } + return urlSchema; + } + } + + private boolean isOnline = true; + + private URI baseURI; + + private static Logger logger = Logger.getLogger(RecreationIDBRuntimeEnvironment.class.getName()); + + public RecreationIDBRuntimeEnvironment() throws URISyntaxException { + this.setBaseURI(new URI("https://ridb.recreation.gov/api/v1")); + } + + public RecreationIDBRuntimeEnvironment(String baseURI) { + try { + this.setBaseURI(new URI(baseURI)); + } catch (URISyntaxException e) { + isOnline = false; + } + } + + public boolean isOnline() { + return isOnline; + } + + public URI getBaseURI() { + return this.baseURI; + } + + public void setBaseURI(URI baseURI) { + this.baseURI = baseURI; + } + + private GetRequest buildRequest(String URL, String input, String apiKey) { + return Unirest.get(URL + input).header("accept", "application/json").header("apikey", apiKey); + } + + private String recreationIDBResponseHandler(HttpResponse response) throws KlabException { + + // Get the response status code: + int statusCode = response.getStatus(); + HTTPStatusCode status = HTTPStatusCode.getStatus(statusCode); + + // Check the response status code and act accordingly. Note that we don't expect + // a 201 code + // as JSON I/O RPC is producing plain 200 with the result in the response body. + if (status == HTTPStatusCode.OK) { + logger.info("Request to Recreation Information Data Base was successful."); + + // Get the HTTP entity: + String body = response.getBody(); + + // Check the HTTP entity: + if (body == null) { + logger.severe("No content received from the Recreation Information Data Base."); + throw new KlabException("No content received from the Recreation Information Data Base."); + } + + return body; + + } else { + + if (Objects.requireNonNull(status) == HTTPStatusCode.Unauthorized) { + logger.severe(" Unauthorized access. Request failed."); + } else { + logger.severe("Request failed with code: " + statusCode); + throw new KlabException("Request failed with code: " + statusCode); + } + + String message; + String body = response.getBody(); + if (body == null) { + logger.severe("No content received from the Recreation Information Data Base."); + message = "No content received from the Recreation Information Data Base."; + } else { + try { + message = body; + } catch (RuntimeException e) { + logger.severe("Cannot read the output from the Recreation Information Data Base response."); + throw new KlabException( + "Cannot read the output from the Recreation Information Data Base response.", e); + } + } + logger.severe("Bad request: " + message); + throw new KlabException("Bad Request: " + message); + } + } + + public String recreationIDBSendRequest(String input, RecreationIDBRequestType requestType, String apiKey) + throws KlabException { + + String url = this.getBaseURI().toString() + RecreationIDBRequestType.getURLSchema(requestType); + GetRequest request = buildRequest(url, input, apiKey); + + logger.info("Sending synchronous request to the Recreation Information Data Base server (" + url + ")."); + + HttpResponse response; + response = request.asString(); + + return recreationIDBResponseHandler(response); + } } diff --git a/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/Valhalla.java b/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/Valhalla.java index eb93b195e..110a2d0a0 100644 --- a/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/Valhalla.java +++ b/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/Valhalla.java @@ -26,14 +26,16 @@ public class Valhalla { public Valhalla() { this("https://routing.integratedmodelling.org"); } - + public Valhalla(boolean local) { String serviceUrl; - if (local) serviceUrl = "http://localhost:8002" ; - else serviceUrl = "http://192.168.250.240:8002"; + if (local) + serviceUrl = "http://localhost:8002"; + else + serviceUrl = "http://192.168.250.240:8002"; new Valhalla(serviceUrl); } - + public Valhalla(String serviceUrl) { this.service = serviceUrl; valhalla = new ValhallaRuntimeEnvironment(this.service); @@ -83,7 +85,6 @@ public static void main(String[] args) throws ValhallaException { String input = "{\"sources\":[{\"lat\":40.544014,\"lon\":-103},{\"lat\":40.524014,\"lon\":-103}],\"targets\":[{\"lat\":40.539735,\"lon\":-103},{\"lat\":40.541735,\"lon\":-103}],\"costing\":\"auto\"}"; - // Call to matrix method with input, the function returns the deserialized JSON // string in a specific format. ValhallaOutputDeserializer.Matrix matrix = valhalla.matrix(input); @@ -126,7 +127,6 @@ public static void main(String[] args) throws ValhallaException { input = "{\"locations\":[{\"lat\":40.544014,\"lon\":-103},{\"lat\":40.524014,\"lon\":-103}],\"costing\":\"auto\"}"; - // Call to optimized route method with input, the function returns the // deserialized JSON string in a specific format. ValhallaOutputDeserializer.OptimizedRoute route = valhalla.optimized_route(input); @@ -141,20 +141,21 @@ public static void main(String[] args) throws ValhallaException { public static String buildValhallaJsonInput(IDirectObservation source, IDirectObservation target, String transportType, String geometryCollapser) { - + double[] sourceCoordinates = null; double[] targetCoordinates = null; - + // Using a switch statement for generality when more methods will be supported. - switch(geometryCollapser) { + switch (geometryCollapser) { case "centroid": sourceCoordinates = source.getSpace().getStandardizedCentroid(); targetCoordinates = target.getSpace().getStandardizedCentroid(); break; - default: - throw new KlabException("Invalid method for geometry collapse: " + geometryCollapser +". Supported: \"centroid\"."); + default: + throw new KlabException( + "Invalid method for geometry collapse: " + geometryCollapser + ". Supported: \"centroid\"."); } - + double sourceLat = sourceCoordinates[1]; double sourceLon = sourceCoordinates[0]; double targetLat = targetCoordinates[1]; diff --git a/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaException.java b/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaException.java index 239b2b95b..b2d968393 100644 --- a/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaException.java +++ b/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaException.java @@ -2,20 +2,20 @@ import org.integratedmodelling.klab.exceptions.KlabException; -public class ValhallaException extends KlabException{ +public class ValhallaException extends KlabException { private static final long serialVersionUID = -2808727016413136720L; public ValhallaException(String message) { - super(message); - } + super(message); + } - public ValhallaException(String message, Throwable cause) { - super(message, cause); - } + public ValhallaException(String message, Throwable cause) { + super(message, cause); + } - public ValhallaException(Throwable cause) { - super(cause); - } + public ValhallaException(Throwable cause) { + super(cause); + } } diff --git a/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaOutputDeserializer.java b/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaOutputDeserializer.java index ab89ddce1..263127fdd 100644 --- a/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaOutputDeserializer.java +++ b/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaOutputDeserializer.java @@ -22,453 +22,466 @@ public class ValhallaOutputDeserializer { - public String json; - - public ValhallaOutputDeserializer(String json){ - this.json = json; - } - - public ValhallaOutputDeserializer(){ - this.json = ""; - } - - public void setJson(String json){ - this.json = json; - } - - public Matrix deserializeMatrixOutput(){ - ObjectMapper mapper = new ObjectMapper(); - try { - return mapper.readValue(this.json, Matrix.class); - } catch (JsonProcessingException e) { - e.printStackTrace(); - return null; - } - } - - public OptimizedRoute deserializeOptimizedRoutes(){ - ObjectMapper mapper = new ObjectMapper(); - try { - return mapper.readValue(this.json, OptimizedRoute.class); - } catch (JsonProcessingException e) { - e.printStackTrace(); - return null; - } - } - - - static public class Matrix{ - - public String algorithm; - public String units; - public ArrayList> sources; - public ArrayList> targets; - public Collection> sourcesToTargets; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public Matrix( - @JsonProperty("algorithm") String algorithm, - @JsonProperty("units") String units, - @JsonProperty("sources") ArrayList> sources, - @JsonProperty("targets") ArrayList> targets, - @JsonProperty("sources_to_targets") Collection> sourcesToTargets){ - this.algorithm = algorithm; - this.units = units; - this.sources = sources; - this.targets = targets; - this.sourcesToTargets = sourcesToTargets; - } - - @JsonProperty("algorithm") - public String algorithm() { - return algorithm; - } - @JsonProperty("units") - public String units() { - return units; - } - @JsonProperty("sources") - public ArrayList> sources() { - return sources; - } - @JsonProperty("targets") - public ArrayList> targets() { - return targets; - } - @JsonProperty("sources_to_targets") - public Collection> sourcesToTargets() { - return sourcesToTargets; - } - - - public String getAlgorithm(){ - return this.algorithm; - } - public String getUnits(){ - return this.algorithm; - } - public List> getSources(){ - return this.sources.get(0).stream().map(Coordinates::exportAsMap).collect(Collectors.toList()); - } - public List> getTargets(){ - return this.sources.get(0).stream().map(Coordinates::exportAsMap).collect(Collectors.toList()); - } - - public List> getAdjacencyList(){ - return this.sourcesToTargets - .stream() - .flatMap(x -> x.stream().map(PairwiseDistance::exportAsMap)) - .collect(Collectors.toList()); - } - - public static class Coordinates{ - public double lon; - public double lat; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public Coordinates( - @JsonProperty("lon") double lon, - @JsonProperty("lat") double lat){ - this.lon = lon; - this.lat = lat; - } - @JsonProperty("lon") - public double lon() { - return lon; - } - @JsonProperty("lat") - public double lat() { - return lat; - } - - public Map exportAsMap(){ - return Map.of("lon", lon, "lat", lat); - } - } - - public static class PairwiseDistance{ - public double distance; - public double time; - public int targetId; - public int sourceId; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public PairwiseDistance( - @JsonProperty("distance") double distance, - @JsonProperty("time") double time, - @JsonProperty("to_index") int targetId, - @JsonProperty("from_index") int sourceId){ - this.distance = distance; - this.time = time; - this.targetId = targetId; - this.sourceId = sourceId; - } - @JsonProperty("distance") - public double distance() { - return distance; - } - @JsonProperty("time") - public double time() { - return time; - } - @JsonProperty("to_index") - public int targetId() { - return targetId; - } - - @JsonProperty("from_index") - public int sourceId() { - return sourceId; - } - - public Map exportAsMap(){ - return Map.of("source", sourceId, "target", targetId, "distance", distance, "time", time); - } - } - } - - static public class OptimizedRoute{ - public Trip trip; - - public IShape getPath() { - List polylinePath = getPolylineEncodedPath(); - Shape trajectory = PolylineDecoder.decode(polylinePath, 1E6, true); - return trajectory; - } - - public List getPolylineEncodedPath(){ - return this.trip.getPath(); - } - public List> getWaypoints(){ - return this.trip.getWaypointCoordinates(); - } - public Map getSummaryStatistics(){ - return this.trip.summary.exportSummaryStatisticsAsMap(); - } - public List> getSummaryStatisticsByLeg(){ - return this.trip.legs.stream().map(navigation -> navigation.summary.exportSummaryStatisticsAsMap()).collect(Collectors.toList()); - } - public String getUnits(){ - return this.trip.units; - } - public boolean isPossible(){ - return this.trip.status == 0; - } - - public static class Trip{ - public List locations; - public List legs; - public TripSummary summary; - public String statusMessage; - public Integer status; - public String units; - public String language; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public Trip( - @JsonProperty("locations") List locations, - @JsonProperty("legs") List legs, - @JsonProperty("summary") TripSummary summary, - @JsonProperty("status_message") String statusMessage, - @JsonProperty("status") Integer status, - @JsonProperty("units") String units, - @JsonProperty("language") String language){ - this.locations = locations; - this.legs = legs; - this.summary = summary; - this.statusMessage = statusMessage; - this.status = status; - this.units = units; - this.language = language; - } - @JsonProperty("locations") - public List locations() { - return locations; - } - @JsonProperty("legs") - public List legs() { - return legs; - } - @JsonProperty("summary") - public TripSummary summary() { - return summary; - } - @JsonProperty("status_message") - public String statusMessage() { - return statusMessage; - } - @JsonProperty("status") - public Integer status() { - return status; - } - @JsonProperty("units") - public String units() { - return units; - } - @JsonProperty("language") - public String language() { - return language; - } - - public List> getWaypointCoordinates(){ - return locations.stream().map(Location::exportCoordinatesAsMap).collect(Collectors.toList()); - } - public Map exportTripSummaryAsMap(){ - return this.summary.exportAsMap(); - } - public List getPath(){ - return legs.stream().map(navigation -> navigation.path).collect(Collectors.toList()); - } - - - public static class TripSummary{ - public boolean hasTimeRestrictions; - public boolean hasToll; - public boolean hasHighway; - public boolean hasFerry; - public Double minLat; - public Double minLon; - public Double maxLat; - public Double maxLon; - public Double time; - public Double length; - public Double cost; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public TripSummary( - @JsonProperty("hast_time_restrictions") boolean hasTimeRestrictions, - @JsonProperty("has_toll") boolean hasToll, - @JsonProperty("has_highway") boolean hasHighway, - @JsonProperty("has_ferry") boolean hasFerry, - @JsonProperty("min_lat") Double minLat, - @JsonProperty("min_lon") Double minLon, - @JsonProperty("max_lat") Double maxLat, - @JsonProperty("max_lon") Double maxLon, - @JsonProperty("time") Double time, - @JsonProperty("length") Double length, - @JsonProperty("cost") Double cost){ - this.hasTimeRestrictions = hasTimeRestrictions; - this.hasToll = hasToll; - this.hasFerry = hasFerry; - this.hasHighway = hasHighway; - this.minLat = minLat; - this.minLon = minLon; - this.maxLat = maxLat; - this.maxLon = maxLon; - this.time = time; - this.length = length; - this.cost = cost; - } - @JsonProperty("has_time_restrictions") - public boolean hasTimeRestrictions() { - return hasTimeRestrictions; - } - @JsonProperty("has_toll") - public boolean hasToll() { - return hasToll; - } - @JsonProperty("hasFerry") - public boolean hasFerry() { - return hasFerry; - } - @JsonProperty("hasHighway") - public boolean hasHighway() { - return hasHighway; - } - @JsonProperty("min_lon") - public Double minLon() { - return minLon; - } - @JsonProperty("min_lat") - public Double minLat() { - return minLat; - } - @JsonProperty("max_lon") - public Double maxLon() { - return maxLon; - } - @JsonProperty("max_lat") - public Double maxLat() { - return maxLat; - } - @JsonProperty("time") - public Double time() { - return time; - } - @JsonProperty("length") - public Double lenght() { - return length; - } - @JsonProperty("cost") - public Double cost() { - return cost; - } - - public Map exportAsMap(){ - return Map.ofEntries( - Map.entry("has_time_restrictions", hasTimeRestrictions), - Map.entry("has_toll", hasToll), - Map.entry("has_highway", hasHighway), - Map.entry("has_ferry", hasFerry), - Map.entry("min_lat", minLat), - Map.entry("min_lon", minLon), - Map.entry("max_lat", maxLat), - Map.entry("max_lon", maxLon), - Map.entry("time", time), - Map.entry("length", length), - Map.entry( "cost", cost) - ); - } - public Map exportSummaryStatisticsAsMap(){ - return Map.of("time", time, "length", length, "cost", cost); - } - } - - public static class Navigation{ - public List maneuvers; - public TripSummary summary; - public String path; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public Navigation( - @JsonProperty("maneuvers") List maneuvers, - @JsonProperty("summary") TripSummary summary, - @JsonProperty("shape") String path){ - this.maneuvers = maneuvers; - this.summary = summary; - this.path = path; - } - @JsonProperty("maneuvers") - public List maneuvers() { - return maneuvers; - } - @JsonProperty("summary") - public TripSummary summary() { - return summary; - } - @JsonProperty("shape") - public String path() { - return path; - } - - public Map exportTripSummaryAsMap(){ - return this.summary.exportAsMap(); - } - - } - - public static class Location{ - public String type; - public double lat; - public double lon; - public String sideOfStreet; - public Integer originalIndex; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public Location( - @JsonProperty("type") String type, - @JsonProperty("lat") double lat, - @JsonProperty("lon") double lon, - @JsonProperty("side_of_street") String sideOfStreet, - @JsonProperty("original_index") Integer originalIndex){ - this.type = type; - this.lon = lon; - this.lat = lat; - this.sideOfStreet = sideOfStreet; - this.originalIndex = originalIndex; - } - @JsonProperty("type") - public String type() { - return type; - } - @JsonProperty("lon") - public double lon() { - return lon; - } - @JsonProperty("lat") - public double lat() { - return lat; - } - @JsonProperty("side_of_street") - public String sideOfStreet() { - return sideOfStreet; - } - @JsonProperty("original_index") - public Integer originalIndex() { - return originalIndex; - } - - public Map exportCoordinatesAsMap(){ - return Map.of("lon", lon, "lat", lat,"id",originalIndex); - } - - public Map exportAsMap(){ - return Map.of("type", type, "lon", lon, "lat", lat, "side_of_street", sideOfStreet, "original_index", originalIndex); - } - } - - } - - } + public String json; + + public ValhallaOutputDeserializer(String json) { + this.json = json; + } + + public ValhallaOutputDeserializer() { + this.json = ""; + } + + public void setJson(String json) { + this.json = json; + } + + public Matrix deserializeMatrixOutput() { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.readValue(this.json, Matrix.class); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + public OptimizedRoute deserializeOptimizedRoutes() { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.readValue(this.json, OptimizedRoute.class); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + static public class Matrix { + + public String algorithm; + public String units; + public ArrayList> sources; + public ArrayList> targets; + public Collection> sourcesToTargets; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public Matrix(@JsonProperty("algorithm") String algorithm, @JsonProperty("units") String units, + @JsonProperty("sources") ArrayList> sources, + @JsonProperty("targets") ArrayList> targets, + @JsonProperty("sources_to_targets") Collection> sourcesToTargets) { + this.algorithm = algorithm; + this.units = units; + this.sources = sources; + this.targets = targets; + this.sourcesToTargets = sourcesToTargets; + } + + @JsonProperty("algorithm") + public String algorithm() { + return algorithm; + } + + @JsonProperty("units") + public String units() { + return units; + } + + @JsonProperty("sources") + public ArrayList> sources() { + return sources; + } + + @JsonProperty("targets") + public ArrayList> targets() { + return targets; + } + + @JsonProperty("sources_to_targets") + public Collection> sourcesToTargets() { + return sourcesToTargets; + } + + public String getAlgorithm() { + return this.algorithm; + } + + public String getUnits() { + return this.algorithm; + } + + public List> getSources() { + return this.sources.get(0).stream().map(Coordinates::exportAsMap).collect(Collectors.toList()); + } + + public List> getTargets() { + return this.sources.get(0).stream().map(Coordinates::exportAsMap).collect(Collectors.toList()); + } + + public List> getAdjacencyList() { + return this.sourcesToTargets.stream().flatMap(x -> x.stream().map(PairwiseDistance::exportAsMap)) + .collect(Collectors.toList()); + } + + public static class Coordinates { + public double lon; + public double lat; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public Coordinates(@JsonProperty("lon") double lon, @JsonProperty("lat") double lat) { + this.lon = lon; + this.lat = lat; + } + + @JsonProperty("lon") + public double lon() { + return lon; + } + + @JsonProperty("lat") + public double lat() { + return lat; + } + + public Map exportAsMap() { + return Map.of("lon", lon, "lat", lat); + } + } + + public static class PairwiseDistance { + public double distance; + public double time; + public int targetId; + public int sourceId; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public PairwiseDistance(@JsonProperty("distance") double distance, @JsonProperty("time") double time, + @JsonProperty("to_index") int targetId, @JsonProperty("from_index") int sourceId) { + this.distance = distance; + this.time = time; + this.targetId = targetId; + this.sourceId = sourceId; + } + + @JsonProperty("distance") + public double distance() { + return distance; + } + + @JsonProperty("time") + public double time() { + return time; + } + + @JsonProperty("to_index") + public int targetId() { + return targetId; + } + + @JsonProperty("from_index") + public int sourceId() { + return sourceId; + } + + public Map exportAsMap() { + return Map.of("source", sourceId, "target", targetId, "distance", distance, "time", time); + } + } + } + + static public class OptimizedRoute { + public Trip trip; + + public IShape getPath() { + List polylinePath = getPolylineEncodedPath(); + Shape trajectory = PolylineDecoder.decode(polylinePath, 1E6, true); + return trajectory; + } + + public List getPolylineEncodedPath() { + return this.trip.getPath(); + } + + public List> getWaypoints() { + return this.trip.getWaypointCoordinates(); + } + + public Map getSummaryStatistics() { + return this.trip.summary.exportSummaryStatisticsAsMap(); + } + + public List> getSummaryStatisticsByLeg() { + return this.trip.legs.stream().map(navigation -> navigation.summary.exportSummaryStatisticsAsMap()) + .collect(Collectors.toList()); + } + + public String getUnits() { + return this.trip.units; + } + + public boolean isPossible() { + return this.trip.status == 0; + } + + public static class Trip { + public List locations; + public List legs; + public TripSummary summary; + public String statusMessage; + public Integer status; + public String units; + public String language; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public Trip(@JsonProperty("locations") List locations, + @JsonProperty("legs") List legs, @JsonProperty("summary") TripSummary summary, + @JsonProperty("status_message") String statusMessage, @JsonProperty("status") Integer status, + @JsonProperty("units") String units, @JsonProperty("language") String language) { + this.locations = locations; + this.legs = legs; + this.summary = summary; + this.statusMessage = statusMessage; + this.status = status; + this.units = units; + this.language = language; + } + + @JsonProperty("locations") + public List locations() { + return locations; + } + + @JsonProperty("legs") + public List legs() { + return legs; + } + + @JsonProperty("summary") + public TripSummary summary() { + return summary; + } + + @JsonProperty("status_message") + public String statusMessage() { + return statusMessage; + } + + @JsonProperty("status") + public Integer status() { + return status; + } + + @JsonProperty("units") + public String units() { + return units; + } + + @JsonProperty("language") + public String language() { + return language; + } + + public List> getWaypointCoordinates() { + return locations.stream().map(Location::exportCoordinatesAsMap).collect(Collectors.toList()); + } + + public Map exportTripSummaryAsMap() { + return this.summary.exportAsMap(); + } + + public List getPath() { + return legs.stream().map(navigation -> navigation.path).collect(Collectors.toList()); + } + + public static class TripSummary { + public boolean hasTimeRestrictions; + public boolean hasToll; + public boolean hasHighway; + public boolean hasFerry; + public Double minLat; + public Double minLon; + public Double maxLat; + public Double maxLon; + public Double time; + public Double length; + public Double cost; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public TripSummary(@JsonProperty("hast_time_restrictions") boolean hasTimeRestrictions, + @JsonProperty("has_toll") boolean hasToll, @JsonProperty("has_highway") boolean hasHighway, + @JsonProperty("has_ferry") boolean hasFerry, @JsonProperty("min_lat") Double minLat, + @JsonProperty("min_lon") Double minLon, @JsonProperty("max_lat") Double maxLat, + @JsonProperty("max_lon") Double maxLon, @JsonProperty("time") Double time, + @JsonProperty("length") Double length, @JsonProperty("cost") Double cost) { + this.hasTimeRestrictions = hasTimeRestrictions; + this.hasToll = hasToll; + this.hasFerry = hasFerry; + this.hasHighway = hasHighway; + this.minLat = minLat; + this.minLon = minLon; + this.maxLat = maxLat; + this.maxLon = maxLon; + this.time = time; + this.length = length; + this.cost = cost; + } + + @JsonProperty("has_time_restrictions") + public boolean hasTimeRestrictions() { + return hasTimeRestrictions; + } + + @JsonProperty("has_toll") + public boolean hasToll() { + return hasToll; + } + + @JsonProperty("hasFerry") + public boolean hasFerry() { + return hasFerry; + } + + @JsonProperty("hasHighway") + public boolean hasHighway() { + return hasHighway; + } + + @JsonProperty("min_lon") + public Double minLon() { + return minLon; + } + + @JsonProperty("min_lat") + public Double minLat() { + return minLat; + } + + @JsonProperty("max_lon") + public Double maxLon() { + return maxLon; + } + + @JsonProperty("max_lat") + public Double maxLat() { + return maxLat; + } + + @JsonProperty("time") + public Double time() { + return time; + } + + @JsonProperty("length") + public Double lenght() { + return length; + } + + @JsonProperty("cost") + public Double cost() { + return cost; + } + + public Map exportAsMap() { + return Map.ofEntries(Map.entry("has_time_restrictions", hasTimeRestrictions), + Map.entry("has_toll", hasToll), Map.entry("has_highway", hasHighway), + Map.entry("has_ferry", hasFerry), Map.entry("min_lat", minLat), + Map.entry("min_lon", minLon), Map.entry("max_lat", maxLat), Map.entry("max_lon", maxLon), + Map.entry("time", time), Map.entry("length", length), Map.entry("cost", cost)); + } + + public Map exportSummaryStatisticsAsMap() { + return Map.of("time", time, "length", length, "cost", cost); + } + } + + public static class Navigation { + public List maneuvers; + public TripSummary summary; + public String path; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public Navigation(@JsonProperty("maneuvers") List maneuvers, + @JsonProperty("summary") TripSummary summary, @JsonProperty("shape") String path) { + this.maneuvers = maneuvers; + this.summary = summary; + this.path = path; + } + + @JsonProperty("maneuvers") + public List maneuvers() { + return maneuvers; + } + + @JsonProperty("summary") + public TripSummary summary() { + return summary; + } + + @JsonProperty("shape") + public String path() { + return path; + } + + public Map exportTripSummaryAsMap() { + return this.summary.exportAsMap(); + } + + } + + public static class Location { + public String type; + public double lat; + public double lon; + public String sideOfStreet; + public Integer originalIndex; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public Location(@JsonProperty("type") String type, @JsonProperty("lat") double lat, + @JsonProperty("lon") double lon, @JsonProperty("side_of_street") String sideOfStreet, + @JsonProperty("original_index") Integer originalIndex) { + this.type = type; + this.lon = lon; + this.lat = lat; + this.sideOfStreet = sideOfStreet; + this.originalIndex = originalIndex; + } + + @JsonProperty("type") + public String type() { + return type; + } + + @JsonProperty("lon") + public double lon() { + return lon; + } + + @JsonProperty("lat") + public double lat() { + return lat; + } + + @JsonProperty("side_of_street") + public String sideOfStreet() { + return sideOfStreet; + } + + @JsonProperty("original_index") + public Integer originalIndex() { + return originalIndex; + } + + public Map exportCoordinatesAsMap() { + return Map.of("lon", lon, "lat", lat, "id", originalIndex); + } + + public Map exportAsMap() { + return Map.of("type", type, "lon", lon, "lat", lat, "side_of_street", sideOfStreet, + "original_index", originalIndex); + } + } + + } + + } } diff --git a/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaRuntimeEnvironment.java b/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaRuntimeEnvironment.java index 28eca658d..a1bd410e7 100644 --- a/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaRuntimeEnvironment.java +++ b/klab.engine/src/main/java/org/integratedmodelling/klab/components/geospace/routing/ValhallaRuntimeEnvironment.java @@ -15,165 +15,193 @@ public class ValhallaRuntimeEnvironment { static final Boolean log_only_critical = false; - - public enum HTTPStatusCode { - SUCCESS(200),FAIL(400),INVALID_PATH(404),INVALID_MESSAGE(405),SERVER_PROBLEM(500),NOT_IMPLEMENTED(501); - - private int code; - - HTTPStatusCode(int code){ - this.code = code; - } - - final public int getCode() { - return this.code; - } - - static public HTTPStatusCode getStatus(int code){ - HTTPStatusCode status = null; - switch (code){ - case 200: status = HTTPStatusCode.SUCCESS;break; - case 400: status = HTTPStatusCode.FAIL;break; - case 404: status = HTTPStatusCode.INVALID_PATH;break; - case 405: status = HTTPStatusCode.INVALID_MESSAGE;break; - case 500: status = HTTPStatusCode.SERVER_PROBLEM;break; - case 501: status = HTTPStatusCode.NOT_IMPLEMENTED;break; - } - return status; - } - } - - public enum ValhallaRequestType{ - ROUTE, OPTIMIZE, MATRIX, ISOCHRONE; - - static public String getURLSchema(ValhallaRequestType requestType) throws ValhallaException { - String urlSchema; - switch (requestType) { - case ROUTE: urlSchema = "/route?json=";break; - case OPTIMIZE: urlSchema = "/optimized_route?json=";break; - case MATRIX: urlSchema = "/sources_to_targets?json=";break; - case ISOCHRONE: urlSchema = "/isochrone?json=";break; - default: throw new ValhallaException("Request type does not exist: " + requestType +"."); - } - return urlSchema; - } - } - - private boolean isOnline = true; - - private URI baseURI; - - private static Logger logger = Logger.getLogger(ValhallaRuntimeEnvironment.class.getName()); - - public ValhallaRuntimeEnvironment() throws URISyntaxException { - this.setBaseURI(new URI("http", null, "localhost", 8002, null, null, null)); - } - - public ValhallaRuntimeEnvironment(String baseURI) { - try { - this.setBaseURI(new URI(baseURI)); - } catch (URISyntaxException e) { - isOnline = false; - } - } - - public boolean isOnline(){ - return isOnline; - } - - public URI getBaseURI() { - return this.baseURI; - } - public void setBaseURI(URI baseURI) { - this.baseURI = baseURI; - } - - private HttpRequest buildRequest(String URL, String input) { - return HttpRequest.newBuilder() - .uri(URI.create(URL)) - .header("Content-type", "application/json") - .POST(BodyPublishers.ofString(input)) - .build(); - } - - private String valhallaResponseHandler(HttpResponse response) throws ValhallaException { - - // Get the response status code: - int statusCode = response.statusCode(); - HTTPStatusCode status = HTTPStatusCode.getStatus(statusCode); - - // Check the response status code and act accordingly. Note that we don't expect a 201 code - // as JSON I/O RPC is producing plain 200 with the result in the response body. - if (status == HTTPStatusCode.SUCCESS) { - - if(!log_only_critical) { - logger.info("Request to valhalla.test.Valhalla Server has been successful."); - } - - // Get the HTTP entity: - String body = response.body(); - - // Check the HTTP entity: - if (body == null) { - logger.severe("No content received from valhalla.test.Valhalla Server."); - throw new ValhallaException("No content received from valhalla.test.Valhalla Server."); - } - - return body; - - } else { - - switch (status) { - case FAIL: - logger.severe("Request to valhalla.test.Valhalla Server has failed.");break; - case INVALID_PATH: - logger.severe("Request to valhalla.test.Valhalla Server has failed: invalid path.");break; - case INVALID_MESSAGE: - logger.severe("Request to valhalla.test.Valhalla Server has failed: invalid message.");break; - case SERVER_PROBLEM: - logger.severe("Request to valhalla.test.Valhalla Server has failed: server problem.");break; - case NOT_IMPLEMENTED: - logger.severe("Request to valhalla.test.Valhalla Server has failed: not implemented.");break; - default: - {logger.severe("Unrecognized response from the valhalla.test.Valhalla Server: " + statusCode); - throw new ValhallaException("Unrecognized response from the valhalla.test.Valhalla Server: " + statusCode);} - } - - String message; - String body = response.body(); - if (body == null) { - logger.severe("No content received from valhalla.test.Valhalla Server."); - message = "No content received from valhalla.test.Valhalla Server."; - } else { - try { - message = body; - } catch (RuntimeException e) { - logger.severe("Cannot read the output from valhalla.test.Valhalla server response."); - throw new ValhallaException("Cannot read the output from valhalla.test.Valhalla server response.", e); - } - } - logger.severe("Bad request: " + message); - throw new ValhallaException("Bad Request: " + message); - } - } - - public String valhallaSendRequest(String input, ValhallaRequestType requestType) throws ValhallaException{ - - String url = this.getBaseURI().toString() + ValhallaRequestType.getURLSchema(requestType); - HttpRequest request = buildRequest(url, input); - - if (!log_only_critical) { - logger.info("Sending synchronous request to valhalla.test.Valhalla server (" + url + ")."); - } - - HttpResponse response; - try { - response = HttpClient.newHttpClient().send(request, BodyHandlers.ofString()); - } catch (IOException | InterruptedException ie) { - throw new ValhallaException(ie); - } - - return valhallaResponseHandler(response); - } + + public enum HTTPStatusCode { + SUCCESS(200), FAIL(400), INVALID_PATH(404), INVALID_MESSAGE(405), SERVER_PROBLEM(500), NOT_IMPLEMENTED(501); + + private int code; + + HTTPStatusCode(int code) { + this.code = code; + } + + final public int getCode() { + return this.code; + } + + static public HTTPStatusCode getStatus(int code) { + HTTPStatusCode status = null; + switch (code) { + case 200: + status = HTTPStatusCode.SUCCESS; + break; + case 400: + status = HTTPStatusCode.FAIL; + break; + case 404: + status = HTTPStatusCode.INVALID_PATH; + break; + case 405: + status = HTTPStatusCode.INVALID_MESSAGE; + break; + case 500: + status = HTTPStatusCode.SERVER_PROBLEM; + break; + case 501: + status = HTTPStatusCode.NOT_IMPLEMENTED; + break; + } + return status; + } + } + + public enum ValhallaRequestType { + ROUTE, OPTIMIZE, MATRIX, ISOCHRONE; + + static public String getURLSchema(ValhallaRequestType requestType) throws ValhallaException { + String urlSchema; + switch (requestType) { + case ROUTE: + urlSchema = "/route?json="; + break; + case OPTIMIZE: + urlSchema = "/optimized_route?json="; + break; + case MATRIX: + urlSchema = "/sources_to_targets?json="; + break; + case ISOCHRONE: + urlSchema = "/isochrone?json="; + break; + default: + throw new ValhallaException("Request type does not exist: " + requestType + "."); + } + return urlSchema; + } + } + + private boolean isOnline = true; + + private URI baseURI; + + private static Logger logger = Logger.getLogger(ValhallaRuntimeEnvironment.class.getName()); + + public ValhallaRuntimeEnvironment() throws URISyntaxException { + this.setBaseURI(new URI("http", null, "localhost", 8002, null, null, null)); + } + + public ValhallaRuntimeEnvironment(String baseURI) { + try { + this.setBaseURI(new URI(baseURI)); + } catch (URISyntaxException e) { + isOnline = false; + } + } + + public boolean isOnline() { + return isOnline; + } + + public URI getBaseURI() { + return this.baseURI; + } + + public void setBaseURI(URI baseURI) { + this.baseURI = baseURI; + } + + private HttpRequest buildRequest(String URL, String input) { + return HttpRequest.newBuilder().uri(URI.create(URL)).header("Content-type", "application/json") + .POST(BodyPublishers.ofString(input)).build(); + } + + private String valhallaResponseHandler(HttpResponse response) throws ValhallaException { + + // Get the response status code: + int statusCode = response.statusCode(); + HTTPStatusCode status = HTTPStatusCode.getStatus(statusCode); + + // Check the response status code and act accordingly. Note that we don't expect + // a 201 code + // as JSON I/O RPC is producing plain 200 with the result in the response body. + if (status == HTTPStatusCode.SUCCESS) { + + if (!log_only_critical) { + logger.info("Request to valhalla.test.Valhalla Server has been successful."); + } + + // Get the HTTP entity: + String body = response.body(); + + // Check the HTTP entity: + if (body == null) { + logger.severe("No content received from valhalla.test.Valhalla Server."); + throw new ValhallaException("No content received from valhalla.test.Valhalla Server."); + } + + return body; + + } else { + + switch (status) { + case FAIL: + logger.severe("Request to valhalla.test.Valhalla Server has failed."); + break; + case INVALID_PATH: + logger.severe("Request to valhalla.test.Valhalla Server has failed: invalid path."); + break; + case INVALID_MESSAGE: + logger.severe("Request to valhalla.test.Valhalla Server has failed: invalid message."); + break; + case SERVER_PROBLEM: + logger.severe("Request to valhalla.test.Valhalla Server has failed: server problem."); + break; + case NOT_IMPLEMENTED: + logger.severe("Request to valhalla.test.Valhalla Server has failed: not implemented."); + break; + default: { + logger.severe("Unrecognized response from the valhalla.test.Valhalla Server: " + statusCode); + throw new ValhallaException( + "Unrecognized response from the valhalla.test.Valhalla Server: " + statusCode); + } + } + + String message; + String body = response.body(); + if (body == null) { + logger.severe("No content received from valhalla.test.Valhalla Server."); + message = "No content received from valhalla.test.Valhalla Server."; + } else { + try { + message = body; + } catch (RuntimeException e) { + logger.severe("Cannot read the output from valhalla.test.Valhalla server response."); + throw new ValhallaException("Cannot read the output from valhalla.test.Valhalla server response.", + e); + } + } + logger.severe("Bad request: " + message); + throw new ValhallaException("Bad Request: " + message); + } + } + + public String valhallaSendRequest(String input, ValhallaRequestType requestType) throws ValhallaException { + + String url = this.getBaseURI().toString() + ValhallaRequestType.getURLSchema(requestType); + HttpRequest request = buildRequest(url, input); + + if (!log_only_critical) { + logger.info("Sending synchronous request to valhalla.test.Valhalla server (" + url + ")."); + } + + HttpResponse response; + try { + response = HttpClient.newHttpClient().send(request, BodyHandlers.ofString()); + } catch (IOException | InterruptedException ie) { + throw new ValhallaException(ie); + } + + return valhallaResponseHandler(response); + } } diff --git a/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/model/Network.java b/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/model/Network.java index dd256ae1b..513331bd6 100644 --- a/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/model/Network.java +++ b/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/model/Network.java @@ -52,19 +52,20 @@ public class Network extends Pattern implements INetwork { public Graph getNetwork() { return network; } - + public Network(Collection observations, IRuntimeScope scope) { super(observations, scope); - - IDirectObservation source=null; - IDirectObservation target=null; + + IDirectObservation source = null; + IDirectObservation target = null; for (IObservation observation : observations) { for (IArtifact artifact : observation) { if (artifact instanceof IRelationship) { source = scope.getSourceSubject((IRelationship) artifact); target = scope.getTargetSubject((IRelationship) artifact); - network.addVertex(source); network.addVertex(target); + network.addVertex(source); + network.addVertex(target); network.addEdge(source, target, (IRelationship) artifact); } } @@ -74,32 +75,37 @@ public Network(Collection observations, IRuntimeScope scope) { /* - * Utility method to facilitate the export of networks with multiple edge parameters in CSV format. CSV export only exports weights as edge attributes thus - * a weighted multigraph is built from the relationships graph and the weight of each edge between a pair of nodes is extracted from the relationship metadata. - * */ - public static WeightedMultigraph> asWeightedMultigraph(Graph network){ - - WeightedMultigraph> wmg = new WeightedMultigraph<>(Pair.class); - + * Utility method to facilitate the export of networks with multiple edge + * parameters in CSV format. CSV export only exports weights as edge attributes + * thus a weighted multigraph is built from the relationships graph and the + * weight of each edge between a pair of nodes is extracted from the + * relationship metadata. + */ + public static WeightedMultigraph> asWeightedMultigraph( + Graph network) { + + WeightedMultigraph> wmg = new WeightedMultigraph<>(Pair.class); + Integer i = 0; for (IRelationship e : network.edgeSet()) { - - i += 1; - + + i += 1; + IDirectObservation source = e.getSource(); - IDirectObservation target = e.getTarget(); - wmg.addVertex(source); wmg.addVertex(target); - - for (Entry entry: e.getMetadata().entrySet()) { - Pair edge = new Pair(i, entry.getKey()); - wmg.addEdge(source, target, edge); - wmg.setEdgeWeight(edge, (Double) entry.getValue()); - } - + IDirectObservation target = e.getTarget(); + wmg.addVertex(source); + wmg.addVertex(target); + + for (Entry entry : e.getMetadata().entrySet()) { + Pair edge = new Pair(i, entry.getKey()); + wmg.addEdge(source, target, edge); + wmg.setEdgeWeight(edge, (Double) entry.getValue()); + } + } - + return wmg; - + } @@ -107,31 +113,31 @@ public static WeightedMultigraph> asWei @Override public void export(String format, OutputStream output) { - // Define vertex and edges attribute providers. + // Define vertex and edges attribute providers. Function> vertexAttributeProvider = v -> { - Map map = new LinkedHashMap<>(); - double[] xy = v.getSpace().getShape().getCenter(true); - map.put("latitude", DefaultAttribute.createAttribute(xy[1])); - map.put("longitude", DefaultAttribute.createAttribute(xy[0])); - return map; + Map map = new LinkedHashMap<>(); + double[] xy = v.getSpace().getShape().getCenter(true); + map.put("latitude", DefaultAttribute.createAttribute(xy[1])); + map.put("longitude", DefaultAttribute.createAttribute(xy[0])); + return map; }; - + Function> edgeAttributeProvider = e -> { - Map map = new LinkedHashMap<>(); - - String time = e.getScale().getTime().getStart().toRFC3339String(); - map.put("time", DefaultAttribute.createAttribute(time)); - - // Adding relationship metadata as edge attributes. - for (Entry entry: e.getMetadata().entrySet()) { - map.put(entry.getKey(), DefaultAttribute.createAttribute( ((Double) entry.getValue()).toString()) ); - } - - return map; + Map map = new LinkedHashMap<>(); + + String time = e.getScale().getTime().getStart().toRFC3339String(); + map.put("time", DefaultAttribute.createAttribute(time)); + + // Adding relationship metadata as edge attributes. + for (Entry entry : e.getMetadata().entrySet()) { + map.put(entry.getKey(), DefaultAttribute.createAttribute(((Double) entry.getValue()).toString())); + } + + return map; }; - + Writer writer = new OutputStreamWriter(output); - + switch (format) { case "json": JSONExporter json = new JSONExporter<>(); @@ -154,8 +160,8 @@ public void export(String format, OutputStream output) { graphml.exportGraph(network, writer); break; case "csv": - WeightedMultigraph> wmg = Network.asWeightedMultigraph(network); - CSVExporter> csv = new CSVExporter<>(); + WeightedMultigraph> wmg = Network.asWeightedMultigraph(network); + CSVExporter> csv = new CSVExporter<>(); csv.setFormat(CSVFormat.EDGE_LIST); csv.setParameter(CSVFormat.Parameter.EDGE_WEIGHTS, true); csv.setVertexAttributeProvider(vertexAttributeProvider); @@ -184,35 +190,36 @@ public void export(String format, OutputStream output) { def.setVertexAttributeProvider(vertexAttributeProvider); def.setEdgeAttributeProvider(edgeAttributeProvider); def.exportGraph(network, writer); - throw new KlabIOException("Solicited graph export format is not supported or does not exist. Exporting in JSON format instead."); + throw new KlabIOException( + "Solicited graph export format is not supported or does not exist. Exporting in JSON format instead."); } } - public void export(String format, String filename){ - try { - OutputStream out = new FileOutputStream( new File(filename) ); - export(format, out); - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - + public void export(String format, String filename) { + try { + OutputStream out = new FileOutputStream(new File(filename)); + export(format, out); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + public void JSONGraphToCSV(String inFile, String outFile) { - + @SuppressWarnings("unchecked") - Map map = JsonUtils.load(new File(inFile), Map.class); - + Map map = JsonUtils.load(new File(inFile), Map.class); + Object nodes = map.get("nodes"); - + Object edges = map.get("edges"); - + System.out.println(JsonUtils.printAsJson(nodes)); System.out.println(JsonUtils.printAsJson(edges)); } - + @Override public Collection> getExportCapabilities(IObservation observation) { List> ret = new ArrayList<>(); diff --git a/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/services/CommunityInstantiator.java b/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/services/CommunityInstantiator.java index 25f12b379..255cca704 100644 --- a/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/services/CommunityInstantiator.java +++ b/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/services/CommunityInstantiator.java @@ -28,11 +28,9 @@ import org.integratedmodelling.klab.api.observations.IConfiguration; import org.integratedmodelling.klab.api.observations.IDirectObservation; import org.integratedmodelling.klab.api.observations.IObservation; -import org.integratedmodelling.klab.api.observations.IObservationGroup; import org.integratedmodelling.klab.api.observations.IRelationship; import org.integratedmodelling.klab.api.observations.scale.IScale; import org.integratedmodelling.klab.api.observations.scale.space.IShape; -import org.integratedmodelling.klab.api.provenance.IArtifact; import org.integratedmodelling.klab.api.provenance.IArtifact.Type; import org.integratedmodelling.klab.api.runtime.IContextualizationScope; import org.integratedmodelling.klab.components.geospace.routing.ValhallaException; @@ -45,49 +43,52 @@ public class CommunityInstantiator extends AbstractContextualizer implements IExpression, IInstantiator { - private final static String infomap_url = "http://127.0.0.1:5000"; - - private String networkArtifact = null; - + + private String networkArtifact = null; + private Network network; private IContextualizationScope scope; - + String name = null; Map communityMap; - - - public CommunityInstantiator() {/* to instantiate as expression - do not remove (or use) */} - - + + public CommunityInstantiator() { + /* to instantiate as expression - do not remove (or use) */} + public CommunityInstantiator(IParameters parameters, IContextualizationScope scope) { - + this.scope = scope; this.networkArtifact = parameters.get("network", String.class); - + } - - + @Override public List instantiate(IObservable semantics, IContextualizationScope scope) throws KlabException { - + IConcept networkConcept = semantics.getType(); List networks = new ArrayList<>(); - + if (networkArtifact == null) { - - // All configurations from the context are recovered, thus this might cause trouble if there are multiple. + + // All configurations from the context are recovered, thus this might cause + // trouble if there are multiple. networks = new ArrayList<>(scope.getContextObservation().getChildren(IConfiguration.class)); - + } else { - - // TODO: name of the network observation is different than name of the artifact!! - String obsName = networkArtifact.substring(networkArtifact.lastIndexOf(':') + 1).replaceAll("(.)(\\p{Lu})", "$1_$2").toLowerCase(); - - // Adding only the configuration with the name of the passed network. This works as long as the semantics are attached to a single network vs. multiple disconnected ones. - networks.add(scope.getContextObservation().getChildren(IConfiguration.class).stream().filter(c->c.getName().equals(obsName)).iterator().next()); - + + // TODO: name of the network observation is different than name of the + // artifact!! + String obsName = networkArtifact.substring(networkArtifact.lastIndexOf(':') + 1) + .replaceAll("(.)(\\p{Lu})", "$1_$2").toLowerCase(); + + // Adding only the configuration with the name of the passed network. This works + // as long as the semantics are attached to a single network vs. multiple + // disconnected ones. + networks.add(scope.getContextObservation().getChildren(IConfiguration.class).stream() + .filter(c -> c.getName().equals(obsName)).iterator().next()); + // IArtifact net = scope.getArtifact(networkArtifact); // // if (net instanceof IObservationGroup) { @@ -98,78 +99,69 @@ public List instantiate(IObservable semantics, IContextualizati // networks.add((IObservation) net); // } } - - switch (networks.size()){ + switch (networks.size()) { case 1: // if ( !(networks.get(0) instanceof IDirectObservation) ) { // throw new IllegalArgumentException("Network observation is not a direct observation"); // } - + this.network = (Network) ((IDirectObservation) networks.get(0)).getOriginatingPattern(); - break; + break; case 0: - throw new KlabException("Community instantiator finished with errors. There are no observations of " + networkConcept.getName() + " in the scope."); - /* There cannot be multiple network objects of the same network in the scope. Disconnected networks are disconnected subgraphs of the same graph.*/ + throw new KlabException("Community instantiator finished with errors. There are no observations of " + + networkConcept.getName() + " in the scope."); + /* + * There cannot be multiple network objects of the same network in the scope. + * Disconnected networks are disconnected subgraphs of the same graph. + */ default: - throw new KlabException("Community instantiator finished with errors. There are multiple instances of " + networkConcept.getName() + " in the scope."); + throw new KlabException("Community instantiator finished with errors. There are multiple instances of " + + networkConcept.getName() + " in the scope."); } - + /* * Build the data package to be sent to the Infomap server. - * */ - + */ + KlabData.Object.Builder encodedNetwork = KlabData.Object.newBuilder().setName("test-net"); - Map edgeProperties; - + Map edgeProperties; + for (IRelationship edge : network.getNetwork().edgeSet()) { - - edgeProperties = edge.getMetadata().entrySet() - .stream() - .collect(Collectors.toMap( - e -> e.getKey(), - e -> e.getValue() != null ? e.getValue().toString(): null - )); - - edgeProperties.put("source", edge.getSource().getName() ); - edgeProperties.put("target", edge.getTarget().getName() ); - - encodedNetwork.addObjects( - KlabData.Object.newBuilder() - .putAllProperties(edgeProperties) - .build() - ); - + + edgeProperties = edge.getMetadata().entrySet().stream().collect( + Collectors.toMap(e -> e.getKey(), e -> e.getValue() != null ? e.getValue().toString() : null)); + + edgeProperties.put("source", edge.getSource().getName()); + edgeProperties.put("target", edge.getTarget().getName()); + + encodedNetwork.addObjects(KlabData.Object.newBuilder().putAllProperties(edgeProperties).build()); + } - - - KlabData.Object infomapParams = KlabData.Object.newBuilder() - .putProperties("param1", "1.1") + + KlabData.Object infomapParams = KlabData.Object.newBuilder().putProperties("param1", "1.1").build(); + + KlabData infomapMessage = KlabData.newBuilder().addObjects(encodedNetwork.build()).addObjects(infomapParams) .build(); - KlabData infomapMessage = KlabData.newBuilder() - .addObjects(encodedNetwork.build()) - .addObjects(infomapParams) - .build(); - HttpResponse response = null; - Map map = null; - + Map map = null; + File outputFile = new File("/home/dibepa/protobuf-infomap"); try { - + FileOutputStream output = new FileOutputStream(outputFile); infomapMessage.writeTo(output); output.close(); - + response = infomapSendRequest(outputFile); KlabData infomapResponse = KlabData.parseFrom(response.body()); - + KlabData.Object communities = infomapResponse.getObjects(0); - + name = communities.getName(); map = communities.getPropertiesMap(); - + } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -177,87 +169,84 @@ public List instantiate(IObservable semantics, IContextualizati // TODO Auto-generated catch block e.printStackTrace(); } - - - communityMap = new HashMap(); + + communityMap = new HashMap(); for (IDirectObservation node : network.getNetwork().vertexSet()) { String c = map.get(node.getName()); communityMap.put(node, c); } - - - if (communityMap.size()>0) { - scope.getMonitor() - .info("instantiating " + communityMap.values().stream().collect(Collectors.toSet()).size() + " communities detected in " + network.getName() + "."); + + if (communityMap.size() > 0) { + scope.getMonitor().info("instantiating " + communityMap.values().stream().collect(Collectors.toSet()).size() + + " communities detected in " + network.getName() + "."); } else { throw new KlabException("The server returned an empty result."); } - + return instantiateCommunities(semantics); } - - private List instantiateCommunities(IObservable observable){ - - int i =1 ; - + + private List instantiateCommunities(IObservable observable) { + + int i = 1; + List ret = new ArrayList<>(); - - Map> mapInversed = - communityMap.keySet() - .stream() - .collect( Collectors.groupingBy(k -> communityMap.get(k)) ); - - for (List community : mapInversed.values() ) { - - List locations = community.stream().map( obs -> obs.getScale().getSpace().getShape() ).collect(Collectors.toList()); - - Optional shape = locations.stream().reduce( (u,s) -> {return u.union(s);} ); - + + Map> mapInversed = communityMap.keySet().stream() + .collect(Collectors.groupingBy(k -> communityMap.get(k))); + + for (List community : mapInversed.values()) { + + List locations = community.stream().map(obs -> obs.getScale().getSpace().getShape()) + .collect(Collectors.toList()); + + Optional shape = locations.stream().reduce((u, s) -> { + return u.union(s); + }); + // shape.get() throws an Exception is shape is not present. - IScale scale = Scale.substituteExtent(scope.getScale(),shape.get()); + IScale scale = Scale.substituteExtent(scope.getScale(), shape.get()); ret.add(scope.newObservation(observable, observable.getName() + "_" + i, scale, null)); - + i++; } - + return ret; - + } - + private HttpRequest infomapBuildRequest(File outputFile) { HttpRequest request = null; - + try { - request = HttpRequest.newBuilder() - .uri(URI.create(infomap_url)) - .header("Content-type", "application/protobuf") - .POST(BodyPublishers.ofFile(Paths.get(outputFile.getAbsolutePath()))) - .build(); + request = HttpRequest.newBuilder().uri(URI.create(infomap_url)) + .header("Content-type", "application/protobuf") + .POST(BodyPublishers.ofFile(Paths.get(outputFile.getAbsolutePath()))).build(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } - + return request; } - + private HttpResponse infomapSendRequest(File outputFile) { HttpRequest request = infomapBuildRequest(outputFile); HttpResponse response; - try { - response = HttpClient.newHttpClient().send(request, BodyHandlers.ofInputStream()); - } catch (IOException | InterruptedException ie) { - throw new ValhallaException(ie); - } + try { + response = HttpClient.newHttpClient().send(request, BodyHandlers.ofInputStream()); + } catch (IOException | InterruptedException ie) { + throw new ValhallaException(ie); + } return response; - + } @Override public Object eval(IContextualizationScope scope, Object... additionalParameters) { - return new CommunityInstantiator(Parameters.create(additionalParameters),scope); + return new CommunityInstantiator(Parameters.create(additionalParameters), scope); } - + @Override public Type getType() { return Type.OBJECT; diff --git a/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/services/RoutingRelationshipInstantiator.java b/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/services/RoutingRelationshipInstantiator.java index 1db2901be..7d8df9421 100644 --- a/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/services/RoutingRelationshipInstantiator.java +++ b/klab.engine/src/main/java/org/integratedmodelling/klab/components/network/services/RoutingRelationshipInstantiator.java @@ -48,234 +48,235 @@ public class RoutingRelationshipInstantiator extends AbstractContextualizer implements IExpression, IInstantiator { private String sourceArtifact = null; - private String targetArtifact = null; - - private Double timeThreshold = null; - private Double distanceThreshold = null; + private String targetArtifact = null; - // Diego: Not sure what is the role of this. - Descriptor selectorDescriptor = null; + private Double timeThreshold = null; + private Double distanceThreshold = null; + // Diego: Not sure what is the role of this. + Descriptor selectorDescriptor = null; + + static enum TransportType { + Auto("auto"), Pedestrian("pedestrian"), Bicycle("bicycle"), Bus("bus"), Truck("truck"), Taxi("taxi"), + MotorScooter("motor_scooter"), Multimodal("multimodel"); + + private String type; + + TransportType(String type) { + this.type = type; + } + + final public String getType() { + return this.type; + } + } - static enum TransportType{ - Auto("auto"), - Pedestrian("pedestrian"), - Bicycle("bicycle"), - Bus("bus"), - Truck("truck"), - Taxi("taxi"), - MotorScooter("motor_scooter"), - Multimodal("multimodel"); - - private String type; - - TransportType(String type) { - this.type = type; - } - - final public String getType() { - return this.type; - } - } - - static enum Server{ - Local(true), - Remote(false); - - private boolean type; - - Server(boolean type) { - this.type = type; - } - - final public boolean getType() { - return this.type; - } - } + static enum Server { + Local(true), Remote(false); + + private boolean type; + + Server(boolean type) { + this.type = type; + } + + final public boolean getType() { + return this.type; + } + } - static enum GeometryCollapser { - Centroid("centroid"); - private String type; - GeometryCollapser(String type) { - this.type = type; - } - final public String getType() { - return this.type; - } - } + static enum GeometryCollapser { + Centroid("centroid"); + + private String type; + + GeometryCollapser(String type) { + this.type = type; + } + + final public String getType() { + return this.type; + } + } - private TransportType transportType = TransportType.Auto; - private GeometryCollapser geometryCollapser = GeometryCollapser.Centroid; - private Server server = Server.Local; - private IContextualizationScope scope; - private Valhalla valhalla; - private Graph graph; - private Map,IShape> trajectories; + private TransportType transportType = TransportType.Auto; + private GeometryCollapser geometryCollapser = GeometryCollapser.Centroid; + private Server server = Server.Local; + private IContextualizationScope scope; + private Valhalla valhalla; + private Graph graph; + private Map, IShape> trajectories; - static enum CostingOptions{ - /* Empty for the time being, it is maybe too much unneeded detail. To be developed as needed. */ - } - - public RoutingRelationshipInstantiator() {/* to instantiate as expression - do not remove (or use) */} + static enum CostingOptions { + /* + * Empty for the time being, it is maybe too much unneeded detail. To be + * developed as needed. + */ + } + public RoutingRelationshipInstantiator() { + /* to instantiate as expression - do not remove (or use) */} + public RoutingRelationshipInstantiator(IParameters parameters, IContextualizationScope scope) { this.scope = scope; - this.sourceArtifact = parameters.get("source", String.class); - this.targetArtifact = parameters.get("target", String.class); - this.timeThreshold = parameters.get("time_limit", Double.class); - this.distanceThreshold = parameters.get("distance_limit", Double.class); - - if (parameters.containsKey("transport")) { - this.transportType = TransportType.valueOf(Utils.removePrefix(parameters.get("transport", String.class))); - } - if (parameters.containsKey("collapse_geometry")) { - this.geometryCollapser = GeometryCollapser.valueOf(Utils.removePrefix(parameters.get("collapse_geometry", String.class))); - } - if (parameters.containsKey("server")) { - this.server = Server.valueOf(Utils.removePrefix(parameters.get("server", String.class))); - } - - this.valhalla = new Valhalla(); + this.sourceArtifact = parameters.get("source", String.class); + this.targetArtifact = parameters.get("target", String.class); + this.timeThreshold = parameters.get("time_limit", Double.class); + this.distanceThreshold = parameters.get("distance_limit", Double.class); + + if (parameters.containsKey("transport")) { + this.transportType = TransportType.valueOf(Utils.removePrefix(parameters.get("transport", String.class))); + } + if (parameters.containsKey("collapse_geometry")) { + this.geometryCollapser = GeometryCollapser + .valueOf(Utils.removePrefix(parameters.get("collapse_geometry", String.class))); + } + if (parameters.containsKey("server")) { + this.server = Server.valueOf(Utils.removePrefix(parameters.get("server", String.class))); + } + + this.valhalla = new Valhalla(); } /* - * This is an adapted copy of the instantiate method of the configurable relationship instantiator. - * */ + * This is an adapted copy of the instantiate method of the configurable + * relationship instantiator. + */ @Override - public List instantiate(IObservable semantics, IContextualizationScope context) throws KlabException { - - - IConcept sourceConcept = Observables.INSTANCE.getRelationshipSource(semantics.getType()); - IConcept targetConcept = Observables.INSTANCE.getRelationshipTarget(semantics.getType()); + public List instantiate(IObservable semantics, IContextualizationScope context) + throws KlabException { + + IConcept sourceConcept = Observables.INSTANCE.getRelationshipSource(semantics.getType()); + IConcept targetConcept = Observables.INSTANCE.getRelationshipTarget(semantics.getType()); + + /* + * recover artifacts according to parameterization or lack thereof. Source and + * target artifacts may be the same artifact. + */ + List sources = new ArrayList<>(); + if (sourceArtifact == null) { + sources.addAll(context.getObservations(sourceConcept)); + } else { + IArtifact src = context.getArtifact(sourceArtifact); + if (src instanceof IObservationGroup) { + for (IArtifact a : src) { + sources.add((IObservation) a); + } + } + } + + List targets = new ArrayList<>(); + if (targetArtifact == null) { + targets.addAll(context.getObservations(targetConcept)); + } else { + IArtifact src = context.getArtifact(targetArtifact); + if (src instanceof IObservationGroup) { + for (IArtifact a : src) { + targets.add((IObservation) a); + } + } + } + + // all artifacts must be non-null and objects + for (List co : new List[] { sources, targets }) { + for (Object o : co) { + if (!(o instanceof IObjectArtifact)) { + throw new IllegalArgumentException( + "klab.networks.routing: at least one source or target artifact does not exist or is not an object artifact"); + } + } + } - - /* - * recover artifacts according to parameterization or lack thereof. Source and target - * artifacts may be the same artifact. - */ - List sources = new ArrayList<>(); - if (sourceArtifact == null) { - sources.addAll(context.getObservations(sourceConcept)); - } else { - IArtifact src = context.getArtifact(sourceArtifact); - if (src instanceof IObservationGroup) { - for (IArtifact a : src) { - sources.add((IObservation) a); - } - } - } - - List targets = new ArrayList<>(); - if (targetArtifact == null) { - targets.addAll(context.getObservations(targetConcept)); - } else { - IArtifact src = context.getArtifact(targetArtifact); - if (src instanceof IObservationGroup) { - for (IArtifact a : src) { - targets.add((IObservation) a); - } - } - } - + ILanguageExpression selector = null; + Parameters parameters = new Parameters<>(); + if (selectorDescriptor != null) { + selector = selectorDescriptor.compile(); + } - // all artifacts must be non-null and objects - for (List co : new List[]{sources, targets}) { - for (Object o : co) { - if (!(o instanceof IObjectArtifact)) { - throw new IllegalArgumentException( - "klab.networks.routing: at least one source or target artifact does not exist or is not an object artifact"); - } - } - } - - ILanguageExpression selector = null; - Parameters parameters = new Parameters<>(); - if (selectorDescriptor != null) { - selector = selectorDescriptor.compile(); - } - - // TODO these are the simple methods - enable others separately - Collection allSources = CollectionUtils.joinObservations(sources); - Collection allTargets = CollectionUtils.joinObservations(targets); - + // TODO these are the simple methods - enable others separately + Collection allSources = CollectionUtils.joinObservations(sources); + Collection allTargets = CollectionUtils.joinObservations(targets); - graph = new DefaultDirectedGraph<>(SpatialEdge.class); - trajectories = new HashMap<>(); + graph = new DefaultDirectedGraph<>(SpatialEdge.class); + trajectories = new HashMap<>(); - Set connected = new HashSet<>(); + Set connected = new HashSet<>(); - int nullTrajectories = 0; - int outOfLimitTrajectories = 0; - - for (IObservation source : allSources) { - - - if (context.getMonitor().isInterrupted()) { - break; - } - - if (connected.contains(source)) { - continue; - } - - for (IArtifact target : allTargets) { - - if (context.getMonitor().isInterrupted()) { - break; - } - - // A direct connection of an instance to itself in the context of routing makes no sense and is thus avoided. - // Note that closed paths are nevertheless possible. - if (source.equals(target)) { - continue; - } - - if (!(source instanceof IDirectObservation)) { - throw new IllegalArgumentException("source observations are not direct observations"); - } - - if (!(target instanceof IDirectObservation)) { - throw new IllegalArgumentException("target observations are not direct observations"); - } - - // Diego: I don't get the purpose of this. - if (selector != null) { - - Object o = selector.eval(context, parameters, "source", source, "target", target); - - if (o == null) { - o = Boolean.FALSE; - } - if (!(o instanceof Boolean)) { - throw new KlabValidationException( - "relationship instantiator: selector expression must return true/false"); - } - - if (!(Boolean) o) { - continue; - } - } - - // Find the optimal route between target and location. - - // Handle non-0 dimension objects: collapse higher dimension geometries to their centroid. This is the easiest. - // More complex versions could involve generating N random points within the geometry, or for polygons random points - // along its border. - - String valhallaInput = Valhalla.buildValhallaJsonInput((IDirectObservation) source, (IDirectObservation) target, transportType.getType(), geometryCollapser.getType()); - ValhallaOutputDeserializer.OptimizedRoute route; - IShape trajectory; - Map stats; - Parameters routeParameters = null; + int nullTrajectories = 0; + int outOfLimitTrajectories = 0; + + for (IObservation source : allSources) { + + if (context.getMonitor().isInterrupted()) { + break; + } + + if (connected.contains(source)) { + continue; + } + + for (IArtifact target : allTargets) { + + if (context.getMonitor().isInterrupted()) { + break; + } + + // A direct connection of an instance to itself in the context of routing makes + // no sense and is thus avoided. + // Note that closed paths are nevertheless possible. + if (source.equals(target)) { + continue; + } + + if (!(source instanceof IDirectObservation)) { + throw new IllegalArgumentException("source observations are not direct observations"); + } + + if (!(target instanceof IDirectObservation)) { + throw new IllegalArgumentException("target observations are not direct observations"); + } + + // Diego: I don't get the purpose of this. + if (selector != null) { + + Object o = selector.eval(context, parameters, "source", source, "target", target); + + if (o == null) { + o = Boolean.FALSE; + } + if (!(o instanceof Boolean)) { + throw new KlabValidationException( + "relationship instantiator: selector expression must return true/false"); + } + + if (!(Boolean) o) { + continue; + } + } + + // Find the optimal route between target and location. + + // Handle non-0 dimension objects: collapse higher dimension geometries to their + // centroid. This is the easiest. + // More complex versions could involve generating N random points within the + // geometry, or for polygons random points + // along its border. + + String valhallaInput = Valhalla.buildValhallaJsonInput((IDirectObservation) source, + (IDirectObservation) target, transportType.getType(), geometryCollapser.getType()); + ValhallaOutputDeserializer.OptimizedRoute route; + IShape trajectory; + Map stats; + Parameters routeParameters = null; try { route = valhalla.optimized_route(valhallaInput); trajectory = route.getPath().transform(scope.getScale().getSpace().getProjection()); - stats = route.getSummaryStatistics(); - routeParameters = new Parameters(stats); - + stats = route.getSummaryStatistics(); + routeParameters = new Parameters(stats); + } catch (ValhallaException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -283,104 +284,105 @@ public List instantiate(IObservable semantics, IContextualizati stats = null; trajectory = null; } - + if (trajectory != null && stats != null) { - if ( - (timeThreshold == null || ((Double) stats.get("time") < timeThreshold)) && - (distanceThreshold == null || ((Double) stats.get("length") < distanceThreshold)) - - ) - { - - connect((IDirectObservation) source, (IDirectObservation) target, trajectory, routeParameters); - connected.add((IObservation) target); - trajectories.put(new Pair((IDirectObservation)source,(IDirectObservation)target),trajectory); - } - else { - outOfLimitTrajectories += 1; - } - - } - else { - - nullTrajectories += 1; - - } - - } - } + if ((timeThreshold == null || ((Double) stats.get("time") < timeThreshold)) + && (distanceThreshold == null || ((Double) stats.get("length") < distanceThreshold)) + + ) { + + connect((IDirectObservation) source, (IDirectObservation) target, trajectory, routeParameters); + connected.add((IObservation) target); + trajectories.put(new Pair((IDirectObservation) source, + (IDirectObservation) target), trajectory); + } else { + outOfLimitTrajectories += 1; + } + + } else { + + nullTrajectories += 1; + + } + + } + } - if (nullTrajectories > 0) { - - context.getMonitor() - .info("creating " + graph.edgeSet().size() + " " + Concepts.INSTANCE.getDisplayName(semantics.getType()) - + " routing relationships. \n" + nullTrajectories + " relationships could not be created because a route " - + "was not found either due to a lack of data or because travel characteristics exceed the allowed limits."); - - } else { - context.getMonitor() - .info("creating " + graph.edgeSet().size() + " " + Concepts.INSTANCE.getDisplayName(semantics.getType()) - + " routing relationships."); - } - return instantiateRelationships(semantics); + if (nullTrajectories > 0) { + + context.getMonitor().info("creating " + graph.edgeSet().size() + " " + + Concepts.INSTANCE.getDisplayName(semantics.getType()) + " routing relationships. \n" + + nullTrajectories + " relationships could not be created because a route " + + "was not found either due to a lack of data or because travel characteristics exceed the allowed limits."); + + } else { + context.getMonitor().info("creating " + graph.edgeSet().size() + " " + + Concepts.INSTANCE.getDisplayName(semantics.getType()) + " routing relationships."); + } + return instantiateRelationships(semantics); } private List instantiateRelationships(IObservable observable) { - - int i = 1; - List ret = new ArrayList<>(); - // build from graph - for (SpatialEdge edge : graph.edgeSet()) { - - IDirectObservation source = (IDirectObservation) graph.getEdgeSource(edge); - IDirectObservation target = (IDirectObservation) graph.getEdgeTarget(edge); - Parameters routeParameters = edge.getParameters(); - - IScale scale = Scale.substituteExtent(scope.getScale(), trajectories.get(new Pair((IDirectObservation)source,(IDirectObservation)target))); - - ret.add(scope.newRelationship(observable, observable.getName() + "_" + i, scale, source, target, new Metadata(routeParameters))); - - i++; - } - return ret; - } - - private void connect(IDirectObservation source, IDirectObservation target, ISpace spatialConnection, Parameters routeParameters) { - // add to graph for bookkeeping unless we don't need it - graph.addVertex(source); - graph.addVertex(target); - graph.addEdge(source, target, new SpatialEdge(null, spatialConnection == null ? null : spatialConnection.getShape(), routeParameters)); - } + int i = 1; + List ret = new ArrayList<>(); + // build from graph + for (SpatialEdge edge : graph.edgeSet()) { + + IDirectObservation source = (IDirectObservation) graph.getEdgeSource(edge); + IDirectObservation target = (IDirectObservation) graph.getEdgeTarget(edge); + Parameters routeParameters = edge.getParameters(); + + IScale scale = Scale.substituteExtent(scope.getScale(), + trajectories.get(new Pair((IDirectObservation) source, + (IDirectObservation) target))); + + ret.add(scope.newRelationship(observable, observable.getName() + "_" + i, scale, source, target, + new Metadata(routeParameters))); + + i++; + } + return ret; + } + + private void connect(IDirectObservation source, IDirectObservation target, ISpace spatialConnection, + Parameters routeParameters) { + + // add to graph for bookkeeping unless we don't need it + graph.addVertex(source); + graph.addVertex(target); + graph.addEdge(source, target, new SpatialEdge(null, + spatialConnection == null ? null : spatialConnection.getShape(), routeParameters)); + } class SpatialEdge extends DefaultEdge { - private static final long serialVersionUID = -6448417928592670704L; + private static final long serialVersionUID = -6448417928592670704L; - IShape sourceShape; - IShape targetShape; - - Parameters routeParameters; + IShape sourceShape; + IShape targetShape; - SpatialEdge() { - } + Parameters routeParameters; - SpatialEdge(IShape s, IShape t, Parameters rp) { - this.sourceShape = s; - this.targetShape = t; - this.routeParameters = rp; - } - - public Parameters getParameters(){ - return this.routeParameters; - } + SpatialEdge() { + } + + SpatialEdge(IShape s, IShape t, Parameters rp) { + this.sourceShape = s; + this.targetShape = t; + this.routeParameters = rp; + } - } + public Parameters getParameters() { + return this.routeParameters; + } + + } @Override - public Object eval(IContextualizationScope context, Object...parameters) throws KlabException { + public Object eval(IContextualizationScope context, Object... parameters) throws KlabException { return new RoutingRelationshipInstantiator(Parameters.create(parameters), context); }