From f8e00b1d268b7fb1d0fceb242d417912aaf78a53 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 25 Aug 2020 10:21:55 +0200 Subject: [PATCH 01/48] adding of contributions controller --- .../rawdata/ContributionsController.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java new file mode 100644 index 00000000..1dbfcd19 --- /dev/null +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java @@ -0,0 +1,42 @@ +package org.heigit.ohsome.ohsomeapi.controller.rawdata; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.heigit.ohsome.ohsomeapi.output.rawdataresponse.DataResponse; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * REST controller containing the methods, which are mapped to "/contributions" and used to return + * each contribution (creation, modification, deletion) of the OSM data. + */ +@Api(tags = "Contributions") +@RestController +@RequestMapping("/contributions") +public class ContributionsController { + + /** + * Gives the contributions as GeoJSON features, which have the geometry of the respective objects + * in the geometry field. + * + * @param servletRequest HttpServletRequest of the incoming request + * @param servletResponse HttpServletResponse of the outgoing response + */ + @ApiOperation( + value = "OSM contributions having the raw geometry of each OSM object as geometry", + nickname = "contribution", response = DataResponse.class) + @ApiImplicitParam(name = "time", + value = "Two ISO-8601 conform timestrings defining an interval; no default value", + defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", + required = true) + @RequestMapping(value = "/geometry", method = {RequestMethod.GET, RequestMethod.POST}, + produces = "application/json") + public void contributions(HttpServletRequest servletRequest, + HttpServletResponse servletResponse) throws Exception { + } + +} From 8e6724432b1e446702d5cc6ad39641d621547221 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Wed, 26 Aug 2020 12:46:22 +0200 Subject: [PATCH 02/48] adding further endpoints under /contributions as well as a request executor class --- .../rawdata/ContributionsController.java | 47 +++++++++++++++++++ .../ContributionsRequestExecutor.java | 14 ++++++ 2 files changed, 61 insertions(+) create mode 100644 src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java index 1dbfcd19..b6d93767 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java @@ -5,6 +5,7 @@ import io.swagger.annotations.ApiOperation; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.heigit.ohsome.ohsomeapi.executor.ContributionsRequestExecutor; import org.heigit.ohsome.ohsomeapi.output.rawdataresponse.DataResponse; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -37,6 +38,52 @@ public class ContributionsController { produces = "application/json") public void contributions(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { + ContributionsRequestExecutor.extract(ElementsGeometry.RAW, servletRequest, + servletResponse); + } + + /** + * Gives the contributions as GeoJSON features, which have the bounding box of the respective + * objects in the geometry field. + * + * @param servletRequest HttpServletRequest of the incoming request + * @param servletResponse HttpServletResponse of the outgoing response + */ + @ApiOperation( + value = "OSM contributions having the bounding box of each OSM object as geometry", + nickname = "contributionBbox", response = DataResponse.class) + @ApiImplicitParam(name = "time", + value = "Two ISO-8601 conform timestrings defining an interval; no default value", + defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", + required = true) + @RequestMapping(value = "/bbox", method = {RequestMethod.GET, RequestMethod.POST}, + produces = "application/json") + public void contributionsBbox(HttpServletRequest servletRequest, + HttpServletResponse servletResponse) throws Exception { + ContributionsRequestExecutor.extract(ElementsGeometry.BBOX, servletRequest, + servletResponse); + } + + /** + * Gives the contributions as GeoJSON features, which have the centroid of the respective objects + * in the geometry field. + * + * @param servletRequest HttpServletRequest of the incoming request + * @param servletResponse HttpServletResponse of the outgoing response + */ + @ApiOperation( + value = "OSM contributions having the centroid of each OSM object as geometry", + nickname = "contributionCentroid", response = DataResponse.class) + @ApiImplicitParam(name = "time", + value = "Two ISO-8601 conform timestrings defining an interval; no default value", + defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", + required = true) + @RequestMapping(value = "/centroid", method = {RequestMethod.GET, RequestMethod.POST}, + produces = "application/json") + public void contributionsCentroid(HttpServletRequest servletRequest, + HttpServletResponse servletResponse) throws Exception { + ContributionsRequestExecutor.extract(ElementsGeometry.CENTROID, servletRequest, + servletResponse); } } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java new file mode 100644 index 00000000..6eb0d528 --- /dev/null +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java @@ -0,0 +1,14 @@ +package org.heigit.ohsome.ohsomeapi.executor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.heigit.ohsome.ohsomeapi.controller.rawdata.ElementsGeometry; + +public class ContributionsRequestExecutor { + + public static void extract(ElementsGeometry elemGeom, HttpServletRequest servletRequest, + HttpServletResponse servletResponse) throws Exception { + + } + +} From 7a6c2c5a3e7dcd48a9df2af8814466f5fae70014 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Wed, 26 Aug 2020 15:01:03 +0200 Subject: [PATCH 03/48] refactoring of response streams combining the snapshot and contribution streams into one stream --- .../ohsomeapi/executor/ElementsRequestExecutor.java | 6 +++--- .../heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java | 9 ++------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java index be323b03..a1ccda1f 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java @@ -144,7 +144,7 @@ public static void extract(ElementsGeometry elemGeom, HttpServletRequest servlet DataResponse osmData = new DataResponse(new Attribution(URL, TEXT), Application.API_VERSION, metadata, "FeatureCollection", Collections.emptyList()); try (Stream streamResult = preResult.stream()) { - exeUtils.streamElementsResponse(servletResponse, osmData, false, streamResult, null); + exeUtils.streamElementsResponse(servletResponse, osmData, false, streamResult); } } @@ -343,8 +343,8 @@ public static void extractFullHistory(ElementsGeometry elemGeom, metadata, "FeatureCollection", Collections.emptyList()); try (Stream contributionStream = contributionPreResult.stream(); Stream snapshotStream = snapshotPreResult.stream()) { - exeUtils.streamElementsResponse(servletResponse, osmData, true, snapshotStream, - contributionStream); + exeUtils.streamElementsResponse(servletResponse, osmData, true, + Stream.concat(contributionStream, snapshotStream)); } } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java index 50b7040f..432b74ee 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java @@ -250,9 +250,7 @@ public static & Serializable, V extends Comparable snapshotStream, - Stream contributionStream) - throws ExecutionException, InterruptedException, IOException { + boolean isFullHistory, Stream resultStream) throws Exception { JsonFactory jsonFactory = new JsonFactory(); ByteArrayOutputStream tempStream = new ByteArrayOutputStream(); @@ -288,10 +286,7 @@ public void writeIndentation(JsonGenerator g, int level) throws IOException { } }); isFirst = new AtomicReference<>(true); - if (isFullHistory) { - writeStreamResponse(outputJsonGen, contributionStream, outputBuffers, outputStream); - } - writeStreamResponse(outputJsonGen, snapshotStream, outputBuffers, outputStream); + writeStreamResponse(outputJsonGen, resultStream, outputBuffers, outputStream); outputStream.print("]\n}\n"); servletResponse.flushBuffer(); } From 89d53917a646d307331abb8be37583858f474775 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Thu, 27 Aug 2020 11:19:39 +0200 Subject: [PATCH 04/48] adapting swagger nicknames of data extraction endpoints to better express the distinct endpoints --- .../ohsomeapi/controller/rawdata/ElementsController.java | 6 +++--- .../controller/rawdata/ElementsFullHistoryController.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java index 400fc226..39e9db32 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java @@ -30,7 +30,7 @@ public class ElementsController { * extract} */ @ApiOperation(value = "OSM Data having the raw geometry of each OSM object as geometry", - nickname = "geometry", response = DataResponse.class) + nickname = "elementsGeometry", response = DataResponse.class) @RequestMapping(value = "/geometry", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json") public void elementsGeometry(HttpServletRequest servletRequest, @@ -49,7 +49,7 @@ public void elementsGeometry(HttpServletRequest servletRequest, * extract} */ @ApiOperation(value = "OSM Data, having the bounding box of each OSM object as geometry", - nickname = "bbox", response = DataResponse.class) + nickname = "elementsBbox", response = DataResponse.class) @RequestMapping(value = "/bbox", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json") public void elementsBbox(HttpServletRequest servletRequest, HttpServletResponse servletResponse) @@ -68,7 +68,7 @@ public void elementsBbox(HttpServletRequest servletRequest, HttpServletResponse * extract} */ @ApiOperation(value = "OSM Data, having the centroid of each OSM object as geometry", - nickname = "centroid", response = DataResponse.class) + nickname = "elementsCentroid", response = DataResponse.class) @RequestMapping(value = "/centroid", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json") public void elementsCentroid(HttpServletRequest servletRequest, diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java index 7cc07307..9759fd88 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java @@ -33,7 +33,7 @@ public class ElementsFullHistoryController { */ @ApiOperation( value = "Full-history OSM data having the raw geometry of each OSM object as geometry", - nickname = "fullHistory", response = DataResponse.class) + nickname = "elementsFullHistory", response = DataResponse.class) @ApiImplicitParam(name = "time", value = "Two ISO-8601 conform timestrings defining an interval; no default value", defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", @@ -58,7 +58,7 @@ public void elementsFullHistory(HttpServletRequest servletRequest, */ @ApiOperation( value = "Full-history OSM data, having the bounding box of each OSM object as geometry", - nickname = "bboxFullHistory", response = DataResponse.class) + nickname = "elementsBboxFullHistory", response = DataResponse.class) @ApiImplicitParam(name = "time", value = "Two ISO-8601 conform timestrings defining an interval; no default value", defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", @@ -82,7 +82,7 @@ public void elementsBboxFullHistory(HttpServletRequest servletRequest, * extractFullHistory} */ @ApiOperation(value = "Full-history OSM data, having the centroid of each OSM object as geometry", - nickname = "centroidFullHistory", response = DataResponse.class) + nickname = "elementsCentroidFullHistory", response = DataResponse.class) @ApiImplicitParam(name = "time", value = "Two ISO-8601 conform timestrings defining an interval; no default value", defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", From 15f0ca697b1316bf3555369081113684723179ba Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Thu, 27 Aug 2020 11:23:25 +0200 Subject: [PATCH 05/48] adding of /latest endpoints --- .../rawdata/ContributionsController.java | 95 +++++++++++++++---- .../ContributionsRequestExecutor.java | 5 + 2 files changed, 83 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java index b6d93767..75227115 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java @@ -27,21 +27,19 @@ public class ContributionsController { * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response */ - @ApiOperation( - value = "OSM contributions having the raw geometry of each OSM object as geometry", - nickname = "contribution", response = DataResponse.class) + @ApiOperation(value = "OSM contributions having the raw geometry of each OSM object as geometry", + nickname = "contributionsGeometry", response = DataResponse.class) @ApiImplicitParam(name = "time", value = "Two ISO-8601 conform timestrings defining an interval; no default value", defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", required = true) @RequestMapping(value = "/geometry", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json") - public void contributions(HttpServletRequest servletRequest, - HttpServletResponse servletResponse) throws Exception { - ContributionsRequestExecutor.extract(ElementsGeometry.RAW, servletRequest, - servletResponse); + public void contributions(HttpServletRequest servletRequest, HttpServletResponse servletResponse) + throws Exception { + ContributionsRequestExecutor.extract(ElementsGeometry.RAW, servletRequest, servletResponse); } - + /** * Gives the contributions as GeoJSON features, which have the bounding box of the respective * objects in the geometry field. @@ -49,9 +47,8 @@ public void contributions(HttpServletRequest servletRequest, * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response */ - @ApiOperation( - value = "OSM contributions having the bounding box of each OSM object as geometry", - nickname = "contributionBbox", response = DataResponse.class) + @ApiOperation(value = "OSM contributions having the bounding box of each OSM object as geometry", + nickname = "contributionsBbox", response = DataResponse.class) @ApiImplicitParam(name = "time", value = "Two ISO-8601 conform timestrings defining an interval; no default value", defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", @@ -60,10 +57,9 @@ public void contributions(HttpServletRequest servletRequest, produces = "application/json") public void contributionsBbox(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ContributionsRequestExecutor.extract(ElementsGeometry.BBOX, servletRequest, - servletResponse); + ContributionsRequestExecutor.extract(ElementsGeometry.BBOX, servletRequest, servletResponse); } - + /** * Gives the contributions as GeoJSON features, which have the centroid of the respective objects * in the geometry field. @@ -71,9 +67,8 @@ public void contributionsBbox(HttpServletRequest servletRequest, * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response */ - @ApiOperation( - value = "OSM contributions having the centroid of each OSM object as geometry", - nickname = "contributionCentroid", response = DataResponse.class) + @ApiOperation(value = "OSM contributions having the centroid of each OSM object as geometry", + nickname = "contributionsCentroid", response = DataResponse.class) @ApiImplicitParam(name = "time", value = "Two ISO-8601 conform timestrings defining an interval; no default value", defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", @@ -86,4 +81,70 @@ public void contributionsCentroid(HttpServletRequest servletRequest, servletResponse); } + /** + * Gives the latest contributions as GeoJSON features, which have the geometry of the respective + * objects in the geometry field. + * + * @param servletRequest HttpServletRequest of the incoming request + * @param servletResponse HttpServletResponse of the outgoing response + */ + @ApiOperation( + value = "Latest OSM contributions having the raw geometry of each OSM object as geometry", + nickname = "contributionsLatestGeometry", response = DataResponse.class) + @ApiImplicitParam(name = "time", + value = "Two ISO-8601 conform timestrings defining an interval; no default value", + defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", + required = true) + @RequestMapping(value = "/latest/geometry", method = {RequestMethod.GET, RequestMethod.POST}, + produces = "application/json") + public void contributionsLatest(HttpServletRequest servletRequest, + HttpServletResponse servletResponse) throws Exception { + ContributionsRequestExecutor.extractLatest(ElementsGeometry.RAW, servletRequest, + servletResponse); + } + + /** + * Gives the latest contributions as GeoJSON features, which have the bounding box of the + * respective objects in the geometry field. + * + * @param servletRequest HttpServletRequest of the incoming request + * @param servletResponse HttpServletResponse of the outgoing response + */ + @ApiOperation( + value = "Latest OSM contributions having the bounding box of each OSM object as geometry", + nickname = "contributionsLatestBbox", response = DataResponse.class) + @ApiImplicitParam(name = "time", + value = "Two ISO-8601 conform timestrings defining an interval; no default value", + defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", + required = true) + @RequestMapping(value = "/latest/bbox", method = {RequestMethod.GET, RequestMethod.POST}, + produces = "application/json") + public void contributionsBboxLatest(HttpServletRequest servletRequest, + HttpServletResponse servletResponse) throws Exception { + ContributionsRequestExecutor.extractLatest(ElementsGeometry.BBOX, servletRequest, + servletResponse); + } + + /** + * Gives the latest contributions as GeoJSON features, which have the centroid of the respective + * objects in the geometry field. + * + * @param servletRequest HttpServletRequest of the incoming request + * @param servletResponse HttpServletResponse of the outgoing response + */ + @ApiOperation( + value = "Latest OSM contributions having the centroid of each OSM object as geometry", + nickname = "contributionsLatestCentroid", response = DataResponse.class) + @ApiImplicitParam(name = "time", + value = "Two ISO-8601 conform timestrings defining an interval; no default value", + defaultValue = "2016-01-01,2017-01-01", paramType = "query", dataType = "string", + required = true) + @RequestMapping(value = "/latest/centroid", method = {RequestMethod.GET, RequestMethod.POST}, + produces = "application/json") + public void contributionsCentroidLatest(HttpServletRequest servletRequest, + HttpServletResponse servletResponse) throws Exception { + ContributionsRequestExecutor.extractLatest(ElementsGeometry.CENTROID, servletRequest, + servletResponse); + } + } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java index 6eb0d528..33345ab5 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java @@ -11,4 +11,9 @@ public static void extract(ElementsGeometry elemGeom, HttpServletRequest servlet } + public static void extractLatest(ElementsGeometry elemGeom, HttpServletRequest servletRequest, + HttpServletResponse servletResponse) throws Exception { + + } + } From 325779c35e564d216e04080127ba2d7bd6c068ce Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Thu, 27 Aug 2020 11:43:32 +0200 Subject: [PATCH 06/48] javadoc fix --- .../ohsome/ohsomeapi/executor/ElementsRequestExecutor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java index a1ccda1f..ecab16ea 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java @@ -89,7 +89,7 @@ private ElementsRequestExecutor() { * {@link org.heigit.ohsome.ohsomeapi.inputprocessing.InputProcessor#processParameters() * processParameters}, * {@link org.heigit.bigspatialdata.oshdb.api.mapreducer.MapReducer#stream() stream}, or - * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, boolean, Stream, Stream) + * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, boolean, Stream) * streamElementsResponse} */ public static void extract(ElementsGeometry elemGeom, HttpServletRequest servletRequest, @@ -164,7 +164,7 @@ public static void extract(ElementsGeometry elemGeom, HttpServletRequest servlet * {@link org.heigit.bigspatialdata.oshdb.util.time.ISODateTimeParser#parseISODateTime(String) * parseISODateTime}, * {@link org.heigit.bigspatialdata.oshdb.api.mapreducer.MapReducer#stream() stream}, or - * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, boolean, Stream, Stream) + * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, boolean, Stream) * streamElementsResponse} */ public static void extractFullHistory(ElementsGeometry elemGeom, From 923de6da74ecf2df18c51c3cbd094d6b6df17b50 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Thu, 27 Aug 2020 17:46:11 +0200 Subject: [PATCH 07/48] adding of processing for /contribution/latest together with re-arranging of code for full-history processing --- .../ohsomeapi/config/SwaggerConfig.java | 12 + .../ContributionsController.java | 17 +- .../rawdata/ElementsController.java | 10 +- .../ElementsFullHistoryController.java | 15 +- .../executor/AggregateRequestExecutor.java | 4 +- .../executor/ElementsRequestExecutor.java | 237 ++---------------- .../ohsomeapi/executor/ExecutionUtils.java | 6 +- .../ohsomeapi/executor/RequestResource.java | 19 +- 8 files changed, 73 insertions(+), 247 deletions(-) rename src/main/java/org/heigit/ohsome/ohsomeapi/controller/{rawdata => contributions}/ContributionsController.java (91%) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java b/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java index 550baa46..d58daae6 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java @@ -73,6 +73,18 @@ public Docket rawDataDocket() { "Direct access to the full-history of the OSM data")) .forCodeGeneration(true).globalResponseMessage(RequestMethod.GET, responseMessages); } + + /** Creates the Swagger2 documentation for the contributions resources. */ + @Bean + public Docket contributionsDocket() { + ArrayList responseMessages = defineResponseMessages(); + return new Docket(DocumentationType.SWAGGER_2).groupName("Contributions").select() + .apis(RequestHandlerSelectors.basePackage("org.heigit.ohsome.ohsomeapi.controller.contributions")) + .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) + .globalOperationParameters(defineGlobalOperationParams(true)) + .tags(new Tag("Contributions", "Get the contributed OSM features")) + .forCodeGeneration(true).globalResponseMessage(RequestMethod.GET, responseMessages); + } /** Defines custom response messages for the used response codes. */ private ArrayList defineResponseMessages() { diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java similarity index 91% rename from src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java rename to src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java index 75227115..dc44fa97 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ContributionsController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java @@ -1,11 +1,14 @@ -package org.heigit.ohsome.ohsomeapi.controller.rawdata; +package org.heigit.ohsome.ohsomeapi.controller.contributions; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.heigit.ohsome.ohsomeapi.controller.rawdata.ElementsGeometry; import org.heigit.ohsome.ohsomeapi.executor.ContributionsRequestExecutor; +import org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor; +import org.heigit.ohsome.ohsomeapi.executor.RequestResource; import org.heigit.ohsome.ohsomeapi.output.rawdataresponse.DataResponse; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -99,8 +102,8 @@ public void contributionsCentroid(HttpServletRequest servletRequest, produces = "application/json") public void contributionsLatest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ContributionsRequestExecutor.extractLatest(ElementsGeometry.RAW, servletRequest, - servletResponse); + DataRequestExecutor.extract(RequestResource.CONTRIBUTIONSLATEST, ElementsGeometry.RAW, + servletRequest, servletResponse); } /** @@ -121,8 +124,8 @@ public void contributionsLatest(HttpServletRequest servletRequest, produces = "application/json") public void contributionsBboxLatest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ContributionsRequestExecutor.extractLatest(ElementsGeometry.BBOX, servletRequest, - servletResponse); + DataRequestExecutor.extract(RequestResource.CONTRIBUTIONSLATEST, ElementsGeometry.BBOX, + servletRequest, servletResponse); } /** @@ -143,8 +146,8 @@ public void contributionsBboxLatest(HttpServletRequest servletRequest, produces = "application/json") public void contributionsCentroidLatest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ContributionsRequestExecutor.extractLatest(ElementsGeometry.CENTROID, servletRequest, - servletResponse); + DataRequestExecutor.extract(RequestResource.CONTRIBUTIONSLATEST, ElementsGeometry.CENTROID, + servletRequest, servletResponse); } } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java index 39e9db32..de01ba20 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java @@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor; +import org.heigit.ohsome.ohsomeapi.executor.RequestResource; import org.heigit.ohsome.ohsomeapi.output.rawdataresponse.DataResponse; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -35,7 +36,8 @@ public class ElementsController { produces = "application/json") public void elementsGeometry(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ElementsRequestExecutor.extract(ElementsGeometry.RAW, servletRequest, servletResponse); + ElementsRequestExecutor.extract(RequestResource.DATAEXTRACTION, ElementsGeometry.RAW, + servletRequest, servletResponse); } /** @@ -54,7 +56,8 @@ public void elementsGeometry(HttpServletRequest servletRequest, produces = "application/json") public void elementsBbox(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ElementsRequestExecutor.extract(ElementsGeometry.BBOX, servletRequest, servletResponse); + ElementsRequestExecutor.extract(RequestResource.DATAEXTRACTION, ElementsGeometry.BBOX, + servletRequest, servletResponse); } /** @@ -73,6 +76,7 @@ public void elementsBbox(HttpServletRequest servletRequest, HttpServletResponse produces = "application/json") public void elementsCentroid(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ElementsRequestExecutor.extract(ElementsGeometry.CENTROID, servletRequest, servletResponse); + ElementsRequestExecutor.extract(RequestResource.DATAEXTRACTION, ElementsGeometry.CENTROID, + servletRequest, servletResponse); } } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java index 9759fd88..66d0cc76 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java @@ -5,7 +5,8 @@ import io.swagger.annotations.ApiOperation; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor; +import org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor; +import org.heigit.ohsome.ohsomeapi.executor.RequestResource; import org.heigit.ohsome.ohsomeapi.output.rawdataresponse.DataResponse; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -42,8 +43,8 @@ public class ElementsFullHistoryController { produces = "application/json") public void elementsFullHistory(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ElementsRequestExecutor.extractFullHistory(ElementsGeometry.RAW, servletRequest, - servletResponse); + DataRequestExecutor.extract(RequestResource.DATAEXTRACTION, ElementsGeometry.RAW, + servletRequest, servletResponse); } /** @@ -67,8 +68,8 @@ public void elementsFullHistory(HttpServletRequest servletRequest, produces = "application/json") public void elementsBboxFullHistory(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ElementsRequestExecutor.extractFullHistory(ElementsGeometry.BBOX, servletRequest, - servletResponse); + DataRequestExecutor.extract(RequestResource.DATAEXTRACTION, ElementsGeometry.BBOX, + servletRequest, servletResponse); } /** @@ -91,7 +92,7 @@ public void elementsBboxFullHistory(HttpServletRequest servletRequest, produces = "application/json") public void elementsCentroidFullHistory(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ElementsRequestExecutor.extractFullHistory(ElementsGeometry.CENTROID, servletRequest, - servletResponse); + DataRequestExecutor.extract(RequestResource.DATAEXTRACTION, ElementsGeometry.CENTROID, + servletRequest, servletResponse); } } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/AggregateRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/AggregateRequestExecutor.java index 82f50216..99c0def8 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/AggregateRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/AggregateRequestExecutor.java @@ -118,7 +118,7 @@ public Response aggregate() throws Exception { ElementsResult[] resultSet = fillElementsResult(result, requestParameters.isDensity(), df, geom); String description = Description.aggregate(requestParameters.isDensity(), - requestResource.getLabel(), requestResource.getUnit()); + requestResource.getDescription(), requestResource.getUnit()); Metadata metadata = generateMetadata(description); if ("csv".equalsIgnoreCase(requestParameters.getFormat())) { return writeCsv(createCsvTopComments(metadata), writeCsvResponse(resultSet)); @@ -159,7 +159,7 @@ public Response aggregateGroupByBoundary() throws Exception { count++; } String description = Description.aggregate(requestParameters.isDensity(), - requestResource.getLabel(), requestResource.getUnit()); + requestResource.getDescription(), requestResource.getUnit()); Metadata metadata = generateMetadata(description); if ("geojson".equalsIgnoreCase(requestParameters.getFormat())) { return GroupByResponse.of(ATTRIBUTION, Application.API_VERSION, metadata, "FeatureCollection", diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java index ecab16ea..d23ad369 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java @@ -1,7 +1,6 @@ package org.heigit.ohsome.ohsomeapi.executor; import java.text.DecimalFormat; -import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -11,7 +10,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.stream.Collectors; @@ -27,16 +25,13 @@ import org.heigit.bigspatialdata.oshdb.api.generic.function.SerializableFunction; import org.heigit.bigspatialdata.oshdb.api.mapreducer.MapAggregator; import org.heigit.bigspatialdata.oshdb.api.mapreducer.MapReducer; -import org.heigit.bigspatialdata.oshdb.api.object.OSMContribution; import org.heigit.bigspatialdata.oshdb.api.object.OSMEntitySnapshot; import org.heigit.bigspatialdata.oshdb.osm.OSMEntity; import org.heigit.bigspatialdata.oshdb.osm.OSMType; import org.heigit.bigspatialdata.oshdb.util.OSHDBTag; import org.heigit.bigspatialdata.oshdb.util.OSHDBTimestamp; -import org.heigit.bigspatialdata.oshdb.util.celliterator.ContributionType; import org.heigit.bigspatialdata.oshdb.util.geometry.Geo; import org.heigit.bigspatialdata.oshdb.util.tagtranslator.TagTranslator; -import org.heigit.bigspatialdata.oshdb.util.time.ISODateTimeParser; import org.heigit.bigspatialdata.oshdb.util.time.TimestampFormatter; import org.heigit.ohsome.filter.FilterExpression; import org.heigit.ohsome.filter.FilterParser; @@ -92,8 +87,8 @@ private ElementsRequestExecutor() { * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, boolean, Stream) * streamElementsResponse} */ - public static void extract(ElementsGeometry elemGeom, HttpServletRequest servletRequest, - HttpServletResponse servletResponse) throws Exception { + public static void extract(RequestResource requestResource, ElementsGeometry elemGeom, + HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { InputProcessor inputProcessor = new InputProcessor(servletRequest, true, false); MapReducer mapRed = null; inputProcessor.processPropertiesParam(); @@ -138,213 +133,13 @@ public static void extract(ElementsGeometry elemGeom, HttpServletRequest servlet }).filter(Objects::nonNull); Metadata metadata = null; if (processingData.isShowMetadata()) { - metadata = new Metadata(null, "OSM data as GeoJSON features.", + metadata = new Metadata(null, requestResource.getDescription(), inputProcessor.getRequestUrlIfGetRequest(servletRequest)); } DataResponse osmData = new DataResponse(new Attribution(URL, TEXT), Application.API_VERSION, metadata, "FeatureCollection", Collections.emptyList()); try (Stream streamResult = preResult.stream()) { - exeUtils.streamElementsResponse(servletResponse, osmData, false, streamResult); - } - } - - /** - * Performs an OSM data extraction using the full-history of the data. - * - * @param elemGeom {@link org.heigit.ohsome.ohsomeapi.controller.rawdata.ElementsGeometry - * ElementsGeometry} defining the geometry of the OSM elements - * @param servletRequest {@link javax.servlet.http.HttpServletRequest HttpServletRequest} incoming - * request object - * @param servletResponse {@link javax.servlet.http.HttpServletResponse HttpServletResponse]} - * outgoing response object - * @throws BadRequestException if the given time parameter is invalid - * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.inputprocessing.InputProcessor#processParameters() - * processParameters}, - * {@link org.heigit.bigspatialdata.oshdb.util.time.ISODateTimeParser#parseISODateTime(String) - * parseISODateTime}, - * {@link org.heigit.bigspatialdata.oshdb.api.mapreducer.MapReducer#stream() stream}, or - * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, boolean, Stream) - * streamElementsResponse} - */ - public static void extractFullHistory(ElementsGeometry elemGeom, - HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - InputProcessor inputProcessor = new InputProcessor(servletRequest, false, false); - inputProcessor.getProcessingData().setIsFullHistory(true); - InputProcessor snapshotInputProcessor = new InputProcessor(servletRequest, true, false); - snapshotInputProcessor.getProcessingData().setIsFullHistory(true); - MapReducer mapRedSnapshot = null; - MapReducer mapRedContribution = null; - if (DbConnData.db instanceof OSHDBIgnite) { - // on ignite: Use AffinityCall backend, which is the only one properly supporting streaming - // of result data, without buffering the whole result in memory before returning the result. - // This allows to write data out to the client via a chunked HTTP response. - mapRedSnapshot = snapshotInputProcessor.processParameters(ComputeMode.AffinityCall); - mapRedContribution = inputProcessor.processParameters(ComputeMode.AffinityCall); - } else { - mapRedSnapshot = snapshotInputProcessor.processParameters(); - mapRedContribution = inputProcessor.processParameters(); - } - ProcessingData processingData = inputProcessor.getProcessingData(); - RequestParameters requestParameters = processingData.getRequestParameters(); - String[] time = inputProcessor.splitParamOnComma( - inputProcessor.createEmptyArrayIfNull(servletRequest.getParameterValues("time"))); - if (time.length != 2) { - throw new BadRequestException(ExceptionMessages.TIME_FORMAT_FULL_HISTORY); - } - TagTranslator tt = DbConnData.tagTranslator; - String[] keys = requestParameters.getKeys(); - int[] keysInt = new int[keys.length]; - if (keys.length != 0) { - for (int i = 0; i < keys.length; i++) { - keysInt[i] = tt.getOSHDBTagKeyOf(keys[i]).toInt(); - } - } - MapReducer contributionPreResult = null; - ExecutionUtils exeUtils = new ExecutionUtils(processingData); - inputProcessor.processPropertiesParam(); - inputProcessor.processIsUnclippedParam(); - InputProcessingUtils utils = inputProcessor.getUtils(); - final boolean includeTags = inputProcessor.includeTags(); - final boolean includeOSMMetadata = inputProcessor.includeOSMMetadata(); - final boolean clipGeometries = inputProcessor.isClipGeometry(); - final Set simpleFeatureTypes = processingData.getSimpleFeatureTypes(); - Optional filter = processingData.getFilterExpression(); - final boolean requiresGeometryTypeCheck = - filter.isPresent() && ProcessingData.filterContainsGeometryTypeCheck(filter.get()); - FilterExpression filterExpression = processingData.getFilterExpression().orElse(null); - String startTimestamp = ISODateTimeParser.parseISODateTime(requestParameters.getTime()[0]) - .format(DateTimeFormatter.ISO_DATE_TIME); - String endTimestamp = ISODateTimeParser.parseISODateTime(requestParameters.getTime()[1]) - .format(DateTimeFormatter.ISO_DATE_TIME); - MapReducer> mapRedContributions = mapRedContribution.groupByEntity(); - contributionPreResult = mapRedContributions.flatMap(contributions -> { - List output = new LinkedList<>(); - Map properties; - Geometry currentGeom = null; - OSMEntity currentEntity = null; - String validFrom = null; - String validTo; - boolean skipNext = false; - // first contribution: - if (contributions.get(0).is(ContributionType.CREATION)) { - // if creation: skip next output - skipNext = true; - } else { - // if not "creation": take "before" as starting "row" (geom, tags), valid_from = t_start - currentEntity = contributions.get(0).getEntityBefore(); - currentGeom = exeUtils.getGeometry(contributions.get(0), clipGeometries, true); - validFrom = startTimestamp; - } - // then for each contribution: - for (OSMContribution contribution : contributions) { - // set valid_to of previous row, add to output list (output.add(…)) - validTo = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); - if (!skipNext) { - properties = new TreeMap<>(); - // deactivating the adding of the contrib type as it could deliver false results - // properties = exeUtils.addContribType(contribution, properties, includeOSMMetadata); - properties.put("@validFrom", validFrom); - properties.put("@validTo", validTo); - if (!currentGeom.isEmpty()) { - boolean addToOutput; - if (processingData.containsSimpleFeatureTypes()) { - addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); - } else if (requiresGeometryTypeCheck) { - addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); - } else { - addToOutput = true; - } - if (addToOutput) { - output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, - includeTags, includeOSMMetadata, elemGeom)); - } - } - } - skipNext = false; - if (contribution.is(ContributionType.DELETION)) { - // if deletion: skip output of next row - skipNext = true; - } else { - // else: take "after" as next row - currentEntity = contribution.getEntityAfter(); - currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); - validFrom = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); - } - } - // after loop: - OSMContribution lastContribution = contributions.get(contributions.size() - 1); - if (!lastContribution.is(ContributionType.DELETION)) { - // if last contribution was not "deletion": set valid_to = t_end, add row to output list - validTo = endTimestamp; - properties = new TreeMap<>(); - // deactivating the adding of the contrib type as it could deliver false results - // properties = exeUtils.addContribType(lastContribution, properties, includeOSMMetadata); - properties.put("@validFrom", validFrom); - properties.put("@validTo", validTo); - if (!currentGeom.isEmpty()) { - boolean addToOutput; - if (processingData.containsSimpleFeatureTypes()) { - addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); - } else if (requiresGeometryTypeCheck) { - addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); - } else { - addToOutput = true; - } - if (addToOutput) { - output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, - includeTags, includeOSMMetadata, elemGeom)); - } - } - } - return output; - }).filter(Objects::nonNull); - MapReducer snapshotPreResult = null; - // handles cases where valid_from = t_start, valid_to = t_end - snapshotPreResult = mapRedSnapshot.groupByEntity().filter(snapshots -> snapshots.size() == 2) - .filter(snapshots -> snapshots.get(0).getGeometry() == snapshots.get(1).getGeometry() - && snapshots.get(0).getEntity().getVersion() == snapshots.get(1).getEntity() - .getVersion()) - .map(snapshots -> snapshots.get(0)).flatMap(snapshot -> { - Map properties = new TreeMap<>(); - OSMEntity entity = snapshot.getEntity(); - if (includeOSMMetadata) { - properties.put("@lastEdit", entity.getTimestamp().toString()); - } - Geometry geom = snapshot.getGeometry(); - if (!clipGeometries) { - geom = snapshot.getGeometryUnclipped(); - } - properties.put("@snapshotTimestamp", - TimestampFormatter.getInstance().isoDateTime(snapshot.getTimestamp())); - properties.put("@validFrom", startTimestamp); - properties.put("@validTo", endTimestamp); - boolean addToOutput; - if (processingData.containsSimpleFeatureTypes()) { - addToOutput = utils.checkGeometryOnSimpleFeatures(geom, simpleFeatureTypes); - } else if (requiresGeometryTypeCheck) { - addToOutput = filterExpression.applyOSMGeometry(entity, geom); - } else { - addToOutput = true; - } - if (addToOutput) { - return Collections.singletonList(exeUtils.createOSMFeature(entity, geom, properties, - keysInt, includeTags, includeOSMMetadata, elemGeom)); - } else { - return Collections.emptyList(); - } - }).filter(Objects::nonNull); - Metadata metadata = null; - if (processingData.isShowMetadata()) { - metadata = new Metadata(null, "Full-history OSM data as GeoJSON features.", - inputProcessor.getRequestUrlIfGetRequest(servletRequest)); - } - DataResponse osmData = new DataResponse(new Attribution(URL, TEXT), Application.API_VERSION, - metadata, "FeatureCollection", Collections.emptyList()); - try (Stream contributionStream = contributionPreResult.stream(); - Stream snapshotStream = snapshotPreResult.stream()) { - exeUtils.streamElementsResponse(servletResponse, osmData, true, - Stream.concat(contributionStream, snapshotStream)); + exeUtils.streamElementsResponse(servletResponse, osmData, streamResult); } } @@ -439,7 +234,7 @@ public static

Response aggregateGroupByBoundary long duration = System.currentTimeMillis() - startTime; metadata = new Metadata(duration, Description.aggregateGroupByBoundaryGroupByTag(requestParameters.isDensity(), - requestResource.getLabel(), requestResource.getUnit()), + requestResource.getDescription(), requestResource.getUnit()), inputProcessor.getRequestUrlIfGetRequest(servletRequest)); } if ("csv".equalsIgnoreCase(requestParameters.getFormat())) { @@ -527,9 +322,9 @@ public static Response aggregateGroupByTag(RequestResource requestResource, Metadata metadata = null; if (processingData.isShowMetadata()) { long duration = System.currentTimeMillis() - startTime; - metadata = new Metadata( - duration, Description.aggregateGroupByTag(requestParameters.isDensity(), - requestResource.getLabel(), requestResource.getUnit()), + metadata = new Metadata(duration, + Description.aggregateGroupByTag(requestParameters.isDensity(), + requestResource.getDescription(), requestResource.getUnit()), inputProcessor.getRequestUrlIfGetRequest(servletRequest)); } if ("csv".equalsIgnoreCase(requestParameters.getFormat())) { @@ -590,7 +385,7 @@ public static Response aggregateGroupByType(RequestResource requestResource, long duration = System.currentTimeMillis() - startTime; metadata = new Metadata(duration, Description.countPerimeterAreaGroupByType(requestParameters.isDensity(), - requestResource.getLabel(), requestResource.getUnit()), + requestResource.getDescription(), requestResource.getUnit()), inputProcessor.getRequestUrlIfGetRequest(servletRequest)); } if ("csv".equalsIgnoreCase(requestParameters.getFormat())) { @@ -680,9 +475,11 @@ public static Response aggregateGroupByKey(RequestResource requestResource, Metadata metadata = null; if (processingData.isShowMetadata()) { long duration = System.currentTimeMillis() - startTime; - metadata = new Metadata(duration, - Description.aggregateGroupByKey(requestResource.getLabel(), requestResource.getUnit()), - inputProcessor.getRequestUrlIfGetRequest(servletRequest)); + metadata = + new Metadata(duration, + Description.aggregateGroupByKey(requestResource.getDescription(), + requestResource.getUnit()), + inputProcessor.getRequestUrlIfGetRequest(servletRequest)); } if ("csv".equalsIgnoreCase(requestParameters.getFormat())) { exeUtils.writeCsvResponse(resultSet, servletResponse, @@ -696,8 +493,11 @@ public static Response aggregateGroupByKey(RequestResource requestResource, /** * Performs a count|length|perimeter|area|ratio calculation. * + * <<<<<<< HEAD + * * @deprecated Will be removed in next major version update. * + * ======= >>>>>>> adding of processing for /contribution/latest * @param requestResource {@link org.heigit.ohsome.ohsomeapi.executor.RequestResource * RequestResource} definition of the request resource * @param servletRequest {@link javax.servlet.http.HttpServletRequest HttpServletRequest} incoming @@ -946,8 +746,11 @@ public static Response aggregateRatio(RequestResource requestResource, /** * Performs a count|length|perimeter|area-ratio calculation grouped by the boundary. * + * <<<<<<< HEAD + * * @deprecated Will be removed in next major version update. * + * ======= >>>>>>> adding of processing for /contribution/latest * @param requestResource {@link org.heigit.ohsome.ohsomeapi.executor.RequestResource * RequestResource} definition of the request resource * @param servletRequest {@link javax.servlet.http.HttpServletRequest HttpServletRequest} incoming diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java index 432b74ee..3060df49 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java @@ -250,7 +250,7 @@ public static & Serializable, V extends Comparable resultStream) throws Exception { + Stream resultStream) throws Exception { JsonFactory jsonFactory = new JsonFactory(); ByteArrayOutputStream tempStream = new ByteArrayOutputStream(); @@ -643,7 +643,7 @@ public Response createRatioResponse(String[] timeArray, Double[] value1, Double[ if (processingData.isShowMetadata()) { long duration = System.currentTimeMillis() - startTime; metadata = new Metadata(duration, - Description.aggregateRatio(reqRes.getLabel(), reqRes.getUnit()), requestUrl); + Description.aggregateRatio(reqRes.getDescription(), reqRes.getUnit()), requestUrl); } RequestParameters requestParameters = processingData.getRequestParameters(); if ("csv".equalsIgnoreCase(requestParameters.getFormat())) { @@ -685,7 +685,7 @@ public Response createRatioGroupByBoundaryResponse(Object[] boundaryIds, String[ if (processingData.isShowMetadata()) { long duration = System.currentTimeMillis() - startTime; metadata = new Metadata(duration, - Description.aggregateRatioGroupByBoundary(reqRes.getLabel(), reqRes.getUnit()), + Description.aggregateRatioGroupByBoundary(reqRes.getDescription(), reqRes.getUnit()), requestUrl); } RequestParameters requestParameters = processingData.getRequestParameters(); diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/RequestResource.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/RequestResource.java index cf6d1526..18df27b2 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/RequestResource.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/RequestResource.java @@ -2,23 +2,26 @@ /** * Enumeration defining the request resource (LENGTH, PERIMETER, AREA, COUNT, GROUPBYTAG, - * GROUPBYKEY, RATIO, DATAEXTRACTION). + * GROUPBYKEY, RATIO, DATAEXTRACTION, CONTRIBUTION). */ public enum RequestResource { LENGTH("length", "meters"), PERIMETER("perimeter", "meters"), AREA("area", - "square meters"), COUNT("count", "absolute values"), GROUPBYTAG("", - ""), GROUPBYKEY("", ""), RATIO("", ""), DATAEXTRACTION("", ""); + "square meters"), COUNT("count", "absolute values"), GROUPBYTAG("", ""), GROUPBYKEY("", + ""), RATIO("", ""), DATAEXTRACTION("OSM data as GeoJSON features.", + ""), DATAEXTRACTIONFFULLHISTORY("Full-history OSM data as GeoJSON features.", + ""), CONTRIBUTIONS("Contributions as GeoJSON features.", + ""), CONTRIBUTIONSLATEST("Latest contributions as GeoJSON features.", ""); - private final String label; + private final String description; private final String unit; - RequestResource(String label, String unit) { - this.label = label; + RequestResource(String description, String unit) { + this.description = description; this.unit = unit; } - public String getLabel() { - return label; + public String getDescription() { + return description; } public String getUnit() { From b07248c06c9afb41c87d3247c227573fe11df78c Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Thu, 27 Aug 2020 17:51:55 +0200 Subject: [PATCH 08/48] javadoc fix --- .../ohsome/ohsomeapi/executor/ElementsRequestExecutor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java index d23ad369..6e5f90ed 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java @@ -84,7 +84,7 @@ private ElementsRequestExecutor() { * {@link org.heigit.ohsome.ohsomeapi.inputprocessing.InputProcessor#processParameters() * processParameters}, * {@link org.heigit.bigspatialdata.oshdb.api.mapreducer.MapReducer#stream() stream}, or - * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, boolean, Stream) + * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, Stream) * streamElementsResponse} */ public static void extract(RequestResource requestResource, ElementsGeometry elemGeom, From 43acc245793842dc24535b49ddc35aa15c16bd5f Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Thu, 27 Aug 2020 17:55:16 +0200 Subject: [PATCH 09/48] adding of new request executor class --- .../executor/DataRequestExecutor.java | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java new file mode 100644 index 00000000..c4291a54 --- /dev/null +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -0,0 +1,251 @@ +package org.heigit.ohsome.ohsomeapi.executor; + +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Stream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.heigit.bigspatialdata.oshdb.api.db.OSHDBIgnite; +import org.heigit.bigspatialdata.oshdb.api.db.OSHDBIgnite.ComputeMode; +import org.heigit.bigspatialdata.oshdb.api.mapreducer.MapReducer; +import org.heigit.bigspatialdata.oshdb.api.object.OSMContribution; +import org.heigit.bigspatialdata.oshdb.api.object.OSMEntitySnapshot; +import org.heigit.bigspatialdata.oshdb.osm.OSMEntity; +import org.heigit.bigspatialdata.oshdb.util.celliterator.ContributionType; +import org.heigit.bigspatialdata.oshdb.util.tagtranslator.TagTranslator; +import org.heigit.bigspatialdata.oshdb.util.time.ISODateTimeParser; +import org.heigit.bigspatialdata.oshdb.util.time.TimestampFormatter; +import org.heigit.ohsome.filter.FilterExpression; +import org.heigit.ohsome.ohsomeapi.Application; +import org.heigit.ohsome.ohsomeapi.controller.rawdata.ElementsGeometry; +import org.heigit.ohsome.ohsomeapi.exception.BadRequestException; +import org.heigit.ohsome.ohsomeapi.exception.ExceptionMessages; +import org.heigit.ohsome.ohsomeapi.inputprocessing.InputProcessingUtils; +import org.heigit.ohsome.ohsomeapi.inputprocessing.InputProcessor; +import org.heigit.ohsome.ohsomeapi.inputprocessing.ProcessingData; +import org.heigit.ohsome.ohsomeapi.inputprocessing.SimpleFeatureType; +import org.heigit.ohsome.ohsomeapi.oshdb.DbConnData; +import org.heigit.ohsome.ohsomeapi.output.dataaggregationresponse.Attribution; +import org.heigit.ohsome.ohsomeapi.output.dataaggregationresponse.Metadata; +import org.heigit.ohsome.ohsomeapi.output.rawdataresponse.DataResponse; +import org.locationtech.jts.geom.Geometry; +import org.wololo.geojson.Feature; + +/** Holds executor methods for the following endpoints: /elementsFullHistory, /contributions. */ +public class DataRequestExecutor { + + /** + * Performs an OSM data extraction using the full-history of the data. + * + * @param elemGeom {@link org.heigit.ohsome.ohsomeapi.controller.rawdata.ElementsGeometry + * ElementsGeometry} defining the geometry of the OSM elements + * @param servletRequest {@link javax.servlet.http.HttpServletRequest HttpServletRequest} incoming + * request object + * @param servletResponse {@link javax.servlet.http.HttpServletResponse HttpServletResponse]} + * outgoing response object + * @throws Exception thrown by + * {@link org.heigit.ohsome.ohsomeapi.inputprocessing.InputProcessor#processParameters() + * processParameters}, + * {@link org.heigit.bigspatialdata.oshdb.util.time.ISODateTimeParser#parseISODateTime(String) + * parseISODateTime}, + * {@link org.heigit.bigspatialdata.oshdb.api.mapreducer.MapReducer#stream() stream}, or + * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, Stream) + * streamElementsResponse} + */ + public static void extract(RequestResource requestResource, ElementsGeometry elemGeom, + HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { + InputProcessor inputProcessor = new InputProcessor(servletRequest, false, false); + inputProcessor.getProcessingData().setIsFullHistory(true); + InputProcessor snapshotInputProcessor = new InputProcessor(servletRequest, true, false); + snapshotInputProcessor.getProcessingData().setIsFullHistory(true); + MapReducer mapRedSnapshot = null; + MapReducer mapRedContribution = null; + if (DbConnData.db instanceof OSHDBIgnite) { + // on ignite: Use AffinityCall backend, which is the only one properly supporting streaming + // of result data, without buffering the whole result in memory before returning the result. + // This allows to write data out to the client via a chunked HTTP response. + mapRedSnapshot = snapshotInputProcessor.processParameters(ComputeMode.AffinityCall); + mapRedContribution = inputProcessor.processParameters(ComputeMode.AffinityCall); + } else { + mapRedSnapshot = snapshotInputProcessor.processParameters(); + mapRedContribution = inputProcessor.processParameters(); + } + ProcessingData processingData = inputProcessor.getProcessingData(); + RequestParameters requestParameters = processingData.getRequestParameters(); + String[] time = inputProcessor.splitParamOnComma( + inputProcessor.createEmptyArrayIfNull(servletRequest.getParameterValues("time"))); + if (time.length != 2) { + throw new BadRequestException(ExceptionMessages.TIME_FORMAT_FULL_HISTORY); + } + TagTranslator tt = DbConnData.tagTranslator; + String[] keys = requestParameters.getKeys(); + int[] keysInt = new int[keys.length]; + if (keys.length != 0) { + for (int i = 0; i < keys.length; i++) { + keysInt[i] = tt.getOSHDBTagKeyOf(keys[i]).toInt(); + } + } + MapReducer contributionPreResult = null; + ExecutionUtils exeUtils = new ExecutionUtils(processingData); + inputProcessor.processPropertiesParam(); + inputProcessor.processIsUnclippedParam(); + InputProcessingUtils utils = inputProcessor.getUtils(); + final boolean includeTags = inputProcessor.includeTags(); + final boolean includeOSMMetadata = inputProcessor.includeOSMMetadata(); + final boolean clipGeometries = inputProcessor.isClipGeometry(); + final boolean modificationsOnly = + (requestResource.equals(RequestResource.CONTRIBUTIONSLATEST)) ? true : false; + final Set simpleFeatureTypes = processingData.getSimpleFeatureTypes(); + Optional filter = processingData.getFilterExpression(); + final boolean requiresGeometryTypeCheck = + filter.isPresent() && ProcessingData.filterContainsGeometryTypeCheck(filter.get()); + FilterExpression filterExpression = processingData.getFilterExpression().orElse(null); + String startTimestamp = ISODateTimeParser.parseISODateTime(requestParameters.getTime()[0]) + .format(DateTimeFormatter.ISO_DATE_TIME); + String endTimestamp = ISODateTimeParser.parseISODateTime(requestParameters.getTime()[1]) + .format(DateTimeFormatter.ISO_DATE_TIME); + MapReducer> mapRedContributions = mapRedContribution.groupByEntity(); + contributionPreResult = mapRedContributions.flatMap(contributions -> { + List output = new LinkedList<>(); + Map properties; + Geometry currentGeom = null; + OSMEntity currentEntity = null; + String validFrom = null; + String validTo; + boolean skipNext = false; + // first contribution: + if (contributions.get(0).is(ContributionType.CREATION)) { + // if creation: skip next output + skipNext = true; + } else { + // if not "creation": take "before" as starting "row" (geom, tags), valid_from = t_start + currentEntity = contributions.get(0).getEntityBefore(); + currentGeom = exeUtils.getGeometry(contributions.get(0), clipGeometries, true); + validFrom = startTimestamp; + } + // then for each contribution: + for (OSMContribution contribution : contributions) { + // set valid_to of previous row, add to output list (output.add(…)) + validTo = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); + if (!skipNext) { + properties = new TreeMap<>(); + // deactivating the adding of the contrib type as it could deliver false results + // properties = exeUtils.addContribType(contribution, properties, includeOSMMetadata); + properties.put("@validFrom", validFrom); + properties.put("@validTo", validTo); + if (!currentGeom.isEmpty()) { + boolean addToOutput; + if (processingData.containsSimpleFeatureTypes()) { + addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); + } else if (requiresGeometryTypeCheck) { + addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); + } else { + addToOutput = true; + } + if (addToOutput) { + output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, + includeTags, includeOSMMetadata, elemGeom)); + } + } + } + skipNext = false; + if (contribution.is(ContributionType.DELETION)) { + // if deletion: skip output of next row + skipNext = true; + } else { + // else: take "after" as next row + currentEntity = contribution.getEntityAfter(); + currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); + validFrom = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); + } + } + // after loop: + OSMContribution lastContribution = contributions.get(contributions.size() - 1); + if (!lastContribution.is(ContributionType.DELETION)) { + // if last contribution was not "deletion": set valid_to = t_end, add row to output list + validTo = endTimestamp; + properties = new TreeMap<>(); + // deactivating the adding of the contrib type as it could deliver false results + // properties = exeUtils.addContribType(lastContribution, properties, includeOSMMetadata); + properties.put("@validFrom", validFrom); + properties.put("@validTo", validTo); + if (!currentGeom.isEmpty()) { + boolean addToOutput; + if (processingData.containsSimpleFeatureTypes()) { + addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); + } else if (requiresGeometryTypeCheck) { + addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); + } else { + addToOutput = true; + } + if (addToOutput) { + output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, + includeTags, includeOSMMetadata, elemGeom)); + } + } + } + return output; + }).filter(Objects::nonNull); + Metadata metadata = null; + if (processingData.isShowMetadata()) { + metadata = new Metadata(null, requestResource.getDescription(), + inputProcessor.getRequestUrlIfGetRequest(servletRequest)); + } + DataResponse osmData = + new DataResponse(new Attribution(ElementsRequestExecutor.URL, ElementsRequestExecutor.TEXT), + Application.API_VERSION, metadata, "FeatureCollection", Collections.emptyList()); + MapReducer snapshotPreResult = null; + if (!modificationsOnly) { + // handles cases where valid_from = t_start, valid_to = t_end; i.e. non-modified data + snapshotPreResult = mapRedSnapshot.groupByEntity().filter(snapshots -> snapshots.size() == 2) + .filter(snapshots -> snapshots.get(0).getGeometry() == snapshots.get(1).getGeometry() + && snapshots.get(0).getEntity().getVersion() == snapshots.get(1).getEntity() + .getVersion()) + .map(snapshots -> snapshots.get(0)).flatMap(snapshot -> { + Map properties = new TreeMap<>(); + OSMEntity entity = snapshot.getEntity(); + if (includeOSMMetadata) { + properties.put("@lastEdit", entity.getTimestamp().toString()); + } + Geometry geom = snapshot.getGeometry(); + if (!clipGeometries) { + geom = snapshot.getGeometryUnclipped(); + } + properties.put("@snapshotTimestamp", + TimestampFormatter.getInstance().isoDateTime(snapshot.getTimestamp())); + properties.put("@validFrom", startTimestamp); + properties.put("@validTo", endTimestamp); + boolean addToOutput; + if (processingData.containsSimpleFeatureTypes()) { + addToOutput = utils.checkGeometryOnSimpleFeatures(geom, simpleFeatureTypes); + } else if (requiresGeometryTypeCheck) { + addToOutput = filterExpression.applyOSMGeometry(entity, geom); + } else { + addToOutput = true; + } + if (addToOutput) { + return Collections.singletonList(exeUtils.createOSMFeature(entity, geom, properties, + keysInt, includeTags, includeOSMMetadata, elemGeom)); + } else { + return Collections.emptyList(); + } + }).filter(Objects::nonNull); + } + try ( + Stream snapshotStream = + (snapshotPreResult != null) ? snapshotPreResult.stream() : Stream.empty(); + Stream contributionStream = contributionPreResult.stream()) { + exeUtils.streamElementsResponse(servletResponse, osmData, + Stream.concat(contributionStream, snapshotStream)); + } + } + + +} From b5bed7631281f0d25fcd1a64f020b4fc3ea10a76 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Fri, 28 Aug 2020 15:19:57 +0200 Subject: [PATCH 10/48] variable naming changes and removing of unused class as DataRequestExecutor.java will hold the relevant execution code --- .../ContributionsController.java | 7 +++---- .../ContributionsRequestExecutor.java | 19 ------------------- .../executor/DataRequestExecutor.java | 7 ++++--- 3 files changed, 7 insertions(+), 26 deletions(-) delete mode 100644 src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java index dc44fa97..c3219b39 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java @@ -6,7 +6,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.heigit.ohsome.ohsomeapi.controller.rawdata.ElementsGeometry; -import org.heigit.ohsome.ohsomeapi.executor.ContributionsRequestExecutor; import org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor; import org.heigit.ohsome.ohsomeapi.executor.RequestResource; import org.heigit.ohsome.ohsomeapi.output.rawdataresponse.DataResponse; @@ -40,7 +39,7 @@ public class ContributionsController { produces = "application/json") public void contributions(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ContributionsRequestExecutor.extract(ElementsGeometry.RAW, servletRequest, servletResponse); + DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.RAW, servletRequest, servletResponse); } /** @@ -60,7 +59,7 @@ public void contributions(HttpServletRequest servletRequest, HttpServletResponse produces = "application/json") public void contributionsBbox(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ContributionsRequestExecutor.extract(ElementsGeometry.BBOX, servletRequest, servletResponse); + DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.BBOX, servletRequest, servletResponse); } /** @@ -80,7 +79,7 @@ public void contributionsBbox(HttpServletRequest servletRequest, produces = "application/json") public void contributionsCentroid(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - ContributionsRequestExecutor.extract(ElementsGeometry.CENTROID, servletRequest, + DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.CENTROID, servletRequest, servletResponse); } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java deleted file mode 100644 index 33345ab5..00000000 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsRequestExecutor.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.heigit.ohsome.ohsomeapi.executor; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.heigit.ohsome.ohsomeapi.controller.rawdata.ElementsGeometry; - -public class ContributionsRequestExecutor { - - public static void extract(ElementsGeometry elemGeom, HttpServletRequest servletRequest, - HttpServletResponse servletResponse) throws Exception { - - } - - public static void extractLatest(ElementsGeometry elemGeom, HttpServletRequest servletRequest, - HttpServletResponse servletResponse) throws Exception { - - } - -} diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index c4291a54..26b1539c 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -100,8 +100,9 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele final boolean includeTags = inputProcessor.includeTags(); final boolean includeOSMMetadata = inputProcessor.includeOSMMetadata(); final boolean clipGeometries = inputProcessor.isClipGeometry(); - final boolean modificationsOnly = - (requestResource.equals(RequestResource.CONTRIBUTIONSLATEST)) ? true : false; + final boolean isContributionsEndpoint = + (requestResource.equals(RequestResource.CONTRIBUTIONSLATEST) || + requestResource.equals(RequestResource.CONTRIBUTIONS)) ? true : false; final Set simpleFeatureTypes = processingData.getSimpleFeatureTypes(); Optional filter = processingData.getFilterExpression(); final boolean requiresGeometryTypeCheck = @@ -202,7 +203,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele new DataResponse(new Attribution(ElementsRequestExecutor.URL, ElementsRequestExecutor.TEXT), Application.API_VERSION, metadata, "FeatureCollection", Collections.emptyList()); MapReducer snapshotPreResult = null; - if (!modificationsOnly) { + if (!isContributionsEndpoint) { // handles cases where valid_from = t_start, valid_to = t_end; i.e. non-modified data snapshotPreResult = mapRedSnapshot.groupByEntity().filter(snapshots -> snapshots.size() == 2) .filter(snapshots -> snapshots.get(0).getGeometry() == snapshots.get(1).getGeometry() From 5d8367128203a3222063c7459673551a70dd8184 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Mon, 31 Aug 2020 18:00:48 +0200 Subject: [PATCH 11/48] adding output for different contribution types consisting of features together with their properties --- .../executor/DataRequestExecutor.java | 121 +++++++++++------- .../executor/ElementsRequestExecutor.java | 2 +- .../ohsomeapi/executor/ExecutionUtils.java | 39 +++++- 3 files changed, 107 insertions(+), 55 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index 26b1539c..26c63497 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -100,9 +100,12 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele final boolean includeTags = inputProcessor.includeTags(); final boolean includeOSMMetadata = inputProcessor.includeOSMMetadata(); final boolean clipGeometries = inputProcessor.isClipGeometry(); + final boolean isContributionsLatestEndpoint = + requestResource.equals(RequestResource.CONTRIBUTIONSLATEST); final boolean isContributionsEndpoint = - (requestResource.equals(RequestResource.CONTRIBUTIONSLATEST) || - requestResource.equals(RequestResource.CONTRIBUTIONS)) ? true : false; + (isContributionsLatestEndpoint || requestResource.equals(RequestResource.CONTRIBUTIONS)) + ? true + : false; final Set simpleFeatureTypes = processingData.getSimpleFeatureTypes(); Optional filter = processingData.getFilterExpression(); final boolean requiresGeometryTypeCheck = @@ -121,62 +124,76 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele String validFrom = null; String validTo; boolean skipNext = false; - // first contribution: - if (contributions.get(0).is(ContributionType.CREATION)) { - // if creation: skip next output - skipNext = true; - } else { - // if not "creation": take "before" as starting "row" (geom, tags), valid_from = t_start - currentEntity = contributions.get(0).getEntityBefore(); - currentGeom = exeUtils.getGeometry(contributions.get(0), clipGeometries, true); - validFrom = startTimestamp; - } - // then for each contribution: - for (OSMContribution contribution : contributions) { - // set valid_to of previous row, add to output list (output.add(…)) - validTo = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); - if (!skipNext) { - properties = new TreeMap<>(); - // deactivating the adding of the contrib type as it could deliver false results - // properties = exeUtils.addContribType(contribution, properties, includeOSMMetadata); - properties.put("@validFrom", validFrom); - properties.put("@validTo", validTo); - if (!currentGeom.isEmpty()) { - boolean addToOutput; - if (processingData.containsSimpleFeatureTypes()) { - addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); - } else if (requiresGeometryTypeCheck) { - addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); + if (!isContributionsLatestEndpoint) { + // first contribution: + if (contributions.get(0).is(ContributionType.CREATION)) { + // if creation: skip next output + skipNext = true; + } else { + // if not "creation": take "before" as starting "row" (geom, tags), valid_from = t_start + currentEntity = contributions.get(0).getEntityBefore(); + currentGeom = exeUtils.getGeometry(contributions.get(0), clipGeometries, true); + validFrom = startTimestamp; + } + // then for each contribution: + for (OSMContribution contribution : contributions) { + // set valid_to of previous row, add to output list (output.add(…)) + validTo = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); + if (!skipNext) { + properties = new TreeMap<>(); + // deactivating the adding of the contrib type as it could deliver false results + // properties = exeUtils.addContribType(contribution, properties, includeOSMMetadata); + if (!isContributionsEndpoint) { + properties.put("@validFrom", validFrom); + properties.put("@validTo", validTo); } else { - addToOutput = true; + properties.put("@timestamp", validTo); } - if (addToOutput) { - output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, - includeTags, includeOSMMetadata, elemGeom)); + if (!currentGeom.isEmpty()) { + boolean addToOutput; + if (processingData.containsSimpleFeatureTypes()) { + addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); + } else if (requiresGeometryTypeCheck) { + addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); + } else { + addToOutput = true; + } + if (addToOutput) { + output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, + includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, + contribution.getContributionTypes())); + } } } - } - skipNext = false; - if (contribution.is(ContributionType.DELETION)) { - // if deletion: skip output of next row - skipNext = true; - } else { - // else: take "after" as next row - currentEntity = contribution.getEntityAfter(); - currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); - validFrom = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); - } + skipNext = false; + if (contribution.is(ContributionType.DELETION)) { + // if deletion: skip output of next row + skipNext = true; + } else { + // else: take "after" as next row + currentEntity = contribution.getEntityAfter(); + currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); + validFrom = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); + } + } } // after loop: OSMContribution lastContribution = contributions.get(contributions.size() - 1); + currentGeom = exeUtils.getGeometry(lastContribution, clipGeometries, false); + currentEntity = lastContribution.getEntityAfter(); if (!lastContribution.is(ContributionType.DELETION)) { // if last contribution was not "deletion": set valid_to = t_end, add row to output list validTo = endTimestamp; properties = new TreeMap<>(); // deactivating the adding of the contrib type as it could deliver false results // properties = exeUtils.addContribType(lastContribution, properties, includeOSMMetadata); - properties.put("@validFrom", validFrom); - properties.put("@validTo", validTo); + if (!isContributionsEndpoint) { + properties.put("@validFrom", validFrom); + properties.put("@validTo", validTo); + } else { + properties.put("@timestamp", + TimestampFormatter.getInstance().isoDateTime(lastContribution.getTimestamp())); + } if (!currentGeom.isEmpty()) { boolean addToOutput; if (processingData.containsSimpleFeatureTypes()) { @@ -188,9 +205,19 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele } if (addToOutput) { output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, - includeTags, includeOSMMetadata, elemGeom)); + includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, + lastContribution.getContributionTypes())); } } + } else if (isContributionsEndpoint) { + // adds the deletion feature for a /contributions request + currentEntity = lastContribution.getEntityBefore(); + properties = new TreeMap<>(); + properties.put("@timestamp", + TimestampFormatter.getInstance().isoDateTime(lastContribution.getTimestamp())); + output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, + false, includeOSMMetadata, isContributionsEndpoint, elemGeom, + lastContribution.getContributionTypes())); } return output; }).filter(Objects::nonNull); @@ -233,7 +260,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele } if (addToOutput) { return Collections.singletonList(exeUtils.createOSMFeature(entity, geom, properties, - keysInt, includeTags, includeOSMMetadata, elemGeom)); + keysInt, includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, null)); } else { return Collections.emptyList(); } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java index 6e5f90ed..98dab066 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java @@ -129,7 +129,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele geom = snapshot.getGeometryUnclipped(); } return exeUtils.createOSMFeature(snapshot.getEntity(), geom, properties, keysInt, includeTags, - includeOSMMetadata, elemGeom); + includeOSMMetadata, false, elemGeom, null); }).filter(Objects::nonNull); Metadata metadata = null; if (processingData.isShowMetadata()) { diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java index 3060df49..0267458b 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java @@ -17,6 +17,7 @@ import java.sql.SQLException; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; +import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -400,8 +401,9 @@ public List createCsvTopComments(String url, String text, String apiVe /** Creates the Feature objects in the OSM data response. */ public org.wololo.geojson.Feature createOSMFeature(OSMEntity entity, Geometry geometry, Map properties, int[] keysInt, boolean includeTags, - boolean includeOSMMetadata, ElementsGeometry elemGeom) { - if (geometry.isEmpty()) { + boolean includeOSMMetadata, boolean isContributionsEndpoint, ElementsGeometry elemGeom, + EnumSet contributionTypes) { + if (geometry.isEmpty() && !contributionTypes.contains(ContributionType.DELETION)) { // skip invalid geometries (e.g. ways with 0 nodes) return null; } @@ -422,12 +424,11 @@ public org.wololo.geojson.Feature createOSMFeature(OSMEntity entity, Geometry ge } } } - properties.put("@osmId", entity.getType().toString().toLowerCase() + "/" + entity.getId()); if (includeOSMMetadata) { - properties.put("@version", entity.getVersion()); - properties.put("@osmType", entity.getType()); - properties.put("@changesetId", entity.getChangesetId()); + properties = + addAdditionalProperties(entity, properties, isContributionsEndpoint, contributionTypes); } + properties.put("@osmId", entity.getType().toString().toLowerCase() + "/" + entity.getId()); GeoJSONWriter gjw = new GeoJSONWriter(); switch (elemGeom) { case BBOX: @@ -746,7 +747,7 @@ public String combineFiltersWithOr(String firstFilter, String secondFilter) { } return "(" + firstFilter + ") or (" + secondFilter + ")"; } - + /** * Creates the csv response for /elements/_/groupBy requests. * @@ -970,6 +971,30 @@ private CSVWriter writeComments(HttpServletResponse servletResponse, List addAdditionalProperties(OSMEntity entity, + Map properties, boolean isContributionsEndpoint, + EnumSet contributionTypes) { + properties.put("@version", entity.getVersion()); + properties.put("@osmType", entity.getType()); + properties.put("@changesetId", entity.getChangesetId()); + if (isContributionsEndpoint) { + if (contributionTypes.contains(ContributionType.CREATION)) { + properties.put("@creation", "true"); + } + if (contributionTypes.contains(ContributionType.DELETION)) { + properties.put("@deletion", "true"); + } + if (contributionTypes.contains(ContributionType.TAG_CHANGE)) { + properties.put("@tagChange", "true"); + } + if (contributionTypes.contains(ContributionType.GEOMETRY_CHANGE)) { + properties.put("@geometryChange", "true"); + } + } + return properties; + } + /** Enum type used in /ratio computation. */ public enum MatchType { MATCHES1, MATCHES2, MATCHESBOTH, MATCHESNONE From 366e408d13bd8cb8323071348697fec847082543 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 1 Sep 2020 15:12:34 +0200 Subject: [PATCH 12/48] finishing a working /contributions implementation --- .../executor/DataRequestExecutor.java | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index 26c63497..2e912c35 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -124,19 +124,59 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele String validFrom = null; String validTo; boolean skipNext = false; + // used for /contributions endpoint to write creation feature info to response + boolean wasCreation = false; if (!isContributionsLatestEndpoint) { // first contribution: - if (contributions.get(0).is(ContributionType.CREATION)) { - // if creation: skip next output - skipNext = true; + OSMContribution firstContribution = contributions.get(0); + if (firstContribution.is(ContributionType.CREATION)) { + if (isContributionsEndpoint) { + currentEntity = firstContribution.getEntityAfter(); + currentGeom = exeUtils.getGeometry(firstContribution, clipGeometries, false); + properties = new TreeMap<>(); + properties.put("@timestamp", TimestampFormatter.getInstance().isoDateTime(firstContribution.getTimestamp())); + boolean addToOutp; + if (processingData.containsSimpleFeatureTypes()) { + addToOutp = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); + } else if (requiresGeometryTypeCheck) { + addToOutp = filterExpression.applyOSMGeometry(currentEntity, currentGeom); + } else { + addToOutp = true; + } + if (addToOutp) { + output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, + includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, + firstContribution.getContributionTypes())); + } + wasCreation = true; + skipNext = false; + } else { + skipNext = true; + } } else { // if not "creation": take "before" as starting "row" (geom, tags), valid_from = t_start - currentEntity = contributions.get(0).getEntityBefore(); - currentGeom = exeUtils.getGeometry(contributions.get(0), clipGeometries, true); + currentEntity = firstContribution.getEntityBefore(); + currentGeom = exeUtils.getGeometry(firstContribution, clipGeometries, true); validFrom = startTimestamp; } + int index = 0; // then for each contribution: - for (OSMContribution contribution : contributions) { + for (int i = 0; i < contributions.size(); i++) { + if (i == contributions.size() - 1 && isContributionsEndpoint) { + // end the loop when last contribution is reached as it gets added later on + break; + } + OSMContribution contribution = contributions.get(i); + if (wasCreation) { + wasCreation = false; + index++; + continue; + } + if (index == 1) { + currentEntity = contribution.getEntityAfter(); + currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); + index++; + } // set valid_to of previous row, add to output list (output.add(…)) validTo = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); if (!skipNext) { From 61061507bcedc37e6e54484c58e8e92237fc8f6c Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 1 Sep 2020 15:22:29 +0200 Subject: [PATCH 13/48] adding more descriptions and applying auto-formatting --- .../executor/DataRequestExecutor.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index 2e912c35..fbcc156f 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -134,7 +134,8 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele currentEntity = firstContribution.getEntityAfter(); currentGeom = exeUtils.getGeometry(firstContribution, clipGeometries, false); properties = new TreeMap<>(); - properties.put("@timestamp", TimestampFormatter.getInstance().isoDateTime(firstContribution.getTimestamp())); + properties.put("@timestamp", + TimestampFormatter.getInstance().isoDateTime(firstContribution.getTimestamp())); boolean addToOutp; if (processingData.containsSimpleFeatureTypes()) { addToOutp = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); @@ -145,7 +146,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele } if (addToOutp) { output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, - includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, + includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, firstContribution.getContributionTypes())); } wasCreation = true; @@ -164,15 +165,18 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele for (int i = 0; i < contributions.size(); i++) { if (i == contributions.size() - 1 && isContributionsEndpoint) { // end the loop when last contribution is reached as it gets added later on + // only used in /contributions endpoint break; } OSMContribution contribution = contributions.get(i); if (wasCreation) { + // skipping first contribution here as it got added above (only for /contributions) wasCreation = false; index++; continue; } if (index == 1) { + // as contribution was skipped before entity would be empty (only for /contributions) currentEntity = contribution.getEntityAfter(); currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); index++; @@ -199,8 +203,8 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele addToOutput = true; } if (addToOutput) { - output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, - includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, + output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, + keysInt, includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, contribution.getContributionTypes())); } } @@ -215,7 +219,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); validFrom = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); } - } + } } // after loop: OSMContribution lastContribution = contributions.get(contributions.size() - 1); @@ -255,9 +259,9 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele properties = new TreeMap<>(); properties.put("@timestamp", TimestampFormatter.getInstance().isoDateTime(lastContribution.getTimestamp())); - output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, - false, includeOSMMetadata, isContributionsEndpoint, elemGeom, - lastContribution.getContributionTypes())); + output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, false, + includeOSMMetadata, isContributionsEndpoint, elemGeom, + lastContribution.getContributionTypes())); } return output; }).filter(Objects::nonNull); @@ -299,8 +303,9 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele addToOutput = true; } if (addToOutput) { - return Collections.singletonList(exeUtils.createOSMFeature(entity, geom, properties, - keysInt, includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, null)); + return Collections + .singletonList(exeUtils.createOSMFeature(entity, geom, properties, keysInt, + includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, null)); } else { return Collections.emptyList(); } From ec8fea3ea30ee9309c3742666a60993d02c54bbf Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 15 Sep 2020 13:26:44 +0200 Subject: [PATCH 14/48] fixing javadoc issues with leftover conflict text --- .../ohsome/ohsomeapi/executor/ElementsRequestExecutor.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java index 98dab066..34495d77 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java @@ -493,11 +493,8 @@ public static Response aggregateGroupByKey(RequestResource requestResource, /** * Performs a count|length|perimeter|area|ratio calculation. * - * <<<<<<< HEAD - * * @deprecated Will be removed in next major version update. * - * ======= >>>>>>> adding of processing for /contribution/latest * @param requestResource {@link org.heigit.ohsome.ohsomeapi.executor.RequestResource * RequestResource} definition of the request resource * @param servletRequest {@link javax.servlet.http.HttpServletRequest HttpServletRequest} incoming @@ -746,11 +743,8 @@ public static Response aggregateRatio(RequestResource requestResource, /** * Performs a count|length|perimeter|area-ratio calculation grouped by the boundary. * - * <<<<<<< HEAD - * * @deprecated Will be removed in next major version update. * - * ======= >>>>>>> adding of processing for /contribution/latest * @param requestResource {@link org.heigit.ohsome.ohsomeapi.executor.RequestResource * RequestResource} definition of the request resource * @param servletRequest {@link javax.servlet.http.HttpServletRequest HttpServletRequest} incoming From adc9edf202bb22e8466f6544bf950626908b6424 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Thu, 17 Sep 2020 13:19:27 +0200 Subject: [PATCH 15/48] removing unused import and method --- .../ohsome/ohsomeapi/executor/DataRequestExecutor.java | 5 +---- .../heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java | 9 --------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index fbcc156f..728c9793 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -92,7 +92,6 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele keysInt[i] = tt.getOSHDBTagKeyOf(keys[i]).toInt(); } } - MapReducer contributionPreResult = null; ExecutionUtils exeUtils = new ExecutionUtils(processingData); inputProcessor.processPropertiesParam(); inputProcessor.processIsUnclippedParam(); @@ -116,7 +115,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele String endTimestamp = ISODateTimeParser.parseISODateTime(requestParameters.getTime()[1]) .format(DateTimeFormatter.ISO_DATE_TIME); MapReducer> mapRedContributions = mapRedContribution.groupByEntity(); - contributionPreResult = mapRedContributions.flatMap(contributions -> { + MapReducer contributionPreResult = mapRedContributions.flatMap(contributions -> { List output = new LinkedList<>(); Map properties; Geometry currentGeom = null; @@ -185,8 +184,6 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele validTo = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); if (!skipNext) { properties = new TreeMap<>(); - // deactivating the adding of the contrib type as it could deliver false results - // properties = exeUtils.addContribType(contribution, properties, includeOSMMetadata); if (!isContributionsEndpoint) { properties.put("@validFrom", validFrom); properties.put("@validTo", validTo); diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java index 0267458b..83adb23b 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java @@ -707,15 +707,6 @@ public Response createRatioGroupByBoundaryResponse(Object[] boundaryIds, String[ groupByResultSet); } - /** Adds the respective contribution type(s) to the properties if includeMetadata=true. */ - public Map addContribType(OSMContribution contribution, - Map properties, boolean includeMetadata) { - if (includeMetadata) { - properties.put("@contributionTypes", contribution.getContributionTypes()); - } - return properties; - } - /** * Extracts and returns a geometry out of the given contribution. The boolean values specify if it * should be clipped/unclipped and if the geometry before/after a contribution should be taken. From b456cc31e05fb2bf4f1e3d5f2a28778f25a29e18 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Thu, 17 Sep 2020 18:01:11 +0200 Subject: [PATCH 16/48] fixing javadoc issues and adding exception mentions in javadoc in ContributionsController --- .../ContributionsController.java | 22 +++++++++++++++---- .../rawdata/ElementsController.java | 6 ++--- .../ElementsFullHistoryController.java | 6 ++--- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java index c3219b39..bfd6c02e 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java @@ -28,6 +28,9 @@ public class ContributionsController { * * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response + * @throws Exception thrown by + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) + * extractFullHistory} */ @ApiOperation(value = "OSM contributions having the raw geometry of each OSM object as geometry", nickname = "contributionsGeometry", response = DataResponse.class) @@ -39,7 +42,8 @@ public class ContributionsController { produces = "application/json") public void contributions(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.RAW, servletRequest, servletResponse); + DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.RAW, servletRequest, + servletResponse); } /** @@ -48,6 +52,9 @@ public void contributions(HttpServletRequest servletRequest, HttpServletResponse * * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response + * @throws Exception thrown by + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) + * extractFullHistory} */ @ApiOperation(value = "OSM contributions having the bounding box of each OSM object as geometry", nickname = "contributionsBbox", response = DataResponse.class) @@ -59,7 +66,8 @@ public void contributions(HttpServletRequest servletRequest, HttpServletResponse produces = "application/json") public void contributionsBbox(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.BBOX, servletRequest, servletResponse); + DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.BBOX, + servletRequest, servletResponse); } /** @@ -68,6 +76,9 @@ public void contributionsBbox(HttpServletRequest servletRequest, * * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response + * @throws Exception thrown by + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) + * extractFullHistory} */ @ApiOperation(value = "OSM contributions having the centroid of each OSM object as geometry", nickname = "contributionsCentroid", response = DataResponse.class) @@ -79,8 +90,8 @@ public void contributionsBbox(HttpServletRequest servletRequest, produces = "application/json") public void contributionsCentroid(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.CENTROID, servletRequest, - servletResponse); + DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.CENTROID, + servletRequest, servletResponse); } /** @@ -89,6 +100,9 @@ public void contributionsCentroid(HttpServletRequest servletRequest, * * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response + * @throws Exception thrown by + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) + * extractFullHistory} */ @ApiOperation( value = "Latest OSM contributions having the raw geometry of each OSM object as geometry", diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java index de01ba20..c757f6bd 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsController.java @@ -27,7 +27,7 @@ public class ElementsController { * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor#extract(ElementsGeometry, HttpServletRequest, HttpServletResponse) + * {@link org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) * extract} */ @ApiOperation(value = "OSM Data having the raw geometry of each OSM object as geometry", @@ -47,7 +47,7 @@ public void elementsGeometry(HttpServletRequest servletRequest, * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor#extract(ElementsGeometry, HttpServletRequest, HttpServletResponse) + * {@link org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) * extract} */ @ApiOperation(value = "OSM Data, having the bounding box of each OSM object as geometry", @@ -67,7 +67,7 @@ public void elementsBbox(HttpServletRequest servletRequest, HttpServletResponse * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor#extract(ElementsGeometry, HttpServletRequest, HttpServletResponse) + * {@link org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) * extract} */ @ApiOperation(value = "OSM Data, having the centroid of each OSM object as geometry", diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java index 66d0cc76..f85c683f 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java @@ -29,7 +29,7 @@ public class ElementsFullHistoryController { * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor#extractFullHistory(ElementsGeometry, HttpServletRequest, HttpServletResponse) + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) * extractFullHistory} */ @ApiOperation( @@ -54,7 +54,7 @@ public void elementsFullHistory(HttpServletRequest servletRequest, * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor#extractFullHistory(ElementsGeometry, HttpServletRequest, HttpServletResponse) + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) * extractFullHistory} */ @ApiOperation( @@ -79,7 +79,7 @@ public void elementsBboxFullHistory(HttpServletRequest servletRequest, * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.ElementsRequestExecutor#extractFullHistory(ElementsGeometry, HttpServletRequest, HttpServletResponse) + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) * extractFullHistory} */ @ApiOperation(value = "Full-history OSM data, having the centroid of each OSM object as geometry", From 9818d08befd452d59733f12553084111ca5354d0 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Fri, 18 Sep 2020 15:41:22 +0200 Subject: [PATCH 17/48] fixing contribution processing to use the correct entity for the corresponding contribution --- .../ohsome/ohsomeapi/executor/DataRequestExecutor.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index 728c9793..b9764ee1 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -159,7 +159,6 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele currentGeom = exeUtils.getGeometry(firstContribution, clipGeometries, true); validFrom = startTimestamp; } - int index = 0; // then for each contribution: for (int i = 0; i < contributions.size(); i++) { if (i == contributions.size() - 1 && isContributionsEndpoint) { @@ -171,14 +170,12 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele if (wasCreation) { // skipping first contribution here as it got added above (only for /contributions) wasCreation = false; - index++; continue; } - if (index == 1) { - // as contribution was skipped before entity would be empty (only for /contributions) + if (isContributionsEndpoint) { currentEntity = contribution.getEntityAfter(); currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); - index++; + validFrom = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); } // set valid_to of previous row, add to output list (output.add(…)) validTo = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); @@ -210,7 +207,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele if (contribution.is(ContributionType.DELETION)) { // if deletion: skip output of next row skipNext = true; - } else { + } else if (!isContributionsEndpoint) { // else: take "after" as next row currentEntity = contribution.getEntityAfter(); currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); From fd3664a7d4249a41f82552ad732b3b6105e2839d Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Fri, 18 Sep 2020 17:14:37 +0200 Subject: [PATCH 18/48] adding and refactoring tests for data-extraction adding tests for /contribution reducing code for existing data-extraction tests --- ...ollerTest.java => DataExtractionTest.java} | 141 +++++++++++------- 1 file changed, 87 insertions(+), 54 deletions(-) rename src/test/java/org/heigit/ohsome/ohsomeapi/controller/{ElementsControllerTest.java => DataExtractionTest.java} (79%) diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/ElementsControllerTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java similarity index 79% rename from src/test/java/org/heigit/ohsome/ohsomeapi/controller/ElementsControllerTest.java rename to src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java index fc648984..15387236 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/ElementsControllerTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java @@ -21,7 +21,7 @@ import org.springframework.util.MultiValueMap; /** Test class for the data extraction requests. */ -public class ElementsControllerTest { +public class DataExtractionTest { private static String port = TestProperties.PORT3; private String server = TestProperties.SERVER; @@ -51,27 +51,28 @@ public static void applicationMainShutdown() { */ @Test - public void getElementsGeometryTest() { + public void elementsGeometryTest() { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = restTemplate.getForEntity( server + port + "/elements/geometry?bboxes=8.67452,49.40961,8.70392,49.41823&types=way" + "&keys=building&values=residential&time=2015-01-01&properties=metadata", JsonNode.class); + JsonNode feature = StreamSupport + .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), + Spliterator.ORDERED), false) + .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() + .equalsIgnoreCase("way/140112811")) + .findFirst().get(); assertTrue(StreamSupport .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), Spliterator.ORDERED), false) .anyMatch(jsonNode -> jsonNode.get("properties").get("@osmId").asText() .equalsIgnoreCase("way/140112811"))); - assertEquals(7, StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/140112811")) - .findFirst().get().get("properties").size()); + assertEquals(7, feature.get("properties").size()); } @Test - public void getElementsGeomUsingOneTagTest() { + public void elementsGeomUsingOneTagTest() { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = restTemplate.getForEntity(server + port + "/elements/geometry?bboxes=8.67452,49.40961,8.70392,49.41823&types=way&keys=building" @@ -84,7 +85,7 @@ public void getElementsGeomUsingOneTagTest() { } @Test - public void getElementsGeomUsingMultipleTagsTest() { + public void elementsGeomUsingMultipleTagsTest() { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = restTemplate.getForEntity( server + port @@ -99,7 +100,7 @@ public void getElementsGeomUsingMultipleTagsTest() { } @Test - public void getElementsGeomUnclippedSimpleFeaturesTest() { + public void elementsGeomUnclippedSimpleFeaturesTest() { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = restTemplate.getForEntity( server + port @@ -110,7 +111,7 @@ public void getElementsGeomUnclippedSimpleFeaturesTest() { } @Test - public void getElementsGeomSimpleFeaturesOtherLineTest() { + public void elementsGeomSimpleFeaturesOtherLineTest() { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = restTemplate.getForEntity(server + port + "/elements/geometry?bboxes=8.700582,49.4143039,8.701247,49.414994&types=other,line&" @@ -120,7 +121,7 @@ public void getElementsGeomSimpleFeaturesOtherLineTest() { } @Test - public void postElementsGeomUsingNoTagsTest() { + public void elementsGeomUsingNoTagsTest() { TestRestTemplate restTemplate = new TestRestTemplate(); MultiValueMap map = new LinkedMultiValueMap<>(); map.add("bboxes", "8.67452,49.40961,8.70392,49.41823"); @@ -137,28 +138,24 @@ public void postElementsGeomUsingNoTagsTest() { } @Test - public void getElementsBboxTest() { + public void elementsBboxTest() { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = restTemplate.getForEntity( server + port + "/elements/bbox?bboxes=8.67452,49.40961,8.70392,49.41823&types=way" + "&keys=building&values=residential&time=2015-01-01&properties=metadata", JsonNode.class); - assertEquals("Polygon", StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/294644468")) - .findFirst().get().get("geometry").get("type").asText()); - assertEquals(5, StreamSupport + JsonNode featureGeom = StreamSupport .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), Spliterator.ORDERED), false) .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() .equalsIgnoreCase("way/294644468")) - .findFirst().get().get("geometry").get("coordinates").get(0).size()); + .findFirst().get().get("geometry"); + assertEquals("Polygon", featureGeom.get("type").asText()); + assertEquals(5, featureGeom.get("coordinates").get(0).size()); } @Test - public void getElementsCentroidTest() { + public void elementsCentroidTest() { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = restTemplate.getForEntity( server + port + "/elements/centroid?bboxes=8.67452,49.40961,8.70392,49.41823&types=way" @@ -173,7 +170,7 @@ public void getElementsCentroidTest() { } @Test - public void getElementsClipGeometryParamTrueFalseTest() { + public void elementsClipGeometryParamTrueFalseTest() { TestRestTemplate restTemplate = new TestRestTemplate(); String uri = "/elements/geometry?bboxes=8.700582,49.4143039,8.701247,49.414994&types=other," + "line&keys=building&showMetadata=true&time=2018-01-02"; @@ -190,7 +187,7 @@ public void getElementsClipGeometryParamTrueFalseTest() { */ @Test - public void getElementsFullHistoryGeometryTest() { + public void elementsFullHistoryGeometryTest() { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = restTemplate.getForEntity( server + port + "/elementsFullHistory/geometry?bboxes=8.67452,49.40961,8.70392,49.41823&" @@ -211,7 +208,7 @@ public void getElementsFullHistoryGeometryTest() { } @Test - public void getElementsFullHistoryGeometryWithTagsTest() { + public void elementsFullHistoryGeometryWithTagsTest() { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = restTemplate.getForEntity( server + port + "/elementsFullHistory/geometry?bboxes=8.67494,49.417032,8.676136,49.419576&" @@ -232,7 +229,7 @@ public void getElementsFullHistoryGeometryWithTagsTest() { } @Test - public void postElementsFullHistoryBboxTest() { + public void elementsFullHistoryBboxTest() { TestRestTemplate restTemplate = new TestRestTemplate(); MultiValueMap map = new LinkedMultiValueMap<>(); map.add("bboxes", "8.67494,49.417032,8.676136,49.419576"); @@ -243,26 +240,22 @@ public void postElementsFullHistoryBboxTest() { map.add("properties", "tags,metadata"); ResponseEntity response = restTemplate .postForEntity(server + port + "/elementsFullHistory/bbox", map, JsonNode.class); - assertTrue(StreamSupport + JsonNode feature = StreamSupport .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@changesetId").asText() + .filter(jsonNode -> jsonNode.get("properties").get("@changesetId").asText() .equalsIgnoreCase("43971880")) - && StreamSupport - .stream(Spliterators.spliteratorUnknownSize( - response.getBody().get("features").iterator(), Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@validFrom").asText() - .equalsIgnoreCase("2017-01-01T00:00:00Z"))); - assertEquals(16, StreamSupport + .findFirst().get(); + assertTrue(StreamSupport .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@changesetId").asText() - .equalsIgnoreCase("43971880")) - .findFirst().get().get("properties").size()); + .anyMatch(jsonNode -> jsonNode.get("properties").get("@validFrom").asText() + .equalsIgnoreCase("2017-01-01T00:00:00Z"))); + assertEquals(16, feature.get("properties").size()); } @Test - public void postElementsFullHistoryCentroidTest() { + public void elementsFullHistoryCentroidTest() { TestRestTemplate restTemplate = new TestRestTemplate(); MultiValueMap map = new LinkedMultiValueMap<>(); map.add("bboxes", "8.67452,49.40961,8.70392,49.41823"); @@ -272,17 +265,13 @@ public void postElementsFullHistoryCentroidTest() { map.add("values", "residential"); ResponseEntity response = restTemplate .postForEntity(server + port + "/elementsFullHistory/centroid", map, JsonNode.class); - assertTrue(StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/295135455"))); - assertEquals(4, StreamSupport + JsonNode feature = StreamSupport .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), Spliterator.ORDERED), false) .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() .equalsIgnoreCase("way/295135455")) - .findFirst().get().get("properties").size()); + .findFirst().get(); + assertEquals(4, feature.get("properties").size()); } /* @@ -295,17 +284,13 @@ public void getElementsFilterTest() { ResponseEntity response = restTemplate.getForEntity(server + port + "/elements/bbox?bboxes=8.684692,49.407669,8.688061,49.410310&time=2016-01-01,2017-01-01" + "&filter=service=* and name!=*&properties=tags", JsonNode.class); - assertTrue(StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/225890568"))); - assertEquals(6, StreamSupport + JsonNode feature = StreamSupport .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), Spliterator.ORDERED), false) .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() .equalsIgnoreCase("way/225890568")) - .findFirst().get().get("properties").size()); + .findFirst().get(); + assertEquals(6, feature.get("properties").size()); } @Test @@ -349,7 +334,7 @@ public void postDataExtractionWithSpecificParameterOfOtherSpecificResourceTest() } @Test - public void postFullHistoryDataExtractionWithFalseSpecificParameterTest() { + public void fullHistoryDataExtractionWithFalseSpecificParameterTest() { TestRestTemplate restTemplate = new TestRestTemplate(); MultiValueMap map = new LinkedMultiValueMap<>(); map.add("propertie", "tags"); @@ -357,4 +342,52 @@ public void postFullHistoryDataExtractionWithFalseSpecificParameterTest() { .postForEntity(server + port + "/elementsFullHistory/geometry", map, JsonNode.class); assertEquals(400, response.getBody().get("status").asInt()); } + + /* + * ./contributions tests + */ + + @Test + public void contributionsContributionTypesTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/geometry?bboxes=8.686017,49.406453,8.686983,49.406966&filter=building=*&" + + "time=2008-01-01,2009-09-01&properties=metadata,tags&clipGeometry=false", JsonNode.class); + JsonNode featuresArray = response.getBody().get("features"); + assertTrue(featuresArray.get(0).get("properties").get("@creation").asText().equals("true")); + assertTrue( + featuresArray.get(1).get("properties").get("@geometryChange").asText().equals("true")); + assertTrue(featuresArray.get(2).get("properties").get("@tagChange").asText().equals("true")); + } + + @Test + public void contributionsTwoContributionTypesTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/geometry?bboxes=8.70328,49.411926,8.70564,49.413343&filter=building=*&" + + "time=2010-01-01,2012-01-01&properties=metadata&clipGeometry=false", JsonNode.class); + JsonNode featureProperties = StreamSupport + .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), + Spliterator.ORDERED), false) + .filter(jsonNode -> jsonNode.get("properties").get("@changesetId").asInt() == 10082609) + .findFirst().get().get("properties"); + assertTrue(featureProperties.get("@geometryChange").asText().equals("true") + && featureProperties.get("@tagChange").asText().equals("true")); + + } + + /* + * ./contributions/latest tests + */ + + @Test + public void contributionsLatestTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/latest/geometry?bboxes=8.687337,49.415067,8.687493,49.415172&filter=" + + "building=*&time=2010-01-01,2016-06-01&clipGeometry=false", JsonNode.class); + assertTrue(response.getBody().get("features").get(0).get("properties").get("@timestamp") + .asText().equals("2015-06-04T19:23:19Z")); + } + } From 15cec056ed324332580cfd8340ac0cb21831a23c Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Mon, 21 Sep 2020 17:48:08 +0200 Subject: [PATCH 19/48] adding support for deletions in contributions endpoint for /bbox and /centroid --- .../executor/DataRequestExecutor.java | 2 +- .../ohsomeapi/executor/ExecutionUtils.java | 30 +++++++++++++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index b9764ee1..8823d88d 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -249,7 +249,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele } } else if (isContributionsEndpoint) { // adds the deletion feature for a /contributions request - currentEntity = lastContribution.getEntityBefore(); + currentGeom = lastContribution.getGeometryBefore(); properties = new TreeMap<>(); properties.put("@timestamp", TimestampFormatter.getInstance().isoDateTime(lastContribution.getTimestamp())); diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java index 83adb23b..3ca88355 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java @@ -87,6 +87,9 @@ import org.locationtech.jts.geom.Lineal; import org.locationtech.jts.geom.Polygonal; import org.locationtech.jts.geom.Puntal; +import org.wololo.geojson.LineString; +import org.wololo.geojson.Point; +import org.wololo.geojson.Polygon; import org.wololo.jts2geojson.GeoJSONWriter; /** Holds helper methods that are used by the executor classes. */ @@ -94,6 +97,9 @@ public class ExecutionUtils { private AtomicReference isFirst; private final ProcessingData processingData; private final DecimalFormat ratioDf = defineDecimalFormat("#.######"); + private static final Point emptyPoint = new Point(new double[0]); + private static final LineString emptyLine = new LineString(new double[0][0]); + private static final Polygon emptyPolygon = new Polygon(new double[0][0][0]); public ExecutionUtils(ProcessingData processingData) { this.processingData = processingData; @@ -430,18 +436,30 @@ public org.wololo.geojson.Feature createOSMFeature(OSMEntity entity, Geometry ge } properties.put("@osmId", entity.getType().toString().toLowerCase() + "/" + entity.getId()); GeoJSONWriter gjw = new GeoJSONWriter(); + boolean deletionHandling = + isContributionsEndpoint && contributionTypes.contains(ContributionType.DELETION); + Geometry geom; switch (elemGeom) { case BBOX: + if (deletionHandling) { + return new org.wololo.geojson.Feature(emptyPolygon, properties); + } Envelope envelope = geometry.getEnvelopeInternal(); OSHDBBoundingBox bbox = OSHDBGeometryBuilder.boundingBoxOf(envelope); - return new org.wololo.geojson.Feature(gjw.write(OSHDBGeometryBuilder.getGeometry(bbox)), - properties); + geom = OSHDBGeometryBuilder.getGeometry(bbox); + break; case CENTROID: - return new org.wololo.geojson.Feature(gjw.write(geometry.getCentroid()), properties); + if (deletionHandling) { + return new org.wololo.geojson.Feature(emptyPoint, properties); + } + geom = geometry.getCentroid(); + break; case RAW: default: - return new org.wololo.geojson.Feature(gjw.write(geometry), properties); + //TODO think about how to handle deletions here + geom = geometry; } + return new org.wololo.geojson.Feature(gjw.write(geom), properties); } /** @@ -738,7 +756,7 @@ public String combineFiltersWithOr(String firstFilter, String secondFilter) { } return "(" + firstFilter + ") or (" + secondFilter + ")"; } - + /** * Creates the csv response for /elements/_/groupBy requests. * @@ -985,7 +1003,7 @@ private Map addAdditionalProperties(OSMEntity entity, } return properties; } - + /** Enum type used in /ratio computation. */ public enum MatchType { MATCHES1, MATCHES2, MATCHESBOTH, MATCHESNONE From 5b70f06b9adb4411094fa17ecdea46b89c9f37db Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 22 Sep 2020 11:27:12 +0200 Subject: [PATCH 20/48] implementing deletion handling for /geometry endpoint --- .../executor/DataRequestExecutor.java | 2 +- .../ohsomeapi/executor/ExecutionUtils.java | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index 8823d88d..4edb5108 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -187,7 +187,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele } else { properties.put("@timestamp", validTo); } - if (!currentGeom.isEmpty()) { + if (currentGeom != null && !currentGeom.isEmpty()) { boolean addToOutput; if (processingData.containsSimpleFeatureTypes()) { addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java index 3ca88355..28fbb277 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java @@ -438,7 +438,7 @@ public org.wololo.geojson.Feature createOSMFeature(OSMEntity entity, Geometry ge GeoJSONWriter gjw = new GeoJSONWriter(); boolean deletionHandling = isContributionsEndpoint && contributionTypes.contains(ContributionType.DELETION); - Geometry geom; + Geometry outputGeometry; switch (elemGeom) { case BBOX: if (deletionHandling) { @@ -446,20 +446,28 @@ public org.wololo.geojson.Feature createOSMFeature(OSMEntity entity, Geometry ge } Envelope envelope = geometry.getEnvelopeInternal(); OSHDBBoundingBox bbox = OSHDBGeometryBuilder.boundingBoxOf(envelope); - geom = OSHDBGeometryBuilder.getGeometry(bbox); + outputGeometry = OSHDBGeometryBuilder.getGeometry(bbox); break; case CENTROID: if (deletionHandling) { return new org.wololo.geojson.Feature(emptyPoint, properties); } - geom = geometry.getCentroid(); + outputGeometry = geometry.getCentroid(); break; case RAW: default: - //TODO think about how to handle deletions here - geom = geometry; + if (deletionHandling && geometry.getGeometryType().contains("Polygon")) { + return new org.wololo.geojson.Feature(emptyPolygon, properties); + } + if (deletionHandling && geometry.getGeometryType().contains("LineString")) { + return new org.wololo.geojson.Feature(emptyLine, properties); + } + if (deletionHandling && geometry.getGeometryType().contains("Point")) { + return new org.wololo.geojson.Feature(emptyPoint, properties); + } + outputGeometry = geometry; } - return new org.wololo.geojson.Feature(gjw.write(geom), properties); + return new org.wololo.geojson.Feature(gjw.write(outputGeometry), properties); } /** From 1834fb0b8952eebcae9e8301a93b11f37c854fdb Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 22 Sep 2020 11:34:56 +0200 Subject: [PATCH 21/48] changing name of streaming method to be more generic as it's also used for /contribution --- .../ohsome/ohsomeapi/executor/DataRequestExecutor.java | 2 +- .../ohsome/ohsomeapi/executor/ElementsRequestExecutor.java | 2 +- .../org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index 4edb5108..6683f200 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -309,7 +309,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele Stream snapshotStream = (snapshotPreResult != null) ? snapshotPreResult.stream() : Stream.empty(); Stream contributionStream = contributionPreResult.stream()) { - exeUtils.streamElementsResponse(servletResponse, osmData, + exeUtils.streamResponse(servletResponse, osmData, Stream.concat(contributionStream, snapshotStream)); } } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java index 34495d77..9c63abf4 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java @@ -139,7 +139,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele DataResponse osmData = new DataResponse(new Attribution(URL, TEXT), Application.API_VERSION, metadata, "FeatureCollection", Collections.emptyList()); try (Stream streamResult = preResult.stream()) { - exeUtils.streamElementsResponse(servletResponse, osmData, streamResult); + exeUtils.streamResponse(servletResponse, osmData, streamResult); } } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java index 28fbb277..56950c69 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ExecutionUtils.java @@ -237,7 +237,8 @@ public static & Serializable, V extends Comparable & Serializable, V extends Comparable resultStream) throws Exception { JsonFactory jsonFactory = new JsonFactory(); ByteArrayOutputStream tempStream = new ByteArrayOutputStream(); From 15619fb84f484f7b9e69fb62cdaa417d71fa806e Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 22 Sep 2020 12:13:41 +0200 Subject: [PATCH 22/48] adding /contributions endpoint to logger --- .../java/org/heigit/ohsome/ohsomeapi/config/LoggingConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/config/LoggingConfig.java b/src/main/java/org/heigit/ohsome/ohsomeapi/config/LoggingConfig.java index 7b4991ff..61c87ec5 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/config/LoggingConfig.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/config/LoggingConfig.java @@ -16,7 +16,7 @@ public class LoggingConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loggingRequestInterceptor).addPathPatterns("/elements/**/", - "/elementsFullHistory/**/", "/metadata/**/", "/users/**/"); + "/elementsFullHistory/**/", "/metadata/**/", "/users/**/", "/contributions/**/"); } } From 14ba7c276e00ae243190fdf10ce9c3ae81830658 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 22 Sep 2020 14:39:17 +0200 Subject: [PATCH 23/48] javadoc fixes --- .../heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java | 2 +- .../ohsome/ohsomeapi/executor/ElementsRequestExecutor.java | 2 +- .../ohsome/ohsomeapi/output/rawdataresponse/DataResponse.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index 6683f200..55c6118c 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -56,7 +56,7 @@ public class DataRequestExecutor { * {@link org.heigit.bigspatialdata.oshdb.util.time.ISODateTimeParser#parseISODateTime(String) * parseISODateTime}, * {@link org.heigit.bigspatialdata.oshdb.api.mapreducer.MapReducer#stream() stream}, or - * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, Stream) + * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamResponse(HttpServletResponse, DataResponse, Stream) * streamElementsResponse} */ public static void extract(RequestResource requestResource, ElementsGeometry elemGeom, diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java index 9c63abf4..668d285c 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java @@ -84,7 +84,7 @@ private ElementsRequestExecutor() { * {@link org.heigit.ohsome.ohsomeapi.inputprocessing.InputProcessor#processParameters() * processParameters}, * {@link org.heigit.bigspatialdata.oshdb.api.mapreducer.MapReducer#stream() stream}, or - * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamElementsResponse(HttpServletResponse, DataResponse, Stream) + * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamResponse(HttpServletResponse, DataResponse, Stream) * streamElementsResponse} */ public static void extract(RequestResource requestResource, ElementsGeometry elemGeom, diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/output/rawdataresponse/DataResponse.java b/src/main/java/org/heigit/ohsome/ohsomeapi/output/rawdataresponse/DataResponse.java index 753d23fc..92826a00 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/output/rawdataresponse/DataResponse.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/output/rawdataresponse/DataResponse.java @@ -10,7 +10,7 @@ import org.wololo.geojson.Feature; /** - * Represents the whole GeoJSON response object for the /elements resource. + * Represents the whole GeoJSON response object for the data-extraction endpoints. */ @JsonInclude(Include.NON_NULL) public class DataResponse implements Response { From 315cbf06b1c5847d9a9bcb7b9bc0e65e905caa52 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 22 Sep 2020 16:13:34 +0200 Subject: [PATCH 24/48] refactoring of data-extraction tests adding of helper method to extract the feature by the given identifier and it's value --- .../controller/DataExtractionTest.java | 128 ++++-------------- .../ohsome/ohsomeapi/controller/Helper.java | 27 +++- 2 files changed, 50 insertions(+), 105 deletions(-) diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java index 15387236..d205e1a0 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java @@ -7,9 +7,6 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.stream.StreamSupport; import org.heigit.ohsome.ohsomeapi.Application; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -57,17 +54,7 @@ public void elementsGeometryTest() { server + port + "/elements/geometry?bboxes=8.67452,49.40961,8.70392,49.41823&types=way" + "&keys=building&values=residential&time=2015-01-01&properties=metadata", JsonNode.class); - JsonNode feature = StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/140112811")) - .findFirst().get(); - assertTrue(StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/140112811"))); + JsonNode feature = Helper.getFeatureByIdentifier(response, "@osmId", "way/140112811"); assertEquals(7, feature.get("properties").size()); } @@ -77,11 +64,7 @@ public void elementsGeomUsingOneTagTest() { ResponseEntity response = restTemplate.getForEntity(server + port + "/elements/geometry?bboxes=8.67452,49.40961,8.70392,49.41823&types=way&keys=building" + "&values=residential&time=2015-12-01&properties=metadata", JsonNode.class); - assertTrue(StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/140112811"))); + assertTrue(Helper.getFeatureByIdentifier(response, "@osmId", "way/140112811") != null); } @Test @@ -92,11 +75,7 @@ public void elementsGeomUsingMultipleTagsTest() { + "/elements/geometry?bboxes=8.67559,49.40853,8.69379,49.4231&types=way&keys=highway," + "name,maxspeed&values=residential&time=2015-10-01&properties=metadata", JsonNode.class); - assertTrue(StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/4084860"))); + assertTrue(Helper.getFeatureByIdentifier(response, "@osmId", "way/4084860") != null); } @Test @@ -130,11 +109,7 @@ public void elementsGeomUsingNoTagsTest() { map.add("properties", "metadata"); ResponseEntity response = restTemplate.postForEntity(server + port + "/elements/geometry", map, JsonNode.class); - assertTrue(StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("node/135742850"))); + assertTrue(Helper.getFeatureByIdentifier(response, "@osmId", "node/135742850") != null); } @Test @@ -144,12 +119,8 @@ public void elementsBboxTest() { server + port + "/elements/bbox?bboxes=8.67452,49.40961,8.70392,49.41823&types=way" + "&keys=building&values=residential&time=2015-01-01&properties=metadata", JsonNode.class); - JsonNode featureGeom = StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/294644468")) - .findFirst().get().get("geometry"); + JsonNode featureGeom = + Helper.getFeatureByIdentifier(response, "@osmId", "way/294644468").get("geometry"); assertEquals("Polygon", featureGeom.get("type").asText()); assertEquals(5, featureGeom.get("coordinates").get(0).size()); } @@ -161,12 +132,8 @@ public void elementsCentroidTest() { server + port + "/elements/centroid?bboxes=8.67452,49.40961,8.70392,49.41823&types=way" + "&keys=building&values=residential&time=2015-01-01&properties=metadata", JsonNode.class); - assertEquals(2, StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/294644468")) - .findFirst().get().get("geometry").get("coordinates").size()); + assertEquals(2, Helper.getFeatureByIdentifier(response, "@osmId", "way/294644468") + .get("geometry").get("coordinates").size()); } @Test @@ -194,17 +161,9 @@ public void elementsFullHistoryGeometryTest() { + "types=way&keys=building&values=residential&properties=metadata&time=2015-01-01," + "2015-07-01&showMetadata=true", JsonNode.class); - assertTrue(StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/295135436"))); - assertEquals(7, StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@validTo").asText() - .equalsIgnoreCase("2015-05-05T06:59:35Z")) - .findFirst().get().get("properties").size()); + assertTrue(Helper.getFeatureByIdentifier(response, "@osmId", "way/295135436") != null); + assertEquals(7, Helper.getFeatureByIdentifier(response, "@validTo", "2015-05-05T06:59:35Z") + .get("properties").size()); } @Test @@ -215,17 +174,10 @@ public void elementsFullHistoryGeometryWithTagsTest() { + "types=way&keys=brand&values=Aldi Süd&properties=tags&time=2017-01-01,2018-01-01&" + "showMetadata=true", JsonNode.class); - assertTrue(StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@validFrom").asText() - .equalsIgnoreCase("2017-01-18T17:38:06Z"))); - assertEquals(13, StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@validTo").asText() - .equalsIgnoreCase("2017-03-03T18:51:20Z")) - .findFirst().get().get("properties").size()); + assertTrue( + Helper.getFeatureByIdentifier(response, "@validFrom", "2017-01-18T17:38:06Z") != null); + assertEquals(13, Helper.getFeatureByIdentifier(response, "@validTo", "2017-03-03T18:51:20Z") + .get("properties").size()); } @Test @@ -240,18 +192,10 @@ public void elementsFullHistoryBboxTest() { map.add("properties", "tags,metadata"); ResponseEntity response = restTemplate .postForEntity(server + port + "/elementsFullHistory/bbox", map, JsonNode.class); - JsonNode feature = StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@changesetId").asText() - .equalsIgnoreCase("43971880")) - .findFirst().get(); - assertTrue(StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .anyMatch(jsonNode -> jsonNode.get("properties").get("@validFrom").asText() - .equalsIgnoreCase("2017-01-01T00:00:00Z"))); - assertEquals(16, feature.get("properties").size()); + assertTrue( + Helper.getFeatureByIdentifier(response, "@validFrom", "2017-01-01T00:00:00Z") != null); + assertEquals(16, Helper.getFeatureByIdentifier(response, "@changesetId", "43971880") + .get("properties").size()); } @Test @@ -265,13 +209,8 @@ public void elementsFullHistoryCentroidTest() { map.add("values", "residential"); ResponseEntity response = restTemplate .postForEntity(server + port + "/elementsFullHistory/centroid", map, JsonNode.class); - JsonNode feature = StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/295135455")) - .findFirst().get(); - assertEquals(4, feature.get("properties").size()); + assertEquals(4, Helper.getFeatureByIdentifier(response, "@osmId", "way/295135455") + .get("properties").size()); } /* @@ -284,13 +223,8 @@ public void getElementsFilterTest() { ResponseEntity response = restTemplate.getForEntity(server + port + "/elements/bbox?bboxes=8.684692,49.407669,8.688061,49.410310&time=2016-01-01,2017-01-01" + "&filter=service=* and name!=*&properties=tags", JsonNode.class); - JsonNode feature = StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/225890568")) - .findFirst().get(); - assertEquals(6, feature.get("properties").size()); + assertEquals(6, Helper.getFeatureByIdentifier(response, "@osmId", "way/225890568") + .get("properties").size()); } @Test @@ -303,12 +237,8 @@ public void postElementsFilterTest() { map.add("properties", "tags"); ResponseEntity response = restTemplate.postForEntity(server + port + "/elements/bbox", map, JsonNode.class); - assertTrue(StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@osmId").asText() - .equalsIgnoreCase("way/4403824")) - .findFirst().get().get("properties").get("highway").asText().equalsIgnoreCase("tertiary")); + assertTrue(Helper.getFeatureByIdentifier(response, "@osmId", "way/4403824").get("properties") + .get("highway").asText().equalsIgnoreCase("tertiary")); } /* @@ -366,14 +296,10 @@ public void contributionsTwoContributionTypesTest() { ResponseEntity response = restTemplate.getForEntity(server + port + "/contributions/geometry?bboxes=8.70328,49.411926,8.70564,49.413343&filter=building=*&" + "time=2010-01-01,2012-01-01&properties=metadata&clipGeometry=false", JsonNode.class); - JsonNode featureProperties = StreamSupport - .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), - Spliterator.ORDERED), false) - .filter(jsonNode -> jsonNode.get("properties").get("@changesetId").asInt() == 10082609) - .findFirst().get().get("properties"); + JsonNode featureProperties = + Helper.getFeatureByIdentifier(response, "@changesetId", "10082609").get("properties"); assertTrue(featureProperties.get("@geometryChange").asText().equals("true") && featureProperties.get("@tagChange").asText().equals("true")); - } /* diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/Helper.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/Helper.java index b2415fdd..56909860 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/Helper.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/Helper.java @@ -1,8 +1,12 @@ package org.heigit.ohsome.ohsomeapi.controller; +import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.StreamSupport; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; @@ -15,7 +19,7 @@ public class Helper { private static String portPost = TestProperties.PORT2; private static String server = TestProperties.SERVER; - /** Method to get post response body as String */ + /** Gets the post response body as String. */ static String getPostResponseBody(String urlParams, MultiValueMap map) { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = @@ -24,7 +28,7 @@ static String getPostResponseBody(String urlParams, MultiValueMap getCsvRecords(String responseBody) throws IOException { CSVParser csvParser = csvParser(responseBody); List records = csvParser.getRecords(); return records; } - /** Method to get CSV headers */ + /** Gets the CSV headers from the given response. */ public static Map getCsvHeaders(String responseBody) throws IOException { CSVParser csvParser = csvParser(responseBody); Map headers = csvParser.getHeaderMap(); return headers; } + + /** + * Gets the feature from a data-extraction endpoint via the given identifier and corresponding + * value. + */ + public static JsonNode getFeatureByIdentifier(ResponseEntity response, String identifier, + String value) { + return StreamSupport + .stream(Spliterators.spliteratorUnknownSize(response.getBody().get("features").iterator(), + Spliterator.ORDERED), false) + .filter( + jsonNode -> jsonNode.get("properties").get(identifier).asText().equalsIgnoreCase(value)) + .findFirst().get(); + } + } From e541bea34677752fbac3d2fdc77e719a5045f135 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Wed, 23 Sep 2020 10:22:52 +0200 Subject: [PATCH 25/48] adding tests on deletions to check if a proper empty geometry is returned --- .../controller/DataExtractionTest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java index d205e1a0..587c85f5 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -302,6 +303,17 @@ public void contributionsTwoContributionTypesTest() { && featureProperties.get("@tagChange").asText().equals("true")); } + @Test + public void contributionsDeletionTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/geometry?bboxes=8.699552,49.411985,8.700909,49.412648&filter=building=* " + + "and type:way and id:14195519&time=2008-01-28,2012-01-01&properties=metadata" + + "&clipGeometry=false", JsonNode.class); + assertTrue(((ArrayNode) Helper.getFeatureByIdentifier(response, "@changesetId", "9218673") + .get("geometry").get("coordinates")).size() == 0); + } + /* * ./contributions/latest tests */ @@ -316,4 +328,15 @@ public void contributionsLatestTest() { .asText().equals("2015-06-04T19:23:19Z")); } + @Test + public void contributionsLatestDeletionTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/latest/geometry?bboxes=8.699552,49.411985,8.700909,49.412648&filter=building=* " + + "and type:way and id:14195519&time=2008-01-28,2012-01-01&properties=metadata", + JsonNode.class); + assertTrue(((ArrayNode) Helper.getFeatureByIdentifier(response, "@changesetId", "9218673") + .get("geometry").get("coordinates")).size() == 0); + } + } From ad27bb760887309c43bb5915aee953aea1cde33f Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Wed, 23 Sep 2020 11:21:05 +0200 Subject: [PATCH 26/48] changing geometry creation for deletions to incorporate the clipping flag --- .../heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index 55c6118c..24c37e2d 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -249,7 +249,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele } } else if (isContributionsEndpoint) { // adds the deletion feature for a /contributions request - currentGeom = lastContribution.getGeometryBefore(); + currentGeom = exeUtils.getGeometry(lastContribution, clipGeometries, true); properties = new TreeMap<>(); properties.put("@timestamp", TimestampFormatter.getInstance().isoDateTime(lastContribution.getTimestamp())); From 45607618e4910ea4a57c592ab43f2d935ad28a22 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Wed, 23 Sep 2020 12:04:45 +0200 Subject: [PATCH 27/48] removing unnecessary code to handle creations, as they can also be included easier in the for-loop --- .../executor/DataRequestExecutor.java | 35 ++----------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index 24c37e2d..ad2c6627 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -123,36 +123,11 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele String validFrom = null; String validTo; boolean skipNext = false; - // used for /contributions endpoint to write creation feature info to response - boolean wasCreation = false; if (!isContributionsLatestEndpoint) { // first contribution: OSMContribution firstContribution = contributions.get(0); - if (firstContribution.is(ContributionType.CREATION)) { - if (isContributionsEndpoint) { - currentEntity = firstContribution.getEntityAfter(); - currentGeom = exeUtils.getGeometry(firstContribution, clipGeometries, false); - properties = new TreeMap<>(); - properties.put("@timestamp", - TimestampFormatter.getInstance().isoDateTime(firstContribution.getTimestamp())); - boolean addToOutp; - if (processingData.containsSimpleFeatureTypes()) { - addToOutp = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); - } else if (requiresGeometryTypeCheck) { - addToOutp = filterExpression.applyOSMGeometry(currentEntity, currentGeom); - } else { - addToOutp = true; - } - if (addToOutp) { - output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, - includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, - firstContribution.getContributionTypes())); - } - wasCreation = true; - skipNext = false; - } else { - skipNext = true; - } + if (firstContribution.is(ContributionType.CREATION) && !isContributionsEndpoint) { + skipNext = true; } else { // if not "creation": take "before" as starting "row" (geom, tags), valid_from = t_start currentEntity = firstContribution.getEntityBefore(); @@ -167,11 +142,6 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele break; } OSMContribution contribution = contributions.get(i); - if (wasCreation) { - // skipping first contribution here as it got added above (only for /contributions) - wasCreation = false; - continue; - } if (isContributionsEndpoint) { currentEntity = contribution.getEntityAfter(); currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); @@ -259,6 +229,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele } return output; }).filter(Objects::nonNull); + Metadata metadata = null; if (processingData.isShowMetadata()) { metadata = new Metadata(null, requestResource.getDescription(), From cba009b36596896ecc34b261959836148ba7c63e Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Wed, 23 Sep 2020 17:34:46 +0200 Subject: [PATCH 28/48] minor code quality and comment changes to apply a better code flow --- .../executor/DataRequestExecutor.java | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index ad2c6627..acc484c8 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -138,7 +138,6 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele for (int i = 0; i < contributions.size(); i++) { if (i == contributions.size() - 1 && isContributionsEndpoint) { // end the loop when last contribution is reached as it gets added later on - // only used in /contributions endpoint break; } OSMContribution contribution = contributions.get(i); @@ -147,30 +146,28 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele currentGeom = exeUtils.getGeometry(contribution, clipGeometries, false); validFrom = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); } - // set valid_to of previous row, add to output list (output.add(…)) + // set valid_to of previous row validTo = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); - if (!skipNext) { - properties = new TreeMap<>(); - if (!isContributionsEndpoint) { - properties.put("@validFrom", validFrom); - properties.put("@validTo", validTo); + if (!skipNext && currentGeom != null && !currentGeom.isEmpty()) { + boolean addToOutput; + if (processingData.containsSimpleFeatureTypes()) { + addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); + } else if (requiresGeometryTypeCheck) { + addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); } else { - properties.put("@timestamp", validTo); + addToOutput = true; } - if (currentGeom != null && !currentGeom.isEmpty()) { - boolean addToOutput; - if (processingData.containsSimpleFeatureTypes()) { - addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); - } else if (requiresGeometryTypeCheck) { - addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); + if (addToOutput) { + properties = new TreeMap<>(); + if (!isContributionsEndpoint) { + properties.put("@validFrom", validFrom); + properties.put("@validTo", validTo); } else { - addToOutput = true; - } - if (addToOutput) { - output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, - keysInt, includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, - contribution.getContributionTypes())); + properties.put("@timestamp", validTo); } + output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, + includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, + contribution.getContributionTypes())); } } skipNext = false; @@ -190,11 +187,9 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele currentGeom = exeUtils.getGeometry(lastContribution, clipGeometries, false); currentEntity = lastContribution.getEntityAfter(); if (!lastContribution.is(ContributionType.DELETION)) { - // if last contribution was not "deletion": set valid_to = t_end, add row to output list + // if last contribution was not "deletion": set valid_to = t_end validTo = endTimestamp; properties = new TreeMap<>(); - // deactivating the adding of the contrib type as it could deliver false results - // properties = exeUtils.addContribType(lastContribution, properties, includeOSMMetadata); if (!isContributionsEndpoint) { properties.put("@validFrom", validFrom); properties.put("@validTo", validTo); @@ -229,7 +224,6 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele } return output; }).filter(Objects::nonNull); - Metadata metadata = null; if (processingData.isShowMetadata()) { metadata = new Metadata(null, requestResource.getDescription(), From f51512f6642a8058536f93d7a9ce651cab3b89c0 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 29 Sep 2020 16:13:50 +0200 Subject: [PATCH 29/48] adding test on /contributions/latest --- .../ohsomeapi/controller/DataExtractionTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java index 587c85f5..a9fd996f 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java @@ -338,5 +338,16 @@ public void contributionsLatestDeletionTest() { assertTrue(((ArrayNode) Helper.getFeatureByIdentifier(response, "@changesetId", "9218673") .get("geometry").get("coordinates")).size() == 0); } + + @Test + public void contributionsLatestCreationTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/latest/geometry?bboxes=8.679253,49.424025,8.679623,49.424185&filter=" + + "building=*&time=2010-01-01,2011-01-17&properties=metadata,tags&clipGeometry=false", + JsonNode.class); + assertTrue(response.getBody().get("features").get(0).get("properties").get("@creation") + .asText().equals("true")); + } } From a9e1179ef55cc077233926a79102398ae996607d Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 29 Sep 2020 16:51:09 +0200 Subject: [PATCH 30/48] refactoring of data-extraction making DataRequestExecutor unstatic modifying javadoc comments accordingly --- .../ContributionsController.java | 46 +++++----- .../ElementsFullHistoryController.java | 24 ++--- .../executor/AggregateRequestExecutor.java | 1 - .../executor/DataRequestExecutor.java | 89 +++++++++---------- 4 files changed, 82 insertions(+), 78 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java index bfd6c02e..442e70fc 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/contributions/ContributionsController.java @@ -29,8 +29,7 @@ public class ContributionsController { * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) - * extractFullHistory} + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract() extract} */ @ApiOperation(value = "OSM contributions having the raw geometry of each OSM object as geometry", nickname = "contributionsGeometry", response = DataResponse.class) @@ -42,8 +41,9 @@ public class ContributionsController { produces = "application/json") public void contributions(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.RAW, servletRequest, - servletResponse); + DataRequestExecutor executor = new DataRequestExecutor(RequestResource.CONTRIBUTIONS, + ElementsGeometry.RAW, servletRequest, servletResponse); + executor.extract(); } /** @@ -53,8 +53,7 @@ public void contributions(HttpServletRequest servletRequest, HttpServletResponse * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) - * extractFullHistory} + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract() extract} */ @ApiOperation(value = "OSM contributions having the bounding box of each OSM object as geometry", nickname = "contributionsBbox", response = DataResponse.class) @@ -66,8 +65,9 @@ public void contributions(HttpServletRequest servletRequest, HttpServletResponse produces = "application/json") public void contributionsBbox(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.BBOX, - servletRequest, servletResponse); + DataRequestExecutor executor = new DataRequestExecutor(RequestResource.CONTRIBUTIONS, + ElementsGeometry.BBOX, servletRequest, servletResponse); + executor.extract(); } /** @@ -77,8 +77,7 @@ public void contributionsBbox(HttpServletRequest servletRequest, * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) - * extractFullHistory} + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract() extract} */ @ApiOperation(value = "OSM contributions having the centroid of each OSM object as geometry", nickname = "contributionsCentroid", response = DataResponse.class) @@ -90,8 +89,9 @@ public void contributionsBbox(HttpServletRequest servletRequest, produces = "application/json") public void contributionsCentroid(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.CONTRIBUTIONS, ElementsGeometry.CENTROID, - servletRequest, servletResponse); + DataRequestExecutor executor = new DataRequestExecutor(RequestResource.CONTRIBUTIONS, + ElementsGeometry.CENTROID, servletRequest, servletResponse); + executor.extract(); } /** @@ -101,8 +101,7 @@ public void contributionsCentroid(HttpServletRequest servletRequest, * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) - * extractFullHistory} + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract() extract} */ @ApiOperation( value = "Latest OSM contributions having the raw geometry of each OSM object as geometry", @@ -115,8 +114,9 @@ public void contributionsCentroid(HttpServletRequest servletRequest, produces = "application/json") public void contributionsLatest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.CONTRIBUTIONSLATEST, ElementsGeometry.RAW, - servletRequest, servletResponse); + DataRequestExecutor executor = new DataRequestExecutor(RequestResource.CONTRIBUTIONSLATEST, + ElementsGeometry.RAW, servletRequest, servletResponse); + executor.extract(); } /** @@ -125,6 +125,8 @@ public void contributionsLatest(HttpServletRequest servletRequest, * * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response + * @throws Exception thrown by + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract() extract} */ @ApiOperation( value = "Latest OSM contributions having the bounding box of each OSM object as geometry", @@ -137,8 +139,9 @@ public void contributionsLatest(HttpServletRequest servletRequest, produces = "application/json") public void contributionsBboxLatest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.CONTRIBUTIONSLATEST, ElementsGeometry.BBOX, - servletRequest, servletResponse); + DataRequestExecutor executor = new DataRequestExecutor(RequestResource.CONTRIBUTIONSLATEST, + ElementsGeometry.BBOX, servletRequest, servletResponse); + executor.extract(); } /** @@ -147,6 +150,8 @@ public void contributionsBboxLatest(HttpServletRequest servletRequest, * * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response + * @throws Exception thrown by + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract() extract} */ @ApiOperation( value = "Latest OSM contributions having the centroid of each OSM object as geometry", @@ -159,8 +164,9 @@ public void contributionsBboxLatest(HttpServletRequest servletRequest, produces = "application/json") public void contributionsCentroidLatest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.CONTRIBUTIONSLATEST, ElementsGeometry.CENTROID, - servletRequest, servletResponse); + DataRequestExecutor executor = new DataRequestExecutor(RequestResource.CONTRIBUTIONSLATEST, + ElementsGeometry.CENTROID, servletRequest, servletResponse); + executor.extract(); } } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java index f85c683f..d02da8e4 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/controller/rawdata/ElementsFullHistoryController.java @@ -29,8 +29,7 @@ public class ElementsFullHistoryController { * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) - * extractFullHistory} + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract() extract} */ @ApiOperation( value = "Full-history OSM data having the raw geometry of each OSM object as geometry", @@ -43,8 +42,9 @@ public class ElementsFullHistoryController { produces = "application/json") public void elementsFullHistory(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.DATAEXTRACTION, ElementsGeometry.RAW, - servletRequest, servletResponse); + DataRequestExecutor executor = new DataRequestExecutor(RequestResource.DATAEXTRACTION, + ElementsGeometry.RAW, servletRequest, servletResponse); + executor.extract(); } /** @@ -54,8 +54,7 @@ public void elementsFullHistory(HttpServletRequest servletRequest, * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) - * extractFullHistory} + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract() extract} */ @ApiOperation( value = "Full-history OSM data, having the bounding box of each OSM object as geometry", @@ -68,8 +67,9 @@ public void elementsFullHistory(HttpServletRequest servletRequest, produces = "application/json") public void elementsBboxFullHistory(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.DATAEXTRACTION, ElementsGeometry.BBOX, - servletRequest, servletResponse); + DataRequestExecutor executor = new DataRequestExecutor(RequestResource.DATAEXTRACTION, + ElementsGeometry.BBOX, servletRequest, servletResponse); + executor.extract(); } /** @@ -79,8 +79,7 @@ public void elementsBboxFullHistory(HttpServletRequest servletRequest, * @param servletRequest HttpServletRequest of the incoming request * @param servletResponse HttpServletResponse of the outgoing response * @throws Exception thrown by - * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract(RequestResource, ElementsGeometry, HttpServletRequest, HttpServletResponse) - * extractFullHistory} + * {@link org.heigit.ohsome.ohsomeapi.executor.DataRequestExecutor#extract() extract} */ @ApiOperation(value = "Full-history OSM data, having the centroid of each OSM object as geometry", nickname = "elementsCentroidFullHistory", response = DataResponse.class) @@ -92,7 +91,8 @@ public void elementsBboxFullHistory(HttpServletRequest servletRequest, produces = "application/json") public void elementsCentroidFullHistory(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - DataRequestExecutor.extract(RequestResource.DATAEXTRACTION, ElementsGeometry.CENTROID, - servletRequest, servletResponse); + DataRequestExecutor executor = new DataRequestExecutor(RequestResource.DATAEXTRACTION, + ElementsGeometry.CENTROID, servletRequest, servletResponse); + executor.extract(); } } diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/AggregateRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/AggregateRequestExecutor.java index 99c0def8..f6a4d5bb 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/AggregateRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/AggregateRequestExecutor.java @@ -64,7 +64,6 @@ public AggregateRequestExecutor(RequestResource requestResource, this.requestResource = requestResource; inputProcessor = new InputProcessor(servletRequest, true, isDensity); processingData = inputProcessor.getProcessingData(); - } /** diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java index acc484c8..321e8df6 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/executor/DataRequestExecutor.java @@ -32,24 +32,31 @@ import org.heigit.ohsome.ohsomeapi.inputprocessing.ProcessingData; import org.heigit.ohsome.ohsomeapi.inputprocessing.SimpleFeatureType; import org.heigit.ohsome.ohsomeapi.oshdb.DbConnData; -import org.heigit.ohsome.ohsomeapi.output.dataaggregationresponse.Attribution; import org.heigit.ohsome.ohsomeapi.output.dataaggregationresponse.Metadata; import org.heigit.ohsome.ohsomeapi.output.rawdataresponse.DataResponse; import org.locationtech.jts.geom.Geometry; import org.wololo.geojson.Feature; /** Holds executor methods for the following endpoints: /elementsFullHistory, /contributions. */ -public class DataRequestExecutor { +public class DataRequestExecutor extends RequestExecutor { + + private final RequestResource requestResource; + private final InputProcessor inputProcessor; + private final ProcessingData processingData; + private final ElementsGeometry elementsGeometry; + + public DataRequestExecutor(RequestResource requestResource, ElementsGeometry elementsGeometry, + HttpServletRequest servletRequest, HttpServletResponse servletResponse) { + super(servletRequest, servletResponse); + this.requestResource = requestResource; + this.elementsGeometry = elementsGeometry; + inputProcessor = new InputProcessor(servletRequest, false, false); + processingData = inputProcessor.getProcessingData(); + } /** * Performs an OSM data extraction using the full-history of the data. * - * @param elemGeom {@link org.heigit.ohsome.ohsomeapi.controller.rawdata.ElementsGeometry - * ElementsGeometry} defining the geometry of the OSM elements - * @param servletRequest {@link javax.servlet.http.HttpServletRequest HttpServletRequest} incoming - * request object - * @param servletResponse {@link javax.servlet.http.HttpServletResponse HttpServletResponse]} - * outgoing response object * @throws Exception thrown by * {@link org.heigit.ohsome.ohsomeapi.inputprocessing.InputProcessor#processParameters() * processParameters}, @@ -59,9 +66,7 @@ public class DataRequestExecutor { * {@link org.heigit.ohsome.ohsomeapi.executor.ExecutionUtils#streamResponse(HttpServletResponse, DataResponse, Stream) * streamElementsResponse} */ - public static void extract(RequestResource requestResource, ElementsGeometry elemGeom, - HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { - InputProcessor inputProcessor = new InputProcessor(servletRequest, false, false); + public void extract() throws Exception { inputProcessor.getProcessingData().setIsFullHistory(true); InputProcessor snapshotInputProcessor = new InputProcessor(servletRequest, true, false); snapshotInputProcessor.getProcessingData().setIsFullHistory(true); @@ -77,7 +82,6 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele mapRedSnapshot = snapshotInputProcessor.processParameters(); mapRedContribution = inputProcessor.processParameters(); } - ProcessingData processingData = inputProcessor.getProcessingData(); RequestParameters requestParameters = processingData.getRequestParameters(); String[] time = inputProcessor.splitParamOnComma( inputProcessor.createEmptyArrayIfNull(servletRequest.getParameterValues("time"))); @@ -149,14 +153,8 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele // set valid_to of previous row validTo = TimestampFormatter.getInstance().isoDateTime(contribution.getTimestamp()); if (!skipNext && currentGeom != null && !currentGeom.isEmpty()) { - boolean addToOutput; - if (processingData.containsSimpleFeatureTypes()) { - addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); - } else if (requiresGeometryTypeCheck) { - addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); - } else { - addToOutput = true; - } + boolean addToOutput = addEntityToOutput(processingData, utils, simpleFeatureTypes, + requiresGeometryTypeCheck, filterExpression, currentGeom, currentEntity); if (addToOutput) { properties = new TreeMap<>(); if (!isContributionsEndpoint) { @@ -166,7 +164,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele properties.put("@timestamp", validTo); } output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, - includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, + includeTags, includeOSMMetadata, isContributionsEndpoint, elementsGeometry, contribution.getContributionTypes())); } } @@ -198,17 +196,11 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele TimestampFormatter.getInstance().isoDateTime(lastContribution.getTimestamp())); } if (!currentGeom.isEmpty()) { - boolean addToOutput; - if (processingData.containsSimpleFeatureTypes()) { - addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); - } else if (requiresGeometryTypeCheck) { - addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); - } else { - addToOutput = true; - } + boolean addToOutput = addEntityToOutput(processingData, utils, simpleFeatureTypes, + requiresGeometryTypeCheck, filterExpression, currentGeom, currentEntity); if (addToOutput) { output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, - includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, + includeTags, includeOSMMetadata, isContributionsEndpoint, elementsGeometry, lastContribution.getContributionTypes())); } } @@ -219,7 +211,7 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele properties.put("@timestamp", TimestampFormatter.getInstance().isoDateTime(lastContribution.getTimestamp())); output.add(exeUtils.createOSMFeature(currentEntity, currentGeom, properties, keysInt, false, - includeOSMMetadata, isContributionsEndpoint, elemGeom, + includeOSMMetadata, isContributionsEndpoint, elementsGeometry, lastContribution.getContributionTypes())); } return output; @@ -229,9 +221,8 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele metadata = new Metadata(null, requestResource.getDescription(), inputProcessor.getRequestUrlIfGetRequest(servletRequest)); } - DataResponse osmData = - new DataResponse(new Attribution(ElementsRequestExecutor.URL, ElementsRequestExecutor.TEXT), - Application.API_VERSION, metadata, "FeatureCollection", Collections.emptyList()); + DataResponse osmData = new DataResponse(ATTRIBUTION, Application.API_VERSION, metadata, + "FeatureCollection", Collections.emptyList()); MapReducer snapshotPreResult = null; if (!isContributionsEndpoint) { // handles cases where valid_from = t_start, valid_to = t_end; i.e. non-modified data @@ -253,18 +244,12 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele TimestampFormatter.getInstance().isoDateTime(snapshot.getTimestamp())); properties.put("@validFrom", startTimestamp); properties.put("@validTo", endTimestamp); - boolean addToOutput; - if (processingData.containsSimpleFeatureTypes()) { - addToOutput = utils.checkGeometryOnSimpleFeatures(geom, simpleFeatureTypes); - } else if (requiresGeometryTypeCheck) { - addToOutput = filterExpression.applyOSMGeometry(entity, geom); - } else { - addToOutput = true; - } + boolean addToOutput = addEntityToOutput(processingData, utils, simpleFeatureTypes, + requiresGeometryTypeCheck, filterExpression, geom, entity); if (addToOutput) { - return Collections - .singletonList(exeUtils.createOSMFeature(entity, geom, properties, keysInt, - includeTags, includeOSMMetadata, isContributionsEndpoint, elemGeom, null)); + return Collections.singletonList( + exeUtils.createOSMFeature(entity, geom, properties, keysInt, includeTags, + includeOSMMetadata, isContributionsEndpoint, elementsGeometry, null)); } else { return Collections.emptyList(); } @@ -279,5 +264,19 @@ public static void extract(RequestResource requestResource, ElementsGeometry ele } } + /** Checks whether the given entity should be added to the output (true) or not (false). */ + private boolean addEntityToOutput(ProcessingData processingData, InputProcessingUtils utils, + final Set simpleFeatureTypes, final boolean requiresGeometryTypeCheck, + FilterExpression filterExpression, Geometry currentGeom, OSMEntity currentEntity) { + boolean addToOutput; + if (processingData.containsSimpleFeatureTypes()) { + addToOutput = utils.checkGeometryOnSimpleFeatures(currentGeom, simpleFeatureTypes); + } else if (requiresGeometryTypeCheck) { + addToOutput = filterExpression.applyOSMGeometry(currentEntity, currentGeom); + } else { + addToOutput = true; + } + return addToOutput; + } } From 6850c4701014553bd2976c000dbb7710426651cd Mon Sep 17 00:00:00 2001 From: Rosario Trischitta Date: Thu, 1 Oct 2020 16:52:25 +0200 Subject: [PATCH 31/48] adding junit tests for /contributions get requests --- .../controller/DataExtractionTest.java | 86 +++++++++++++++++-- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java index a9fd996f..f65df5d3 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java @@ -1,6 +1,7 @@ package org.heigit.ohsome.ohsomeapi.controller; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import com.fasterxml.jackson.databind.JsonNode; @@ -303,6 +304,54 @@ public void contributionsTwoContributionTypesTest() { && featureProperties.get("@tagChange").asText().equals("true")); } + @Test + public void contributionsCreationTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/geometry?bboxes=8.70606,49.412150,8.70766,49.413686" + + "&filter=building=*&time=2011-06-01,2012-01-01&properties=metadata&clipGeometry=false", + JsonNode.class); + JsonNode featureProperties = + Helper.getFeatureByIdentifier(response, "@changesetId", "8371765").get("properties"); + assertEquals("true", featureProperties.get("@creation").asText()); + } + + @Test + public void contributionsIsNotCreationTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/centroid?bboxes=8.70500,49.412004,8.70666,49.413445" + + "&filter=building=*&time=2015-01-01,2017-01-01&properties=metadata&clipGeometry=false", + JsonNode.class); + JsonNode featureProperties = + Helper.getFeatureByIdentifier(response, "@changesetId", "36337061").get("properties"); + assertNull(featureProperties.get("@creation")); + } + + @Test + public void contributionsWithoutGeometryChangeTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/bbox?bboxes=8.70400,49.411004,8.70566,49.413345" + + "&filter=building=*&time=2012-01-01,2014-01-01&properties=metadata&clipGeometry=false", + JsonNode.class); + JsonNode featureProperties = + Helper.getFeatureByIdentifier(response, "@changesetId", "10696832").get("properties"); + assertNull(featureProperties.get("@geometryChange")); + } + + @Test + public void contributionsWithoutTagChangeTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/geometry?bboxes=8.70600,49.412104,8.70766,49.413666" + + "&filter=building=*&time=2015-01-01,2017-01-01&properties=metadata&clipGeometry=false", + JsonNode.class); + JsonNode featureProperties = + Helper.getFeatureByIdentifier(response, "@changesetId", "36337061").get("properties"); + assertNull(featureProperties.get("@tagChange")); + } + @Test public void contributionsDeletionTest() { TestRestTemplate restTemplate = new TestRestTemplate(); @@ -314,6 +363,30 @@ public void contributionsDeletionTest() { .get("geometry").get("coordinates")).size() == 0); } + @Test + public void contributionsVersionTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/centroid?bboxes=8.70785,49.412222,8.70766,49.413759&filter=building=*" + + "&time=2010-01-01,2014-01-01&properties=metadata&clipGeometry=false", JsonNode.class); + JsonNode featureProperties = + Helper.getFeatureByIdentifier(response, "@osmId", "way/248975559").get("properties"); + assertEquals(1, featureProperties.get("@version").asInt()); + } + + @Test + public void contributionsAssociationChangeSetIdWithOsmIdAndVersion() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/bbox?bboxes=8.70606,49.412150,8.70766,49.413686" + + "&filter=building=*&time=2011-06-01,2012-01-01&properties=metadata&clipGeometry=false", + JsonNode.class); + JsonNode featureProperties = + Helper.getFeatureByIdentifier(response, "@changesetId", "7042867").get("properties"); + assertTrue(featureProperties.get("@version").asInt() == 2 + && featureProperties.get("@osmId").asText().equals("way/96054443")); + } + /* * ./contributions/latest tests */ @@ -338,16 +411,17 @@ public void contributionsLatestDeletionTest() { assertTrue(((ArrayNode) Helper.getFeatureByIdentifier(response, "@changesetId", "9218673") .get("geometry").get("coordinates")).size() == 0); } - + @Test public void contributionsLatestCreationTest() { TestRestTemplate restTemplate = new TestRestTemplate(); - ResponseEntity response = restTemplate.getForEntity(server + port - + "/contributions/latest/geometry?bboxes=8.679253,49.424025,8.679623,49.424185&filter=" - + "building=*&time=2010-01-01,2011-01-17&properties=metadata,tags&clipGeometry=false", + ResponseEntity response = restTemplate.getForEntity( + server + port + + "/contributions/latest/geometry?bboxes=8.679253,49.424025,8.679623,49.424185&filter=" + + "building=*&time=2010-01-01,2011-01-17&properties=metadata,tags&clipGeometry=false", JsonNode.class); - assertTrue(response.getBody().get("features").get(0).get("properties").get("@creation") - .asText().equals("true")); + assertTrue(response.getBody().get("features").get(0).get("properties").get("@creation").asText() + .equals("true")); } } From 1feb38e0fe7476772414e814869089550081002d Mon Sep 17 00:00:00 2001 From: Rosario Trischitta Date: Fri, 2 Oct 2020 11:37:44 +0200 Subject: [PATCH 32/48] adding junit test for /contributions post requests --- .../controller/DataExtractionTest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java index f65df5d3..29296d7d 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java @@ -292,6 +292,38 @@ public void contributionsContributionTypesTest() { assertTrue(featuresArray.get(2).get("properties").get("@tagChange").asText().equals("true")); } + @Test + public void contributionsGeometryChangePostTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + MultiValueMap map = new LinkedMultiValueMap<>(); + map.add("bboxes", "8.70606,49.412150,8.70766,49.413686"); + map.add("time", "2011-06-01,2012-01-01"); + map.add("filter", "building=*"); + map.add("properties", "metadata"); + map.add("clipGeometry", "false"); + ResponseEntity response = + restTemplate.postForEntity(server + port + "/contributions/bbox", map, JsonNode.class); + JsonNode featureProperties = + Helper.getFeatureByIdentifier(response, "@osmId", "relation/1385511").get("properties"); + assertTrue(featureProperties.get("@geometryChange").asBoolean()); + } + + @Test + public void contributionsCreationPostTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + MultiValueMap map = new LinkedMultiValueMap<>(); + map.add("bboxes", "8.70606,49.412150,8.70766,49.413686"); + map.add("time", "2011-06-01,2012-01-01"); + map.add("filter", "building=*"); + map.add("properties", "metadata"); + map.add("clipGeometry", "false"); + ResponseEntity response = + restTemplate.postForEntity(server + port + "/contributions/bbox", map, JsonNode.class); + JsonNode featureProperties = + Helper.getFeatureByIdentifier(response, "@osmId", "relation/1387943").get("properties"); + assertTrue(featureProperties.get("@creation").asBoolean()); + } + @Test public void contributionsTwoContributionTypesTest() { TestRestTemplate restTemplate = new TestRestTemplate(); From 84bed51527519728fdeceb457fbee4392c3b28e3 Mon Sep 17 00:00:00 2001 From: Rosario Trischitta Date: Fri, 2 Oct 2020 12:32:05 +0200 Subject: [PATCH 33/48] adding junit test for /contributions/latest post request --- .../controller/DataExtractionTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java index 29296d7d..5e1b8a67 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java @@ -433,6 +433,23 @@ public void contributionsLatestTest() { .asText().equals("2015-06-04T19:23:19Z")); } + @Test + public void contributionsLatestPostTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + MultiValueMap map = new LinkedMultiValueMap<>(); + map.add("bboxes", "8.70606,49.412150,8.70766,49.413686"); + map.add("time", "2011-06-01,2012-01-01"); + map.add("filter", "building=*"); + map.add("properties", "metadata"); + map.add("clipGeometry", "false"); + ResponseEntity response = restTemplate + .postForEntity(server + port + "/contributions/latest/centroid", map, JsonNode.class); + JsonNode featureProperties = + Helper.getFeatureByIdentifier(response, "@osmId", "relation/1387943").get("properties"); + assertTrue(featureProperties.get("@timestamp").asText().equals("2011-06-07T16:45:11Z") + && featureProperties.get("@changesetId").asInt() == 7052829); + } + @Test public void contributionsLatestDeletionTest() { TestRestTemplate restTemplate = new TestRestTemplate(); From 0f2de70234f1c96427767f6df07feb81b6697c49 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Fri, 2 Oct 2020 15:28:06 +0200 Subject: [PATCH 34/48] modifying spec names in swagger to keep a specific ordering of the sites through adding numbers in front --- .../org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java b/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java index d58daae6..6fedbaa3 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java @@ -34,7 +34,7 @@ public class SwaggerConfig { @Bean public Docket dataAggregationDocket() { ArrayList responseMessages = defineResponseMessages(); - return new Docket(DocumentationType.SWAGGER_2).groupName("Data Aggregation").select() + return new Docket(DocumentationType.SWAGGER_2).groupName("1 - Data Aggregation").select() .apis(RequestHandlerSelectors .basePackage("org.heigit.ohsome.ohsomeapi.controller.dataaggregation")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) @@ -52,7 +52,7 @@ public Docket dataAggregationDocket() { @Bean public Docket metadataDocket() { ArrayList responseMessages = defineResponseMessages(); - return new Docket(DocumentationType.SWAGGER_2).groupName("Metadata").select() + return new Docket(DocumentationType.SWAGGER_2).groupName("4 - Metadata").select() .apis( RequestHandlerSelectors.basePackage("org.heigit.ohsome.ohsomeapi.controller.metadata")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) @@ -64,7 +64,7 @@ public Docket metadataDocket() { @Bean public Docket rawDataDocket() { ArrayList responseMessages = defineResponseMessages(); - return new Docket(DocumentationType.SWAGGER_2).groupName("Data Extraction").select() + return new Docket(DocumentationType.SWAGGER_2).groupName("2 - Data Extraction").select() .apis(RequestHandlerSelectors.basePackage("org.heigit.ohsome.ohsomeapi.controller.rawdata")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) .globalOperationParameters(defineGlobalOperationParams(true)) @@ -78,7 +78,7 @@ public Docket rawDataDocket() { @Bean public Docket contributionsDocket() { ArrayList responseMessages = defineResponseMessages(); - return new Docket(DocumentationType.SWAGGER_2).groupName("Contributions").select() + return new Docket(DocumentationType.SWAGGER_2).groupName("3 - Contributions").select() .apis(RequestHandlerSelectors.basePackage("org.heigit.ohsome.ohsomeapi.controller.contributions")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) .globalOperationParameters(defineGlobalOperationParams(true)) From d818a68c8c9d7f7e35615c8c7ac8dda8ff63c8a4 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Fri, 2 Oct 2020 15:28:59 +0200 Subject: [PATCH 35/48] modifying valid parameters for /contributions removing types, keys, values from list of valid params as they are deprecated --- .../ohsomeapi/inputprocessing/ResourceParameters.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/inputprocessing/ResourceParameters.java b/src/main/java/org/heigit/ohsome/ohsomeapi/inputprocessing/ResourceParameters.java index c05facb9..09205501 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/inputprocessing/ResourceParameters.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/inputprocessing/ResourceParameters.java @@ -47,6 +47,12 @@ public static List getResourceSpecificParams(HttpServletRequest servletR } else if (uri.contains("/bbox") || uri.contains("/centroid") || uri.contains("/geometry")) { possibleParams.add("properties"); possibleParams.add("clipGeometry"); + // removing deprecated params from newly implemented endpoint + if (uri.contains("/contributions")) { + possibleParams.remove("types"); + possibleParams.remove("keys"); + possibleParams.remove("values"); + } return possibleParams; } else { return possibleParams; From 0989912ce1b349545363fcc9befd9a48b655f0a4 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Fri, 2 Oct 2020 16:09:46 +0200 Subject: [PATCH 36/48] modifying description for contributions in swagger --- .../ohsome/ohsomeapi/config/SwaggerConfig.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java b/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java index 6fedbaa3..3c8f7509 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java @@ -73,16 +73,18 @@ public Docket rawDataDocket() { "Direct access to the full-history of the OSM data")) .forCodeGeneration(true).globalResponseMessage(RequestMethod.GET, responseMessages); } - + /** Creates the Swagger2 documentation for the contributions resources. */ @Bean public Docket contributionsDocket() { ArrayList responseMessages = defineResponseMessages(); return new Docket(DocumentationType.SWAGGER_2).groupName("3 - Contributions").select() - .apis(RequestHandlerSelectors.basePackage("org.heigit.ohsome.ohsomeapi.controller.contributions")) + .apis(RequestHandlerSelectors + .basePackage("org.heigit.ohsome.ohsomeapi.controller.contributions")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) .globalOperationParameters(defineGlobalOperationParams(true)) - .tags(new Tag("Contributions", "Get the contributed OSM features")) + .tags( + new Tag("Contributions", "Direct access to all contributions provided to the OSM data")) .forCodeGeneration(true).globalResponseMessage(RequestMethod.GET, responseMessages); } @@ -171,10 +173,9 @@ private List defineGlobalOperationParams(boolean isDataExtraction) { .description(ParameterDescriptions.CLIP_GEOMETRY).modelRef(new ModelRef(string)) .parameterType(query).defaultValue("true").required(false).build()); } - globalOperationParams.add( - new ParameterBuilder().name("showMetadata").description(ParameterDescriptions.SHOW_METADATA) - .modelRef(new ModelRef(string)).parameterType(query) - .defaultValue("").required(false).build()); + globalOperationParams.add(new ParameterBuilder().name("showMetadata") + .description(ParameterDescriptions.SHOW_METADATA).modelRef(new ModelRef(string)) + .parameterType(query).defaultValue("").required(false).build()); return globalOperationParams; } } From a10dce2673b62b3c58358dad3234a3bc7d264b6a Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Fri, 2 Oct 2020 16:19:07 +0200 Subject: [PATCH 37/48] modifying swagger for /contributions removing types, keys, values parameters from swagger --- .../ohsomeapi/config/SwaggerConfig.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java b/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java index 3c8f7509..ec26a546 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java @@ -38,7 +38,7 @@ public Docket dataAggregationDocket() { .apis(RequestHandlerSelectors .basePackage("org.heigit.ohsome.ohsomeapi.controller.dataaggregation")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) - .globalOperationParameters(defineGlobalOperationParams(false)) + .globalOperationParameters(defineGlobalOperationParams(false, false)) .tags(new Tag("Users", "Compute data aggregation functions on users"), new Tag("Area", "Compute the area of polygonal OSM elements"), new Tag("Length", "Compute the length of linear OSM elements"), @@ -67,7 +67,7 @@ public Docket rawDataDocket() { return new Docket(DocumentationType.SWAGGER_2).groupName("2 - Data Extraction").select() .apis(RequestHandlerSelectors.basePackage("org.heigit.ohsome.ohsomeapi.controller.rawdata")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) - .globalOperationParameters(defineGlobalOperationParams(true)) + .globalOperationParameters(defineGlobalOperationParams(true, false)) .tags(new Tag("Data Extraction", "Direct access to the OSM data"), new Tag("Full-History Data Extraction", "Direct access to the full-history of the OSM data")) @@ -82,7 +82,7 @@ public Docket contributionsDocket() { .apis(RequestHandlerSelectors .basePackage("org.heigit.ohsome.ohsomeapi.controller.contributions")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) - .globalOperationParameters(defineGlobalOperationParams(true)) + .globalOperationParameters(defineGlobalOperationParams(true, true)) .tags( new Tag("Contributions", "Direct access to all contributions provided to the OSM data")) .forCodeGeneration(true).globalResponseMessage(RequestMethod.GET, responseMessages); @@ -125,7 +125,8 @@ private ApiInfo apiInfo() { * Defines the description of each parameter, which are used in all resources for the Swagger2 * documentation. */ - private List defineGlobalOperationParams(boolean isDataExtraction) { + private List defineGlobalOperationParams(boolean isDataExtraction, + boolean isContributions) { final String string = "string"; final String query = "query"; List globalOperationParams = new ArrayList<>(); @@ -138,15 +139,17 @@ private List defineGlobalOperationParams(boolean isDataExtraction) { globalOperationParams.add(new ParameterBuilder().name("bpolys") .description(ParameterDescriptions.BPOLYS).modelRef(new ModelRef(string)) .parameterType(query).defaultValue("").required(false).build()); - globalOperationParams.add(new ParameterBuilder().name("types") - .description(ParameterDescriptions.DEPRECATED_USE_FILTER).modelRef(new ModelRef(string)) - .allowMultiple(true).parameterType(query).defaultValue("").required(false).build()); - globalOperationParams.add(new ParameterBuilder().name("keys") - .description(ParameterDescriptions.DEPRECATED_USE_FILTER).modelRef(new ModelRef(string)) - .parameterType(query).defaultValue("").required(false).build()); - globalOperationParams.add(new ParameterBuilder().name("values") - .description(ParameterDescriptions.DEPRECATED_USE_FILTER).modelRef(new ModelRef(string)) - .parameterType(query).defaultValue("").required(false).build()); + if (!isContributions) { + globalOperationParams.add(new ParameterBuilder().name("types") + .description(ParameterDescriptions.DEPRECATED_USE_FILTER).modelRef(new ModelRef(string)) + .allowMultiple(true).parameterType(query).defaultValue("").required(false).build()); + globalOperationParams.add(new ParameterBuilder().name("keys") + .description(ParameterDescriptions.DEPRECATED_USE_FILTER).modelRef(new ModelRef(string)) + .parameterType(query).defaultValue("").required(false).build()); + globalOperationParams.add(new ParameterBuilder().name("values") + .description(ParameterDescriptions.DEPRECATED_USE_FILTER).modelRef(new ModelRef(string)) + .parameterType(query).defaultValue("").required(false).build()); + } globalOperationParams .add(new ParameterBuilder().name("filter").description(ParameterDescriptions.FILTER) .modelRef(new ModelRef(string)).parameterType(query) From 2621afaa28a6f61ef1cd45dcd4cf566dfab58a6c Mon Sep 17 00:00:00 2001 From: Rosario Trischitta Date: Mon, 5 Oct 2020 10:29:51 +0200 Subject: [PATCH 38/48] adding junit test --- .../controller/DataExtractionTest.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java index 5e1b8a67..b0ae551b 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java @@ -6,7 +6,9 @@ import static org.junit.Assume.assumeTrue; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import org.heigit.ohsome.ohsomeapi.Application; @@ -450,6 +452,20 @@ public void contributionsLatestPostTest() { && featureProperties.get("@changesetId").asInt() == 7052829); } + @Test + public void contributionsLatestOnlyOneEntryTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/contributions/latest/geometry?bboxes=8.70606,49.412150,8.70766,49.413686&filter=" + + "building=*&time=2011-06-01,2012-01-01&clipGeometry=false", JsonNode.class); + JsonNode featuresArray = response.getBody().get("features"); + List osmIds = new ArrayList(); + for (JsonNode feature : featuresArray) { + osmIds.add(feature.get("properties").get("@osmId").asText()); + } + assertEquals(1, Collections.frequency(osmIds, "relation/1387943")); + } + @Test public void contributionsLatestDeletionTest() { TestRestTemplate restTemplate = new TestRestTemplate(); @@ -472,5 +488,4 @@ public void contributionsLatestCreationTest() { assertTrue(response.getBody().get("features").get(0).get("properties").get("@creation").asText() .equals("true")); } - } From 82ffeb49e31465d101b23815f533c3df2d24125f Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Mon, 5 Oct 2020 17:10:49 +0200 Subject: [PATCH 39/48] adding base docs for /contributions adding a new section for the new endpoint --- docs/endpoints.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/endpoints.rst b/docs/endpoints.rst index 322c03c5..35c21eb9 100644 --- a/docs/endpoints.rst +++ b/docs/endpoints.rst @@ -1287,6 +1287,16 @@ Extract the modifications of the blown up tower of the heidelberg castle over ti ... ] } + + +Contribution Endpoints +---------------------- + +.. http:post :: /contributions/(geometryType) + + Direct access to all contributions provided to the OSM data. This endpoint does not support the deprecated ``types``, ``keys``, ``values`` parameters. + It uses the same ``geometryType`` options as the ``/elements`` and ``/elementsFullHistory`` endpoints. + Metadata Endpoint From e53251e310cedf2913c032f655d0154330595db5 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Mon, 5 Oct 2020 17:43:41 +0200 Subject: [PATCH 40/48] adding the /contributions/latest endpoint to docs --- docs/endpoints.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/endpoints.rst b/docs/endpoints.rst index 35c21eb9..3bce0385 100644 --- a/docs/endpoints.rst +++ b/docs/endpoints.rst @@ -1294,9 +1294,14 @@ Contribution Endpoints .. http:post :: /contributions/(geometryType) - Direct access to all contributions provided to the OSM data. This endpoint does not support the deprecated ``types``, ``keys``, ``values`` parameters. + Get the contributions provided to the OSM data. This endpoint does not support the deprecated ``types``, ``keys``, ``values`` parameters. It uses the same ``geometryType`` options as the ``/elements`` and ``/elementsFullHistory`` endpoints. + +.. http:post :: /contributions/latest/(geometryType) + + Get the the latest state of the contributions provided to the OSM data. This endpoint does not support the deprecated ``types``, ``keys``, ``values`` parameters. + It uses the same ``geometryType`` options as the ``/elements`` and ``/elementsFullHistory`` endpoints. Metadata Endpoint From 2bae97221e21fce5d939cb1fbc38c122577782a9 Mon Sep 17 00:00:00 2001 From: Katharina Przybill Date: Thu, 8 Oct 2020 15:23:55 +0200 Subject: [PATCH 41/48] add examples (curl, python, R) for contributions and contributions/latest endpoint --- docs/endpoints.rst | 574 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 573 insertions(+), 1 deletion(-) diff --git a/docs/endpoints.rst b/docs/endpoints.rst index 3bce0385..181be354 100644 --- a/docs/endpoints.rst +++ b/docs/endpoints.rst @@ -1297,12 +1297,584 @@ Contribution Endpoints Get the contributions provided to the OSM data. This endpoint does not support the deprecated ``types``, ``keys``, ``values`` parameters. It uses the same ``geometryType`` options as the ``/elements`` and ``/elementsFullHistory`` endpoints. - +**Example request**: + +Get the changes of pharmacies with opening hours in a certain area of Heidelberg in times of COVID-19 + + .. tabs:: + + .. code-tab:: bash curl (GET) + + curl -X GET 'https://api.ohsome.org/v1/contributions/geometry?bboxes=8.6720%2C49.3988%2C8.7026%2C49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01%2C2020-06-29&showMetadata=yes&properties=metadata%2Ctags&clipGeometry=false' + + .. code-tab:: bash curl (POST) + + curl -X POST 'https://api.ohsome.org/v1/contributions/geometry' --data-urlencode 'bboxes=8.6720,49.3988,8.7026,49.4274' --data-urlencode 'time=2020-02-01,2020-06-29' --data-urlencode 'filter=amenity=pharmacy and opening_hours=* and type:node' --data-urlencode 'showMetadata=yes' --data-urlencode 'properties=metadata,tags' --data-urlencode 'clipGeometry=false' + + .. code-tab:: python Python + + import requests + URL = 'https://api.ohsome.org/v1/contributions/geometry' + data = {"bboxes": "8.6720,49.3988,8.7026,49.4274", "time": "2020-02-01,2020-06-29", "filter": "amenity=pharmacy and opening_hours=* and type:node", "showMetadata": "yes", "properties": "metadata,tags", "clipGeometry": "false"} + response = requests.post(URL, data=data) + print(response.json()) + + .. code-tab:: r R + + library(httr) + r <- POST("https://api.ohsome.org/v1/contributions/geometry", encode = "form", body = list(bboxes = "8.6720,49.3988,8.7026,49.4274", time = "2020-02-01,2020-06-29", filter = "amenity=pharmacy and opening_hours=* and type:node", showMetadata = "yes", properties = "metadata,tags", clipGeometry = "false")) + r + +.. note:: The following example responses only show parts of the returned .geojson file. + +**Example response**: + + .. tabs:: + + .. code-tab:: text curl (GET) + + { + "attribution" : { + "url" : "https://ohsome.org/copyrights", + "text" : "© OpenStreetMap contributors" + }, + "apiVersion" : "1.2.0-SNAPSHOT", + "metadata" : { + "description" : "Latest contributions as GeoJSON features.", + "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + }, + "type" : "FeatureCollection", + "features" : [{ + "type" : "Feature", + "geometry" : { + "type" : "Point", + "coordinates" : [ + 8.6902451, + 49.408015899999995 + ] + }, + "properties" : { + "@changesetId" : 83099383, + "@osmId" : "node/323191854", + "@osmType" : "NODE", + "@tagChange" : "true", + "@timestamp" : "2020-04-05T13:32:50Z", + "@version" : 8, + "addr:city" : "Heidelberg", + "addr:housenumber" : "24", + "addr:postcode" : "69115", + "addr:street" : "Poststraße", + "amenity" : "pharmacy", + "contact:email" : "aesculap-heidelberg@web.de", + "contact:fax" : "+49 6221 163746", + "contact:phone" : "+49 6221 27634", + "dispensing" : "yes", + "healthcare" : "pharmacy", + "name" : "Aesculap Apotheke", + "opening_hours" : "Mo-Fr 08:30-18:30; Sa 09:00-13:00", + "operator" : "Stefan Wowra", + "website" : "https://aesculap-heidelberg.de", + "wheelchair" : "yes" + } + }, { ... + }, { + "type" : "Feature", + "geometry" : { + "type" : "Point", + "coordinates" : [ + 8.6922106, + 49.4103048 + ] + }, + "properties" : { + "@changesetId" : 83099383, + "@osmId" : "node/5400804545", + "@osmType" : "NODE", + "@tagChange" : "true", + "@timestamp" : "2020-04-05T13:32:50Z", + "@version" : 2, + "amenity" : "pharmacy", + "dispensing" : "yes", + "fax" : "+49 6221 9831332", + "healthcare" : "pharmacy", + "name" : "ATOS-Apotheke", + "opening_hours" : "Mo-Fr 08:30-18:30; Sa 09:00-14:00", + "phone" : "+49 6221 9831331", + "website" : "http://www.atos-apotheke.de", + "wheelchair" : "yes" + } + }] + } + + + .. code-tab:: text curl (POST) + + { + "attribution" : { + "url" : "https://ohsome.org/copyrights", + "text" : "© OpenStreetMap contributors" + }, + "apiVersion" : "1.2.0-SNAPSHOT", + "metadata" : { + "description" : "Latest contributions as GeoJSON features.", + "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + }, + "type" : "FeatureCollection", + "features" : [{ + "type" : "Feature", + "geometry" : { + "type" : "Point", + "coordinates" : [ + 8.6902451, + 49.408015899999995 + ] + }, + "properties" : { + "@changesetId" : 83099383, + "@osmId" : "node/323191854", + "@osmType" : "NODE", + "@tagChange" : "true", + "@timestamp" : "2020-04-05T13:32:50Z", + "@version" : 8, + "addr:city" : "Heidelberg", + "addr:housenumber" : "24", + "addr:postcode" : "69115", + "addr:street" : "Poststraße", + "amenity" : "pharmacy", + "contact:email" : "aesculap-heidelberg@web.de", + "contact:fax" : "+49 6221 163746", + "contact:phone" : "+49 6221 27634", + "dispensing" : "yes", + "healthcare" : "pharmacy", + "name" : "Aesculap Apotheke", + "opening_hours" : "Mo-Fr 08:30-18:30; Sa 09:00-13:00", + "operator" : "Stefan Wowra", + "website" : "https://aesculap-heidelberg.de", + "wheelchair" : "yes" + } + }, { ... + }, { + "type" : "Feature", + "geometry" : { + "type" : "Point", + "coordinates" : [ + 8.6922106, + 49.4103048 + ] + }, + "properties" : { + "@changesetId" : 83099383, + "@osmId" : "node/5400804545", + "@osmType" : "NODE", + "@tagChange" : "true", + "@timestamp" : "2020-04-05T13:32:50Z", + "@version" : 2, + "amenity" : "pharmacy", + "dispensing" : "yes", + "fax" : "+49 6221 9831332", + "healthcare" : "pharmacy", + "name" : "ATOS-Apotheke", + "opening_hours" : "Mo-Fr 08:30-18:30; Sa 09:00-14:00", + "phone" : "+49 6221 9831331", + "website" : "http://www.atos-apotheke.de", + "wheelchair" : "yes" + } + }] + } + + + .. code-tab:: text Python + + { + "attribution" : { + "url" : "https://ohsome.org/copyrights", + "text" : "© OpenStreetMap contributors" + }, + "apiVersion" : "1.2.0-SNAPSHOT", + "metadata" : { + "description" : "Latest contributions as GeoJSON features.", + "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + }, + "type" : "FeatureCollection", + "features" : [{ + "type" : "Feature", + "geometry" : { + "type" : "Point", + "coordinates" : [ + 8.6902451, + 49.408015899999995 + ] + }, + "properties" : { + "@changesetId" : 83099383, + "@osmId" : "node/323191854", + "@osmType" : "NODE", + "@tagChange" : "true", + "@timestamp" : "2020-04-05T13:32:50Z", + "@version" : 8, + "addr:city" : "Heidelberg", + "addr:housenumber" : "24", + "addr:postcode" : "69115", + "addr:street" : "Poststraße", + "amenity" : "pharmacy", + "contact:email" : "aesculap-heidelberg@web.de", + "contact:fax" : "+49 6221 163746", + "contact:phone" : "+49 6221 27634", + "dispensing" : "yes", + "healthcare" : "pharmacy", + "name" : "Aesculap Apotheke", + "opening_hours" : "Mo-Fr 08:30-18:30; Sa 09:00-13:00", + "operator" : "Stefan Wowra", + "website" : "https://aesculap-heidelberg.de", + "wheelchair" : "yes" + } + }, { ... + }, { + "type" : "Feature", + "geometry" : { + "type" : "Point", + "coordinates" : [ + 8.6922106, + 49.4103048 + ] + }, + "properties" : { + "@changesetId" : 83099383, + "@osmId" : "node/5400804545", + "@osmType" : "NODE", + "@tagChange" : "true", + "@timestamp" : "2020-04-05T13:32:50Z", + "@version" : 2, + "amenity" : "pharmacy", + "dispensing" : "yes", + "fax" : "+49 6221 9831332", + "healthcare" : "pharmacy", + "name" : "ATOS-Apotheke", + "opening_hours" : "Mo-Fr 08:30-18:30; Sa 09:00-14:00", + "phone" : "+49 6221 9831331", + "website" : "http://www.atos-apotheke.de", + "wheelchair" : "yes" + } + }] + } + + + .. code-tab:: text R + + { + "attribution" : { + "url" : "https://ohsome.org/copyrights", + "text" : "© OpenStreetMap contributors" + }, + "apiVersion" : "1.2.0-SNAPSHOT", + "metadata" : { + "description" : "Latest contributions as GeoJSON features.", + "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + }, + "type" : "FeatureCollection", + "features" : [{ + "type" : "Feature", + "geometry" : { + "type" : "Point", + "coordinates" : [ + 8.6902451, + 49.408015899999995 + ] + }, + "properties" : { + "@changesetId" : 83099383, + "@osmId" : "node/323191854", + "@osmType" : "NODE", + "@tagChange" : "true", + "@timestamp" : "2020-04-05T13:32:50Z", + "@version" : 8, + "addr:city" : "Heidelberg", + "addr:housenumber" : "24", + "addr:postcode" : "69115", + "addr:street" : "Poststraße", + "amenity" : "pharmacy", + "contact:email" : "aesculap-heidelberg@web.de", + "contact:fax" : "+49 6221 163746", + "contact:phone" : "+49 6221 27634", + "dispensing" : "yes", + "healthcare" : "pharmacy", + "name" : "Aesculap Apotheke", + "opening_hours" : "Mo-Fr 08:30-18:30; Sa 09:00-13:00", + "operator" : "Stefan Wowra", + "website" : "https://aesculap-heidelberg.de", + "wheelchair" : "yes" + } + }, { ... + }, { + "type" : "Feature", + "geometry" : { + "type" : "Point", + "coordinates" : [ + 8.6922106, + 49.4103048 + ] + }, + "properties" : { + "@changesetId" : 83099383, + "@osmId" : "node/5400804545", + "@osmType" : "NODE", + "@tagChange" : "true", + "@timestamp" : "2020-04-05T13:32:50Z", + "@version" : 2, + "amenity" : "pharmacy", + "dispensing" : "yes", + "fax" : "+49 6221 9831332", + "healthcare" : "pharmacy", + "name" : "ATOS-Apotheke", + "opening_hours" : "Mo-Fr 08:30-18:30; Sa 09:00-14:00", + "phone" : "+49 6221 9831331", + "website" : "http://www.atos-apotheke.de", + "wheelchair" : "yes" + } + }] + } + .. http:post :: /contributions/latest/(geometryType) Get the the latest state of the contributions provided to the OSM data. This endpoint does not support the deprecated ``types``, ``keys``, ``values`` parameters. It uses the same ``geometryType`` options as the ``/elements`` and ``/elementsFullHistory`` endpoints. +**Example request**: + +Get the latest change of constructions in a certain area of the Bahnstadt in Heidelberg + + .. tabs:: + + .. code-tab:: bash curl (GET) + + curl -X GET 'https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644%2C49.4010%2C8.6663%2C49.4027&filter=landuse=construction%20and%20type:way&time=2020-06-29%2C2014-07-01&showMetadata=yes&properties=metadata%2Ctags&clipGeometry=false' + + .. code-tab:: bash curl (POST) + + curl -X POST 'https://api.ohsome.org/v1/contributions/latest/geometry' --data-urlencode 'bboxes=8.6644,49.4010,8.6663,49.4027' --data-urlencode 'time=2020-06-29,2014-07-01' --data-urlencode 'filter=landuse=construction and type:way' --data-urlencode 'showMetadata=yes' --data-urlencode 'properties=metadata,tags' --data-urlencode 'clipGeometry=false' + + .. code-tab:: python Python + + import requests + URL = 'https://api.ohsome.org/v1/contributions/latest/geometry' + data = {"bboxes": "8.6644,49.4010,8.6663,49.4027", "time": "2020-06-29,2014-07-01", "filter": "landuse=construction and type:way", "showMetadata": "yes", "properties": "metadata,tags", "clipGeometry": "false"} + response = requests.post(URL, data=data) + print(response.json()) + + .. code-tab:: r R + + library(httr) + r <- POST("https://api.ohsome.org/v1/contributions/latest/geometry", encode = "form", body = list(bboxes = "8.6644,49.4010,8.6663,49.4027", time = "2020-06-29,2014-07-01", filter = "landuse=construction and type:way", showMetadata = "yes", properties = "metadata,tags", clipGeometry = "false")) + r + +.. note:: The following example responses only show parts of the returned .geojson file. + +**Example response**: + + .. tabs:: + + .. code-tab:: text curl (GET) + + { + "attribution" : { + "url" : "https://ohsome.org/copyrights", + "text" : "© OpenStreetMap contributors" + }, + "apiVersion" : "1.2.0-SNAPSHOT", + "metadata" : { + "description" : "Latest contributions as GeoJSON features.", + "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + }, + "type" : "FeatureCollection", + "features" : [{ + "type" : "Feature", + "geometry" : { + "type" : "Polygon", + "coordinates" : [ + [ + [ + 8.6654314, + 49.4026779 + ], ... + }, + "properties" : { + "@changesetId" : 85604249, + "@geometryChange" : "true", + "@osmId" : "way/795435536", + "@osmType" : "WAY", + "@timestamp" : "2020-05-22T10:22:53Z", + "@version" : 3, + "landuse" : "construction" + } + }, { + "type" : "Feature", + "geometry" : { + "type" : "Polygon", + "coordinates" : [ ] + }, + "properties" : { + "@changesetId" : 51902131, + "@deletion" : "true", + "@osmId" : "way/135635599", + "@osmType" : "WAY", + "@timestamp" : "2017-09-10T09:22:03Z", + "@version" : 9 + } + }] + } + + + .. code-tab:: text curl (POST) + + { + "attribution" : { + "url" : "https://ohsome.org/copyrights", + "text" : "© OpenStreetMap contributors" + }, + "apiVersion" : "1.2.0-SNAPSHOT", + "metadata" : { + "description" : "Latest contributions as GeoJSON features.", + "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + }, + "type" : "FeatureCollection", + "features" : [{ + "type" : "Feature", + "geometry" : { + "type" : "Polygon", + "coordinates" : [ + [ + [ + 8.6654314, + 49.4026779 + ], ... + }, + "properties" : { + "@changesetId" : 85604249, + "@geometryChange" : "true", + "@osmId" : "way/795435536", + "@osmType" : "WAY", + "@timestamp" : "2020-05-22T10:22:53Z", + "@version" : 3, + "landuse" : "construction" + } + }, { + "type" : "Feature", + "geometry" : { + "type" : "Polygon", + "coordinates" : [ ] + }, + "properties" : { + "@changesetId" : 51902131, + "@deletion" : "true", + "@osmId" : "way/135635599", + "@osmType" : "WAY", + "@timestamp" : "2017-09-10T09:22:03Z", + "@version" : 9 + } + }] + } + + + .. code-tab:: text Python + + { + "attribution" : { + "url" : "https://ohsome.org/copyrights", + "text" : "© OpenStreetMap contributors" + }, + "apiVersion" : "1.2.0-SNAPSHOT", + "metadata" : { + "description" : "Latest contributions as GeoJSON features.", + "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + }, + "type" : "FeatureCollection", + "features" : [{ + "type" : "Feature", + "geometry" : { + "type" : "Polygon", + "coordinates" : [ + [ + [ + 8.6654314, + 49.4026779 + ], ... + }, + "properties" : { + "@changesetId" : 85604249, + "@geometryChange" : "true", + "@osmId" : "way/795435536", + "@osmType" : "WAY", + "@timestamp" : "2020-05-22T10:22:53Z", + "@version" : 3, + "landuse" : "construction" + } + }, { + "type" : "Feature", + "geometry" : { + "type" : "Polygon", + "coordinates" : [ ] + }, + "properties" : { + "@changesetId" : 51902131, + "@deletion" : "true", + "@osmId" : "way/135635599", + "@osmType" : "WAY", + "@timestamp" : "2017-09-10T09:22:03Z", + "@version" : 9 + } + }] + } + + + .. code-tab:: text R + + { + "attribution" : { + "url" : "https://ohsome.org/copyrights", + "text" : "© OpenStreetMap contributors" + }, + "apiVersion" : "1.2.0-SNAPSHOT", + "metadata" : { + "description" : "Latest contributions as GeoJSON features.", + "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + }, + "type" : "FeatureCollection", + "features" : [{ + "type" : "Feature", + "geometry" : { + "type" : "Polygon", + "coordinates" : [ + [ + [ + 8.6654314, + 49.4026779 + ], ... + }, + "properties" : { + "@changesetId" : 85604249, + "@geometryChange" : "true", + "@osmId" : "way/795435536", + "@osmType" : "WAY", + "@timestamp" : "2020-05-22T10:22:53Z", + "@version" : 3, + "landuse" : "construction" + } + }, { + "type" : "Feature", + "geometry" : { + "type" : "Polygon", + "coordinates" : [ ] + }, + "properties" : { + "@changesetId" : 51902131, + "@deletion" : "true", + "@osmId" : "way/135635599", + "@osmType" : "WAY", + "@timestamp" : "2017-09-10T09:22:03Z", + "@version" : 9 + } + }] + } Metadata Endpoint ----------------- From 89d0ea01916ad3526b6f5906ec64cd5611c7730d Mon Sep 17 00:00:00 2001 From: Katharina Przybill Date: Thu, 8 Oct 2020 16:41:51 +0200 Subject: [PATCH 42/48] contributions endpoint corrections --- docs/endpoints.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/endpoints.rst b/docs/endpoints.rst index 181be354..a0ba2bb7 100644 --- a/docs/endpoints.rst +++ b/docs/endpoints.rst @@ -1341,7 +1341,7 @@ Get the changes of pharmacies with opening hours in a certain area of Heidelberg "apiVersion" : "1.2.0-SNAPSHOT", "metadata" : { "description" : "Latest contributions as GeoJSON features.", - "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" }, "type" : "FeatureCollection", "features" : [{ @@ -1417,7 +1417,7 @@ Get the changes of pharmacies with opening hours in a certain area of Heidelberg "apiVersion" : "1.2.0-SNAPSHOT", "metadata" : { "description" : "Latest contributions as GeoJSON features.", - "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" }, "type" : "FeatureCollection", "features" : [{ @@ -1493,7 +1493,7 @@ Get the changes of pharmacies with opening hours in a certain area of Heidelberg "apiVersion" : "1.2.0-SNAPSHOT", "metadata" : { "description" : "Latest contributions as GeoJSON features.", - "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" }, "type" : "FeatureCollection", "features" : [{ @@ -1569,7 +1569,7 @@ Get the changes of pharmacies with opening hours in a certain area of Heidelberg "apiVersion" : "1.2.0-SNAPSHOT", "metadata" : { "description" : "Latest contributions as GeoJSON features.", - "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" }, "type" : "FeatureCollection", "features" : [{ @@ -1647,24 +1647,24 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei .. code-tab:: bash curl (GET) - curl -X GET 'https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644%2C49.4010%2C8.6663%2C49.4027&filter=landuse=construction%20and%20type:way&time=2020-06-29%2C2014-07-01&showMetadata=yes&properties=metadata%2Ctags&clipGeometry=false' + curl -X GET 'https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644%2C49.4010%2C8.6663%2C49.4027&filter=landuse=construction%20and%20type:way&time=2014-07-01%2C2020-06-29&showMetadata=yes&properties=metadata%2Ctags&clipGeometry=false' .. code-tab:: bash curl (POST) - curl -X POST 'https://api.ohsome.org/v1/contributions/latest/geometry' --data-urlencode 'bboxes=8.6644,49.4010,8.6663,49.4027' --data-urlencode 'time=2020-06-29,2014-07-01' --data-urlencode 'filter=landuse=construction and type:way' --data-urlencode 'showMetadata=yes' --data-urlencode 'properties=metadata,tags' --data-urlencode 'clipGeometry=false' + curl -X POST 'https://api.ohsome.org/v1/contributions/latest/geometry' --data-urlencode 'bboxes=8.6644,49.4010,8.6663,49.4027' --data-urlencode 'time=2014-07-01,2020-06-29' --data-urlencode 'filter=landuse=construction and type:way' --data-urlencode 'showMetadata=yes' --data-urlencode 'properties=metadata,tags' --data-urlencode 'clipGeometry=false' .. code-tab:: python Python import requests URL = 'https://api.ohsome.org/v1/contributions/latest/geometry' - data = {"bboxes": "8.6644,49.4010,8.6663,49.4027", "time": "2020-06-29,2014-07-01", "filter": "landuse=construction and type:way", "showMetadata": "yes", "properties": "metadata,tags", "clipGeometry": "false"} + data = {"bboxes": "8.6644,49.4010,8.6663,49.4027", "time": "2014-07-01,2020-06-29", "filter": "landuse=construction and type:way", "showMetadata": "yes", "properties": "metadata,tags", "clipGeometry": "false"} response = requests.post(URL, data=data) print(response.json()) .. code-tab:: r R library(httr) - r <- POST("https://api.ohsome.org/v1/contributions/latest/geometry", encode = "form", body = list(bboxes = "8.6644,49.4010,8.6663,49.4027", time = "2020-06-29,2014-07-01", filter = "landuse=construction and type:way", showMetadata = "yes", properties = "metadata,tags", clipGeometry = "false")) + r <- POST("https://api.ohsome.org/v1/contributions/latest/geometry", encode = "form", body = list(bboxes = "8.6644,49.4010,8.6663,49.4027", time = "2014-07-01,2020-06-29", filter = "landuse=construction and type:way", showMetadata = "yes", properties = "metadata,tags", clipGeometry = "false")) r .. note:: The following example responses only show parts of the returned .geojson file. @@ -1683,7 +1683,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei "apiVersion" : "1.2.0-SNAPSHOT", "metadata" : { "description" : "Latest contributions as GeoJSON features.", - "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" }, "type" : "FeatureCollection", "features" : [{ @@ -1699,7 +1699,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei }, "properties" : { "@changesetId" : 85604249, - "@geometryChange" : "true", + "@geometryChange" : "true", "@osmId" : "way/795435536", "@osmType" : "WAY", "@timestamp" : "2020-05-22T10:22:53Z", @@ -1734,7 +1734,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei "apiVersion" : "1.2.0-SNAPSHOT", "metadata" : { "description" : "Latest contributions as GeoJSON features.", - "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" }, "type" : "FeatureCollection", "features" : [{ @@ -1750,7 +1750,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei }, "properties" : { "@changesetId" : 85604249, - "@geometryChange" : "true", + "@geometryChange" : "true", "@osmId" : "way/795435536", "@osmType" : "WAY", "@timestamp" : "2020-05-22T10:22:53Z", @@ -1785,7 +1785,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei "apiVersion" : "1.2.0-SNAPSHOT", "metadata" : { "description" : "Latest contributions as GeoJSON features.", - "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" }, "type" : "FeatureCollection", "features" : [{ @@ -1801,7 +1801,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei }, "properties" : { "@changesetId" : 85604249, - "@geometryChange" : "true", + "@geometryChange" : "true", "@osmId" : "way/795435536", "@osmType" : "WAY", "@timestamp" : "2020-05-22T10:22:53Z", @@ -1836,7 +1836,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei "apiVersion" : "1.2.0-SNAPSHOT", "metadata" : { "description" : "Latest contributions as GeoJSON features.", - "requestUrl" : "http://localhost:8080/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" + "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" }, "type" : "FeatureCollection", "features" : [{ @@ -1852,7 +1852,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei }, "properties" : { "@changesetId" : 85604249, - "@geometryChange" : "true", + "@geometryChange" : "true", "@osmId" : "way/795435536", "@osmType" : "WAY", "@timestamp" : "2020-05-22T10:22:53Z", From 5467cfc1f0c6ead98a683bbb5130e039a5d392a4 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Mon, 19 Oct 2020 11:38:59 +0200 Subject: [PATCH 43/48] swagger: make resource specs sortable --- .../ohsomeapi/config/SwaggerConfig.java | 58 +++++++++++++++++-- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java b/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java index ec26a546..c7cde038 100644 --- a/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java +++ b/src/main/java/org/heigit/ohsome/ohsomeapi/config/SwaggerConfig.java @@ -2,12 +2,18 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import org.heigit.ohsome.ohsomeapi.Application; import org.heigit.ohsome.ohsomeapi.controller.DefaultSwaggerParameters; import org.heigit.ohsome.ohsomeapi.controller.ParameterDescriptions; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.PropertySource; import org.springframework.web.bind.annotation.RequestMethod; import springfox.documentation.builders.ParameterBuilder; @@ -22,19 +28,58 @@ import springfox.documentation.service.Tag; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider; +import springfox.documentation.swagger.web.SwaggerResource; +import springfox.documentation.swagger.web.SwaggerResourcesProvider; import springfox.documentation.swagger2.annotations.EnableSwagger2; /** Swagger configuration class. */ @Configuration @EnableSwagger2 @PropertySource("classpath:application.properties") -public class SwaggerConfig { +@Primary +public class SwaggerConfig implements SwaggerResourcesProvider { + private enum OhsomeApiResourceSpec { + DATA_AGGREGATION("Data Aggregation", 1), + DATA_EXTRACTION("Data Extraction", 2), + CONTRIBUTIONS("Contributions", 3), + METADATA("Metadata", 9); + + private final String name; + private final int sorting; + OhsomeApiResourceSpec(String name, int sorting) { + this.name = name; + this.sorting = sorting; + } + } + + private final InMemorySwaggerResourcesProvider resourcesProvider; + private final Map resourcesSorting = new HashMap<>(); + + /** + * Creates swagger configuration object, initializes internal specs sorting table. + */ + @Autowired + public SwaggerConfig(InMemorySwaggerResourcesProvider resourcesProvider) { + this.resourcesProvider = resourcesProvider; + for (OhsomeApiResourceSpec spec : OhsomeApiResourceSpec.values()) { + resourcesSorting.put(spec.name, spec.sorting); + } + } + + @Override + public List get() { + return resourcesProvider.get().stream() + .sorted(Comparator.comparing(r -> resourcesSorting.getOrDefault(r.getName(), 99))) + .collect(Collectors.toList()); + } /** Creates the Swagger2 documentation for the dataAggregation resources. */ @Bean public Docket dataAggregationDocket() { ArrayList responseMessages = defineResponseMessages(); - return new Docket(DocumentationType.SWAGGER_2).groupName("1 - Data Aggregation").select() + return new Docket(DocumentationType.SWAGGER_2) + .groupName(OhsomeApiResourceSpec.DATA_AGGREGATION.name).select() .apis(RequestHandlerSelectors .basePackage("org.heigit.ohsome.ohsomeapi.controller.dataaggregation")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) @@ -52,7 +97,8 @@ public Docket dataAggregationDocket() { @Bean public Docket metadataDocket() { ArrayList responseMessages = defineResponseMessages(); - return new Docket(DocumentationType.SWAGGER_2).groupName("4 - Metadata").select() + return new Docket(DocumentationType.SWAGGER_2) + .groupName(OhsomeApiResourceSpec.METADATA.name).select() .apis( RequestHandlerSelectors.basePackage("org.heigit.ohsome.ohsomeapi.controller.metadata")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) @@ -64,7 +110,8 @@ public Docket metadataDocket() { @Bean public Docket rawDataDocket() { ArrayList responseMessages = defineResponseMessages(); - return new Docket(DocumentationType.SWAGGER_2).groupName("2 - Data Extraction").select() + return new Docket(DocumentationType.SWAGGER_2) + .groupName(OhsomeApiResourceSpec.DATA_EXTRACTION.name).select() .apis(RequestHandlerSelectors.basePackage("org.heigit.ohsome.ohsomeapi.controller.rawdata")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) .globalOperationParameters(defineGlobalOperationParams(true, false)) @@ -78,7 +125,8 @@ public Docket rawDataDocket() { @Bean public Docket contributionsDocket() { ArrayList responseMessages = defineResponseMessages(); - return new Docket(DocumentationType.SWAGGER_2).groupName("3 - Contributions").select() + return new Docket(DocumentationType.SWAGGER_2) + .groupName(OhsomeApiResourceSpec.CONTRIBUTIONS.name).select() .apis(RequestHandlerSelectors .basePackage("org.heigit.ohsome.ohsomeapi.controller.contributions")) .paths(PathSelectors.any()).build().apiInfo(apiInfo()).useDefaultResponseMessages(false) From 7f1009f53886b040a431716d6ad9c3682482c0e1 Mon Sep 17 00:00:00 2001 From: Rosario Trischitta Date: Tue, 27 Oct 2020 12:24:20 +0100 Subject: [PATCH 44/48] Adding parameters descriptions, solves #58 adding http response status codes, solves #64 --- docs/http-response-status.rst | 25 +++++++++++++++++++++++++ docs/index.rst | 9 ++++++--- docs/response-parameters.rst | 24 ++++++++++++++++++++++++ docs/time.rst | 4 ++-- 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 docs/http-response-status.rst create mode 100644 docs/response-parameters.rst diff --git a/docs/http-response-status.rst b/docs/http-response-status.rst new file mode 100644 index 00000000..a12716ae --- /dev/null +++ b/docs/http-response-status.rst @@ -0,0 +1,25 @@ +HTTP response status of the ohsome API +====================================== + +List of HTTP status codes and respective descriptions of the ohsome API. + +2xx success +----------- + +* ``200 OK`` - standard response for successfully GET and POST requests + +4xx client errors +----------------- + +* ``400 Bad Request`` - the ohsome API cannot or will not process the request due to client error (e.g. malformed request syntax) +* ``401 Unauthorized`` - the client does not have valid authentication credentials for the target resource +* ``404 Not Found``- the requested resource coud not be found +* ``405 Method not allowed`` - a request method is not supported (e.g. a POST request for resources which accept only GET requests) +* ``413 Payload Too Large`` - the request is larger than the ohsome API is willing or able to process. + +5xx server errors +----------------- + +* ``500 Internal Server Error``- generic error message, given when an unexpected condition in the ohsome API was encountered +* ``501 Not Implemented`` - the ohsome API either does not recognize the request method, or it lacks the ability to fulfil the request +* ``503 Service Unavailable`` - the ohsome API cannot handle the request (e.g. because it is overloaded or down for maintenance); temporary state diff --git a/docs/index.rst b/docs/index.rst index 212a2028..1f3407d0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -21,14 +21,17 @@ Welcome to the documentation of the ohsome API! .. autodocs .. toctree:: - :maxdepth: 2 + :maxdepth: 1 :caption: Additional Information: - :hidden: - + boundaries group-by time filter + response-parameters + http-response-status + +.. autodocs Additional Links: ----------------- diff --git a/docs/response-parameters.rst b/docs/response-parameters.rst new file mode 100644 index 00000000..4aff85fe --- /dev/null +++ b/docs/response-parameters.rst @@ -0,0 +1,24 @@ +Response Parameters +=================== + +List and description of response parameters. + +Extraction Endpoints +-------------------- + +* ``@osmId`` - id of the OSM feature with its type (node/way/relation) +* ``@validFrom`` - indicates when a creation or change of this feature with these exactly attributes and geometry was made; has the same value as the fromTimestamp if the creation/change happened before the requested timestamp +* ``@validTo`` - indicates until when this feature with these exactly attributes and geometry stayed unchanged or undeleted; has the same value as the fromTimestamp if the creation/change happened before the requested timestamp + +Contribution Endpoints +---------------------- + +* ``@osmId`` - id of the OSM feature with its type (node/way/relation) +* ``@osmType``- type (node/way/relation) of OSM feature +* ``@timestamp`` - indicates when this contribution occurred +* ``@version`` - version of the feature +* ``@changesetId``- id assigned to a changeset +* ``@creation`` - contribution type; indicates if this feature is newly created (true); cannot occur in combination with other contribution types +* ``@geometryChange`` - contribution type; indicates if the geometry of this feature has changed (true); can occur in combination with @tagChange +* ``@tagChange``- contribution type; indicates if the tag of this feature has changed (true); can occur in combination with @geometryChange +* ``@deletion`` - contribution type; indicates if the feature is deleted (true); cannot occur in combination with other contribution types diff --git a/docs/time.rst b/docs/time.rst index 83c2413f..0723272c 100644 --- a/docs/time.rst +++ b/docs/time.rst @@ -6,8 +6,8 @@ ISO-8601 conform timestring(s). .. note:: The ohsome API only supports the UTC time zone (Z). -Supported time formats: ------------------------ +Supported time formats +---------------------- * timestamp: ``2014-01-01`` * list of timestamps: ``2014-01-01,2015-07-01,2018-10-10`` From b1e82dd7f946ddddc2a06d18a1e13f333a77e8b1 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Tue, 27 Oct 2020 15:42:03 +0100 Subject: [PATCH 45/48] extending parameter descriptions in docs adapting their grouping modifying some descriptions --- docs/http-response-status.rst | 6 +++--- docs/response-parameters.rst | 34 +++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/docs/http-response-status.rst b/docs/http-response-status.rst index a12716ae..bc7aca6b 100644 --- a/docs/http-response-status.rst +++ b/docs/http-response-status.rst @@ -1,7 +1,7 @@ -HTTP response status of the ohsome API -====================================== +HTTP Response Status +==================== -List of HTTP status codes and respective descriptions of the ohsome API. +List of HTTP status codes and respective descriptions. 2xx success ----------- diff --git a/docs/response-parameters.rst b/docs/response-parameters.rst index 4aff85fe..772f5340 100644 --- a/docs/response-parameters.rst +++ b/docs/response-parameters.rst @@ -1,23 +1,35 @@ Response Parameters =================== -List and description of response parameters. +Descriptions of the custom response parameters that are marked with a leading ``@`` for the +data extraction and contributions endpoints. -Extraction Endpoints --------------------- +General Parameters +------------------ * ``@osmId`` - id of the OSM feature with its type (node/way/relation) -* ``@validFrom`` - indicates when a creation or change of this feature with these exactly attributes and geometry was made; has the same value as the fromTimestamp if the creation/change happened before the requested timestamp -* ``@validTo`` - indicates until when this feature with these exactly attributes and geometry stayed unchanged or undeleted; has the same value as the fromTimestamp if the creation/change happened before the requested timestamp +* ``@version`` - version of the feature +* ``@changesetId``- id assigned to a changeset +* ``@osmType``- type (node/way/relation) of OSM feature -Contribution Endpoints ----------------------- -* ``@osmId`` - id of the OSM feature with its type (node/way/relation) -* ``@osmType``- type (node/way/relation) of OSM feature +Extraction Parameters +--------------------- + +**specific for /elements** + +* ``@snapshotTimestamp`` - describes for which timestamp a snapshot of this feature was requested +* ``@lastEdit`` - describes the timestamp at which this feature was edited the last time + +**specific for /elementsFullHistory** + +* ``@validFrom`` - indicates when a creation or change of this feature with the provided attributes and geometry was made; has the same value as the fromTimestamp if the creation/change happened before the requested time interval +* ``@validTo`` - indicates until when this feature with the provided attributes and geometry stayed unchanged or undeleted; has the same value as the toTimestamp if the change/deletion happened after the requested time interval + +Contribution Parameters +----------------------- + * ``@timestamp`` - indicates when this contribution occurred -* ``@version`` - version of the feature -* ``@changesetId``- id assigned to a changeset * ``@creation`` - contribution type; indicates if this feature is newly created (true); cannot occur in combination with other contribution types * ``@geometryChange`` - contribution type; indicates if the geometry of this feature has changed (true); can occur in combination with @tagChange * ``@tagChange``- contribution type; indicates if the tag of this feature has changed (true); can occur in combination with @geometryChange From f50dce28d5bf05703bda15cef9773284f4ebaae5 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Mon, 2 Nov 2020 12:17:32 +0100 Subject: [PATCH 46/48] minor writing-style fixes in docs for HTTP status codes --- docs/http-response-status.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/http-response-status.rst b/docs/http-response-status.rst index bc7aca6b..74b509b8 100644 --- a/docs/http-response-status.rst +++ b/docs/http-response-status.rst @@ -6,15 +6,15 @@ List of HTTP status codes and respective descriptions. 2xx success ----------- -* ``200 OK`` - standard response for successfully GET and POST requests +* ``200 OK`` - standard response for successful GET or POST requests 4xx client errors ----------------- -* ``400 Bad Request`` - the ohsome API cannot or will not process the request due to client error (e.g. malformed request syntax) +* ``400 Bad Request`` - the ohsome API cannot or will not process the request due to a client error (e.g. malformed request syntax) * ``401 Unauthorized`` - the client does not have valid authentication credentials for the target resource * ``404 Not Found``- the requested resource coud not be found -* ``405 Method not allowed`` - a request method is not supported (e.g. a POST request for resources which accept only GET requests) +* ``405 Method not allowed`` - the requested method is not supported (e.g. a POST request for resources which accept only GET requests) * ``413 Payload Too Large`` - the request is larger than the ohsome API is willing or able to process. 5xx server errors From bb6be21138bca090e0eee494cd5666d5a268a5f4 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Mon, 2 Nov 2020 12:22:07 +0100 Subject: [PATCH 47/48] Revert "minor writing-style fixes in docs" This reverts commit 1d909b5698e96614470a4dc3380e7dafae3efbd6. --- docs/http-response-status.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/http-response-status.rst b/docs/http-response-status.rst index 74b509b8..bc7aca6b 100644 --- a/docs/http-response-status.rst +++ b/docs/http-response-status.rst @@ -6,15 +6,15 @@ List of HTTP status codes and respective descriptions. 2xx success ----------- -* ``200 OK`` - standard response for successful GET or POST requests +* ``200 OK`` - standard response for successfully GET and POST requests 4xx client errors ----------------- -* ``400 Bad Request`` - the ohsome API cannot or will not process the request due to a client error (e.g. malformed request syntax) +* ``400 Bad Request`` - the ohsome API cannot or will not process the request due to client error (e.g. malformed request syntax) * ``401 Unauthorized`` - the client does not have valid authentication credentials for the target resource * ``404 Not Found``- the requested resource coud not be found -* ``405 Method not allowed`` - the requested method is not supported (e.g. a POST request for resources which accept only GET requests) +* ``405 Method not allowed`` - a request method is not supported (e.g. a POST request for resources which accept only GET requests) * ``413 Payload Too Large`` - the request is larger than the ohsome API is willing or able to process. 5xx server errors From d8f4c5faeef787ca3802869ed1fdb209d482f5a8 Mon Sep 17 00:00:00 2001 From: Fabian Kowatsch Date: Mon, 2 Nov 2020 12:23:19 +0100 Subject: [PATCH 48/48] minor writing-style fixes in docs for HTTP response codes --- docs/http-response-status.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/http-response-status.rst b/docs/http-response-status.rst index bc7aca6b..fc51f798 100644 --- a/docs/http-response-status.rst +++ b/docs/http-response-status.rst @@ -6,16 +6,16 @@ List of HTTP status codes and respective descriptions. 2xx success ----------- -* ``200 OK`` - standard response for successfully GET and POST requests +* ``200 OK`` - standard response for successful GET or POST requests 4xx client errors ----------------- -* ``400 Bad Request`` - the ohsome API cannot or will not process the request due to client error (e.g. malformed request syntax) +* ``400 Bad Request`` - the ohsome API cannot or will not process the request due to a client error (e.g. malformed request syntax) * ``401 Unauthorized`` - the client does not have valid authentication credentials for the target resource * ``404 Not Found``- the requested resource coud not be found -* ``405 Method not allowed`` - a request method is not supported (e.g. a POST request for resources which accept only GET requests) -* ``413 Payload Too Large`` - the request is larger than the ohsome API is willing or able to process. +* ``405 Method not allowed`` - the requested method is not supported (e.g. a POST request for resources which accept only GET requests) +* ``413 Payload Too Large`` - the request is larger than the ohsome API is willing or able to process 5xx server errors -----------------