From f83cf588b0465828f4cd0580a167e68c2b0ef55d Mon Sep 17 00:00:00 2001 From: rng Date: Wed, 25 Feb 2026 17:05:07 +1100 Subject: [PATCH] Refactor function --- .../server/core/service/geoserver/Server.java | 87 ++++++++++++++ .../geoserver/wfs/DownloadWfsDataService.java | 110 +++--------------- 2 files changed, 105 insertions(+), 92 deletions(-) create mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/Server.java diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/Server.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/Server.java new file mode 100644 index 00000000..fcab443c --- /dev/null +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/Server.java @@ -0,0 +1,87 @@ +package au.org.aodn.ogcapi.server.core.service.geoserver; + +import au.org.aodn.ogcapi.server.core.model.ogc.wfs.WfsField; +import au.org.aodn.ogcapi.server.core.model.ogc.wfs.WfsFields; +import au.org.aodn.ogcapi.server.core.service.geoserver.wfs.WfsServer; +import au.org.aodn.ogcapi.server.core.util.DatetimeUtils; +import au.org.aodn.ogcapi.server.core.util.GeometryUtils; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Slf4j +public abstract class Server { + protected WfsServer wfsServer; + + public Server(WfsServer wfsServer) { + this.wfsServer = wfsServer; + } + /** + * Build CQL filter for temporal and spatial constraints + */ + protected String buildCqlFilter(String wfsServerUrl, String uuid, String layerName, String sd, String ed, Object multiPolygon) { + + WfsFields wfsFieldModel = wfsServer.getDownloadableFields( + uuid, + WfsServer.WfsFeatureRequest.builder() + .layerName(layerName) + .server(wfsServerUrl) + .build() + ); + log.debug("WFSFieldModel by wfs typename: {}", wfsFieldModel); + + // Validate start and end dates + final String startDate = DatetimeUtils.validateAndFormatDate(sd, true); + final String endDate = DatetimeUtils.validateAndFormatDate(ed, false); + + StringBuilder cqlFilter = new StringBuilder(); + + if (wfsFieldModel == null || wfsFieldModel.getFields() == null) { + return cqlFilter.toString(); + } + + List fields = wfsFieldModel.getFields(); + + // Possible to have multiple days, better to consider all + List temporalField = fields.stream() + .filter(field -> "dateTime".equals(field.getType()) || "date".equals(field.getType())) + .toList(); + + // Add temporal filter only if both dates are specified + if (!temporalField.isEmpty() && startDate != null && !startDate.isEmpty() && endDate != null && !endDate.isEmpty()) { + List cqls = new ArrayList<>(); + temporalField.forEach(temp -> + cqls.add(String.format("(%s DURING %sT00:00:00Z/%sT23:59:59Z)", temp.getName(), startDate, endDate)) + ); + cqlFilter.append("(").append(String.join(" OR ", cqls)).append(")"); + } + + // Find geometry field + Optional geometryField = fields.stream() + .filter(field -> "geometrypropertytype".equalsIgnoreCase(field.getType())) + .findFirst(); + + // Add spatial filter + if (geometryField.isPresent() && multiPolygon != null) { + String fieldName = geometryField.get().getName(); + + String wkt = GeometryUtils.convertToWkt(multiPolygon); + + if ((wkt != null) && !cqlFilter.isEmpty()) { + cqlFilter.append(" AND "); + } + + if (wkt != null) { + cqlFilter.append("INTERSECTS(") + .append(fieldName) + .append(",") + .append(wkt) + .append(")"); + } + } + + return cqlFilter.toString(); + } +} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataService.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataService.java index 81f84727..20873aa3 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataService.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataService.java @@ -1,10 +1,7 @@ package au.org.aodn.ogcapi.server.core.service.geoserver.wfs; import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest; -import au.org.aodn.ogcapi.server.core.model.ogc.wfs.WfsField; -import au.org.aodn.ogcapi.server.core.model.ogc.wfs.WfsFields; -import au.org.aodn.ogcapi.server.core.util.DatetimeUtils; -import au.org.aodn.ogcapi.server.core.util.GeometryUtils; +import au.org.aodn.ogcapi.server.core.service.geoserver.Server; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; @@ -21,8 +18,7 @@ @Slf4j @Service -public class DownloadWfsDataService { - private final WfsServer wfsServer; +public class DownloadWfsDataService extends Server { private final RestTemplate restTemplate; private final HttpEntity pretendUserEntity; private final int chunkSize; @@ -33,65 +29,11 @@ public DownloadWfsDataService( @Qualifier("pretendUserEntity") HttpEntity pretendUserEntity, @Value("${app.sse.chunkSize:16384}") int chunkSize ) { - this.wfsServer = wfsServer; + super(wfsServer); this.restTemplate = restTemplate; this.pretendUserEntity = pretendUserEntity; this.chunkSize = chunkSize; } - - /** - * Build CQL filter for temporal and spatial constraints - */ - protected String buildCqlFilter(String startDate, String endDate, Object multiPolygon, WfsFields wfsFieldModel) { - StringBuilder cqlFilter = new StringBuilder(); - - if (wfsFieldModel == null || wfsFieldModel.getFields() == null) { - return cqlFilter.toString(); - } - - List fields = wfsFieldModel.getFields(); - - // Possible to have multiple days, better to consider all - List temporalField = fields.stream() - .filter(field -> "dateTime".equals(field.getType()) || "date".equals(field.getType())) - .toList(); - - // Add temporal filter only if both dates are specified - if (!temporalField.isEmpty() && startDate != null && !startDate.isEmpty() && endDate != null && !endDate.isEmpty()) { - List cqls = new ArrayList<>(); - temporalField.forEach(temp -> - cqls.add(String.format("(%s DURING %sT00:00:00Z/%sT23:59:59Z)", temp.getName(), startDate, endDate)) - ); - cqlFilter.append("(").append(String.join(" OR ", cqls)).append(")"); - } - - // Find geometry field - Optional geometryField = fields.stream() - .filter(field -> "geometrypropertytype".equalsIgnoreCase(field.getType())) - .findFirst(); - - // Add spatial filter - if (geometryField.isPresent() && multiPolygon != null) { - String fieldName = geometryField.get().getName(); - - String wkt = GeometryUtils.convertToWkt(multiPolygon); - - if ((wkt != null) && !cqlFilter.isEmpty()) { - cqlFilter.append(" AND "); - } - - if (wkt != null) { - cqlFilter.append("INTERSECTS(") - .append(fieldName) - .append(",") - .append(wkt) - .append(")"); - } - } - - return cqlFilter.toString(); - } - /** * Does collection lookup, WFS validation, field retrieval, and URL building */ @@ -104,46 +46,30 @@ public String prepareWfsRequestUrl( String layerName, String outputFormat) { - String wfsServerUrl; - String wfsTypeName; - WfsFields wfsFieldModel; // Get WFS server URL and field model for the given UUID and layer name Optional featureServerUrl = wfsServer.getFeatureServerUrl(uuid, layerName); // Get the wfs fields to build the CQL filter if (featureServerUrl.isPresent()) { - wfsServerUrl = featureServerUrl.get(); - wfsTypeName = layerName; - wfsFieldModel = wfsServer.getDownloadableFields( - uuid, - WfsServer.WfsFeatureRequest.builder() - .layerName(wfsTypeName) - .server(wfsServerUrl) - .build() - ); - log.debug("WFSFieldModel by wfs typename: {}", wfsFieldModel); - } else { - throw new IllegalArgumentException("No WFS server URL found for the given UUID and layer name"); - } - - // Validate start and end dates - String validStartDate = DatetimeUtils.validateAndFormatDate(startDate, true); - String validEndDate = DatetimeUtils.validateAndFormatDate(endDate, false); + String wfsServerUrl = featureServerUrl.get(); - // Build CQL filter - String cqlFilter = buildCqlFilter(validStartDate, validEndDate, multiPolygon, wfsFieldModel); + // Build CQL filter + String cqlFilter = buildCqlFilter(wfsServerUrl, uuid, layerName, startDate, endDate, multiPolygon); - // Build final WFS request URL - String wfsRequestUrl = wfsServer.createWfsRequestUrl( - wfsServerUrl, - wfsTypeName, - fields, - cqlFilter, - outputFormat); + // Build final WFS request URL + String wfsRequestUrl = wfsServer.createWfsRequestUrl( + wfsServerUrl, + layerName, + fields, + cqlFilter, + outputFormat); - log.info("Prepared WFS request URL: {}", wfsRequestUrl); - return wfsRequestUrl; + log.info("Prepared WFS request URL: {}", wfsRequestUrl); + return wfsRequestUrl; + } else { + throw new IllegalArgumentException("No WFS server URL found for the given UUID and layer name"); + } } /**