From 5865ff1df44626955e2d6f29e3fdce9ee023e2f0 Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Tue, 19 May 2026 15:59:36 +1000 Subject: [PATCH 01/11] use stacmodel LinkModel --- pom.xml | 323 +++++++++--------- .../server/core/model/ContactModel.java | 1 + .../ogcapi/server/core/model/LinkModel.java | 2 +- .../core/model/StacCollectionModel.java | 2 + .../server/core/model/StacItemModel.java | 1 + .../core/service/ElasticSearchBase.java | 21 +- .../core/service/geoserver/wfs/WfsServer.java | 13 +- .../core/service/geoserver/wms/WmsServer.java | 2 +- .../server/core/util/GeoserverUtils.java | 2 +- .../ogcapi/server/core/util/LinkUtils.java | 18 + .../core/mapper/StacToCollectionTest.java | 2 + .../service/geoserver/wfs/WfsServerTest.java | 2 +- .../service/geoserver/wms/WmsServerTest.java | 2 +- .../server/core/util/LinkUtilsTest.java | 40 +++ 14 files changed, 258 insertions(+), 173 deletions(-) diff --git a/pom.xml b/pom.xml index 727f2764..90c4039f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,110 +1,110 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.5.14 - - - au.org.aodn.ogcapi - ogcapi-java - 0.0.0 - ogcapi-java - pom + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.5.14 + + + au.org.aodn.ogcapi + ogcapi-java + 0.0.0 + ogcapi-java + pom - REST API that implements OGC API - - 17 - 3.0.0 - 1.5.5.Final - 1.18.30 - 0.2.0 - 3.0.69 - 29.6 - true - true - 2.29.52 - - - - mvnrepository.com - https://repo1.maven.org/maven2/ - - - repo.osgeo.org - https://repo.osgeo.org/repository/release/ - - - codeartifact - ${env.CODEARTIFACT_REPO_URL} - - - - common - coverages - features - maps - processes - tile - records - server + REST API that implements OGC API + + 17 + 3.0.0 + 1.5.5.Final + 1.18.30 + 0.2.0 + 3.0.69 + 29.6 + true + true + 2.29.52 + + + + mvnrepository.com + https://repo1.maven.org/maven2/ + + + repo.osgeo.org + https://repo.osgeo.org/repository/release/ + + + codeartifact + ${env.CODEARTIFACT_REPO_URL} + + + + common + coverages + features + maps + processes + tile + records + server - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - 2.8.17 - - - com.github.joschi.jackson - jackson-datatype-threetenbp - 2.6.4 - - - - co.elastic.clients - elasticsearch-java - 8.19.10 - - - org.mapstruct - mapstruct - ${org.mapstruct.version} - - - org.mapstruct - mapstruct-processor - ${org.mapstruct.version} - - - org.projectlombok - lombok - ${org.projectlombok.version} - - - org.projectlombok - lombok-mapstruct-binding - ${org.projectlombok.binding} - - - - org.geotools - gt-cql - ${org.geotools.version} - - - org.geotools - gt-geojson - ${org.geotools.version} - - - org.geotools - gt-referencing - ${org.geotools.version} - + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.8.17 + + + com.github.joschi.jackson + jackson-datatype-threetenbp + 2.6.4 + + + + co.elastic.clients + elasticsearch-java + 8.19.10 + + + org.mapstruct + mapstruct + ${org.mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + org.projectlombok + lombok + ${org.projectlombok.version} + + + org.projectlombok + lombok-mapstruct-binding + ${org.projectlombok.binding} + + + + org.geotools + gt-cql + ${org.geotools.version} + + + org.geotools + gt-geojson + ${org.geotools.version} + + + org.geotools + gt-referencing + ${org.geotools.version} + org.geotools gt-wfs-ng @@ -115,20 +115,20 @@ gt-xml ${org.geotools.version} - - - org.geotools - gt-epsg-hsql - 22.2 - - - org.openapitools - jackson-databind-nullable - 0.2.6 - + + + org.geotools + gt-epsg-hsql + 22.2 + + + org.openapitools + jackson-databind-nullable + 0.2.6 + org.testcontainers testcontainers-bom @@ -153,50 +153,51 @@ cache-api 1.1.1 - - org.mock-server - mockserver-netty - 5.15.0 - - - org.mock-server - mockserver-client-java - 5.15.0 - - - org.locationtech.spatial4j - spatial4j - 0.8 - - - software.amazon.awssdk - batch - ${aws.sdk.version} - - - software.amazon.awssdk - auth - ${aws.sdk.version} - - - software.amazon.awssdk - ses - ${aws.sdk.version} - - - - org.apache.logging.log4j - log4j-layout-template-json - 2.24.3 - - - au.org.aodn - stacmodel - 0.0.56 - - - - + + org.mock-server + mockserver-netty + 5.15.0 + + + org.mock-server + mockserver-client-java + 5.15.0 + + + org.locationtech.spatial4j + spatial4j + 0.8 + + + software.amazon.awssdk + batch + ${aws.sdk.version} + + + software.amazon.awssdk + auth + ${aws.sdk.version} + + + software.amazon.awssdk + ses + ${aws.sdk.version} + + + + org.apache.logging.log4j + log4j-layout-template-json + 2.24.3 + + + au.org.aodn + stacmodel + bugfix-8455-update-stacmodels-SNAPSHOT + + + + + codeartifact codeartifact diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ContactModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ContactModel.java index ce1c3718..28ba6534 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ContactModel.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ContactModel.java @@ -1,5 +1,6 @@ package au.org.aodn.ogcapi.server.core.model; +import au.org.aodn.stac.model.LinkModel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/LinkModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/LinkModel.java index 17533bdf..5ba6507a 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/LinkModel.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/LinkModel.java @@ -36,4 +36,4 @@ public void setTitle(String title) { this.description = parsed[1]; } } -} +} \ No newline at end of file diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java index f69fb996..da4845ae 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java @@ -1,5 +1,7 @@ package au.org.aodn.ogcapi.server.core.model; +import au.org.aodn.stac.model.LinkModel; +import au.org.aodn.stac.model.SummariesModel; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java index ebc19375..37ed9af6 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java @@ -2,6 +2,7 @@ import au.org.aodn.ogcapi.features.model.FeatureCollectionGeoJSON; import au.org.aodn.ogcapi.features.model.FeatureGeoJSON; +import au.org.aodn.stac.model.LinkModel; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearchBase.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearchBase.java index 6bbc6850..7432cbf2 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearchBase.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearchBase.java @@ -5,6 +5,7 @@ import au.org.aodn.ogcapi.server.core.model.enumeration.CQLFieldsInterface; import au.org.aodn.ogcapi.server.core.model.enumeration.StacBasicField; import au.org.aodn.ogcapi.server.core.model.enumeration.StacSummeries; +import au.org.aodn.ogcapi.server.core.util.LinkUtils; import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch._types.*; import co.elastic.clients.elasticsearch._types.aggregations.*; @@ -562,7 +563,9 @@ protected StacCollectionModel formatResult(ObjectNode nodes) { try { if(nodes != null) { String json = nodes.toString(); - return mapper.readValue(json, StacCollectionModel.class); + StacCollectionModel result = mapper.readValue(json, StacCollectionModel.class); + fixupPackedLinkTitles(result); + return result; } else { log.error("Failed to serialize text to StacCollectionModel"); @@ -574,4 +577,20 @@ protected StacCollectionModel formatResult(ObjectNode nodes) { return null; } } + + private static void fixupPackedLinkTitles(StacCollectionModel collection) { + if (collection == null) { + return; + } + if (collection.getLinks() != null) { + collection.getLinks().forEach(LinkUtils::applyParsedTitle); + } + if (collection.getContacts() != null) { + collection.getContacts().forEach(contact -> { + if (contact != null && contact.getLinks() != null) { + contact.getLinks().forEach(LinkUtils::applyParsedTitle); + } + }); + } + } } diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServer.java index 841c9dce..7e2b002e 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServer.java @@ -2,8 +2,8 @@ import au.org.aodn.ogcapi.server.core.exception.GeoserverFieldsNotFoundException; import au.org.aodn.ogcapi.server.core.exception.GeoserverLayersNotFoundException; -import au.org.aodn.ogcapi.server.core.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest; import au.org.aodn.ogcapi.server.core.model.ogc.wfs.*; import au.org.aodn.ogcapi.server.core.service.ElasticSearchBase; @@ -82,6 +82,7 @@ public WfsServer(Search search, this.pretendUserEntity = entity; this.wfsDefaultParam = wfsDefaultParam; } + /** * Build CQL filter for temporal and spatial constraints */ @@ -145,6 +146,7 @@ public String buildCqlFilter(String uuid, WfsFeatureRequest featureRequest) { return cqlFilter.toString(); } + /** * Build WFS GetFeature URL */ @@ -164,17 +166,16 @@ protected String createWfsRequestUrl(String wfsUrl, String layerName, List 0) { + if (maxRecordNum > 0) { param.put("maxFeatures", String.valueOf(maxRecordNum)); } diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServer.java index e2aea30a..0beac398 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServer.java @@ -2,8 +2,8 @@ import au.org.aodn.ogcapi.server.core.exception.GeoserverFieldsNotFoundException; import au.org.aodn.ogcapi.server.core.exception.GeoserverLayersNotFoundException; -import au.org.aodn.ogcapi.server.core.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.LinkModel; 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; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/util/GeoserverUtils.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/util/GeoserverUtils.java index 2c026aac..30cac27e 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/util/GeoserverUtils.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/util/GeoserverUtils.java @@ -1,6 +1,6 @@ package au.org.aodn.ogcapi.server.core.util; -import au.org.aodn.ogcapi.server.core.model.LinkModel; +import au.org.aodn.stac.model.LinkModel; import lombok.extern.slf4j.Slf4j; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriUtils; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/util/LinkUtils.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/util/LinkUtils.java index 30a8d0f1..37f6adb0 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/util/LinkUtils.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/util/LinkUtils.java @@ -1,10 +1,28 @@ package au.org.aodn.ogcapi.server.core.util; +import au.org.aodn.stac.model.LinkModel; + import static au.org.aodn.ogcapi.server.core.util.ConstructUtils.constructByJsonString; public class LinkUtils { record TitleWithDescription(String title, String description) {} + /** + * The shared {@link LinkModel} from the {@code stacmodel} artifact ships with a plain Lombok + * {@code setTitle}. Some indexed documents pack {"title": ..., "description": ...} into the + * single title field, so call this after deserialization to split them back out. + */ + public static void applyParsedTitle(LinkModel link) { + if (link == null) { + return; + } + String[] parsed = parseLinkTitleDescription(link.getTitle()); + link.setTitle(parsed[0]); + if (link.getDescription() == null && parsed[1] != null) { + link.setDescription(parsed[1]); + } + } + public static String[] parseLinkTitleDescription(String combinedTitle) { // if combinedTitle is null or empty, return null for both title and description if (combinedTitle == null || combinedTitle.trim().isEmpty()) { diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java index 5f258421..6e79749d 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java @@ -4,6 +4,8 @@ import au.org.aodn.ogcapi.server.core.configuration.TestConfig; import au.org.aodn.ogcapi.server.core.model.*; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType; +import au.org.aodn.stac.model.LinkModel; +import au.org.aodn.stac.model.SummariesModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CollectionProperty; import au.org.aodn.ogcapi.server.core.parser.stac.CQLToStacFilterFactory; import au.org.aodn.ogcapi.server.core.service.ElasticSearch; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServerTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServerTest.java index 87f4aa15..a3a6810b 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServerTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServerTest.java @@ -1,8 +1,8 @@ package au.org.aodn.ogcapi.server.core.service.geoserver.wfs; import au.org.aodn.ogcapi.server.core.exception.GeoserverFieldsNotFoundException; -import au.org.aodn.ogcapi.server.core.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest; import au.org.aodn.ogcapi.server.core.model.ogc.wfs.FeatureTypeInfo; import au.org.aodn.ogcapi.server.core.model.ogc.wfs.WfsField; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServerTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServerTest.java index f3d4c8ec..d9736c19 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServerTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServerTest.java @@ -5,8 +5,8 @@ import au.org.aodn.ogcapi.server.core.configuration.TestConfig; import au.org.aodn.ogcapi.server.core.configuration.GeoServerConfig; import au.org.aodn.ogcapi.server.core.exception.GeoserverFieldsNotFoundException; -import au.org.aodn.ogcapi.server.core.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest; import au.org.aodn.ogcapi.server.core.model.ogc.wms.DescribeLayerResponse; import au.org.aodn.ogcapi.server.core.service.ElasticSearchBase; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/util/LinkUtilsTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/LinkUtilsTest.java index 4b07fe4d..8a33e9b4 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/util/LinkUtilsTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/LinkUtilsTest.java @@ -1,5 +1,6 @@ package au.org.aodn.ogcapi.server.core.util; +import au.org.aodn.stac.model.LinkModel; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -67,4 +68,43 @@ void testParseLinkTitleDescription_titleWithAbstract() { assertEquals(combinedTitle, result[0]); assertNull(result[1]); } + + @Test + void testApplyParsedTitle_splitsPackedTitle() { + LinkModel link = new LinkModel(); + link.setTitle("{\"title\":\"foo\",\"description\":\"bar\"}"); + + LinkUtils.applyParsedTitle(link); + + assertEquals("foo", link.getTitle()); + assertEquals("bar", link.getDescription()); + } + + @Test + void testApplyParsedTitle_preservesExistingDescription() { + LinkModel link = new LinkModel(); + link.setDescription("existing"); + link.setTitle("{\"title\":\"foo\",\"description\":\"bar\"}"); + + LinkUtils.applyParsedTitle(link); + + assertEquals("foo", link.getTitle()); + assertEquals("existing", link.getDescription()); + } + + @Test + void testApplyParsedTitle_plainTitlePassesThrough() { + LinkModel link = new LinkModel(); + link.setTitle("Just a title"); + + LinkUtils.applyParsedTitle(link); + + assertEquals("Just a title", link.getTitle()); + assertNull(link.getDescription()); + } + + @Test + void testApplyParsedTitle_nullLinkIsNoop() { + assertDoesNotThrow(() -> LinkUtils.applyParsedTitle(null)); + } } From 9a47d5b0bbbf1b045e5dfde2ec7449eac828930c Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Mon, 25 May 2026 22:51:27 +1000 Subject: [PATCH 02/11] update ContactsModel --- pom.xml | 2 +- .../ogcapi/server/core/model/StacCollectionModel.java | 3 ++- .../server/core/mapper/StacToCollectionTest.java | 11 +++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 90c4039f..b3fda17d 100644 --- a/pom.xml +++ b/pom.xml @@ -192,7 +192,7 @@ au.org.aodn stacmodel - bugfix-8455-update-stacmodels-SNAPSHOT + feature-8455-update-stacmodel-2-SNAPSHOT diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java index da4845ae..55205979 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java @@ -1,5 +1,6 @@ package au.org.aodn.ogcapi.server.core.model; +import au.org.aodn.stac.model.ContactsModel; import au.org.aodn.stac.model.LinkModel; import au.org.aodn.stac.model.SummariesModel; import com.fasterxml.jackson.annotation.JsonProperty; @@ -22,7 +23,7 @@ public class StacCollectionModel { protected ExtentModel extent; protected SummariesModel summaries; protected List links; - protected List contacts; + protected List contacts; protected List themes; protected String license; protected Map assets; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java index 6e79749d..a6c6bfcb 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java @@ -4,6 +4,9 @@ import au.org.aodn.ogcapi.server.core.configuration.TestConfig; import au.org.aodn.ogcapi.server.core.model.*; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType; +import au.org.aodn.stac.model.ContactsAddressModel; +import au.org.aodn.stac.model.ContactsModel; +import au.org.aodn.stac.model.ContactsPhoneModel; import au.org.aodn.stac.model.LinkModel; import au.org.aodn.stac.model.SummariesModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CollectionProperty; @@ -57,7 +60,7 @@ public void verifyAddingPropertyWorks() { StacToCollection stacToCollection = new StacToCollectionImpl(); List credits = Arrays.asList("credit1", "credit2"); - var address = AddressModel.builder() + var address = ContactsAddressModel.builder() .city("city") .country("country") .postalCode("postalCode") @@ -65,15 +68,15 @@ public void verifyAddingPropertyWorks() { .deliveryPoint(Arrays.asList("deliveryPoint1", "deliveryPoint2")) .build(); var link = LinkModel.builder().rel("rel").href("href").type("type").title("title").build(); - var contact = ContactModel.builder() + var contact = ContactsModel.builder() .addresses(Collections.singletonList(address)) .name("name") .organization("organization") .roles(Collections.singletonList("roles")) .emails(Arrays.asList("email1", "email2")) .links(Collections.singletonList(link)) - .phones(Collections.singletonList(InfoModel.builder().value("value").build()) - ).build(); + .phones(Collections.singletonList(ContactsPhoneModel.builder().value("value").build())) + .build(); var link1 = LinkModel.builder() .rel("related") .href("https://example.com/data") From 2b903560d33f62851df1b994580114eb0fff3a17 Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Mon, 25 May 2026 23:35:02 +1000 Subject: [PATCH 03/11] update other stac models --- .../ogcapi/server/core/mapper/Converter.java | 4 +- .../ogcapi/server/core/model/AssetModel.java | 53 ----------------- .../server/core/model/CitationModel.java | 16 ------ .../server/core/model/ConceptModel.java | 23 -------- .../server/core/model/LicenseModel.java | 14 ----- .../core/model/StacCollectionModel.java | 4 +- .../server/core/model/StacItemModel.java | 1 + .../server/core/model/SummariesModel.java | 57 ------------------- .../ogcapi/server/core/model/ThemeModel.java | 23 -------- .../core/mapper/StacToCollectionTest.java | 10 +++- 10 files changed, 13 insertions(+), 192 deletions(-) delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/AssetModel.java delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/CitationModel.java delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/ConceptModel.java delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/LicenseModel.java delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/SummariesModel.java delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/ThemeModel.java diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java index d5d5713d..843d09f5 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java @@ -1,7 +1,6 @@ package au.org.aodn.ogcapi.server.core.mapper; import au.org.aodn.ogcapi.features.model.*; -import au.org.aodn.ogcapi.server.core.model.CitationModel; import au.org.aodn.ogcapi.server.core.model.ExtendedCollection; import au.org.aodn.ogcapi.server.core.model.ExtendedLink; import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; @@ -10,6 +9,7 @@ import au.org.aodn.ogcapi.server.core.parser.stac.GeometryVisitor; import au.org.aodn.ogcapi.server.core.util.ConstructUtils; import au.org.aodn.ogcapi.server.core.util.GeometryUtils; +import au.org.aodn.stac.model.Citation; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -144,7 +144,7 @@ default Collection getCollection(D m, Filter fil } if (m.getCitation() != null && !m.getCitation().isEmpty()) { - ConstructUtils.constructByJsonString(m.getCitation(), CitationModel.class).ifPresent( + ConstructUtils.constructByJsonString(m.getCitation(), Citation.class).ifPresent( citation -> collection.getProperties().put(CollectionProperty.citation, citation) ); } diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/AssetModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/AssetModel.java deleted file mode 100644 index cb99a03f..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/AssetModel.java +++ /dev/null @@ -1,53 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@JsonInclude(JsonInclude.Include.NON_NULL) -public class AssetModel { - // https://github.com/radiantearth/stac-spec/blob/master/best-practices.md#list-of-asset-roles - public enum Role { - DATA("data"), - METADATA("metadata"), - THUMBNAIL("thumbnail"), - SUMMARY("summary"), - OVERVIEW("overview"), - VISUAL("visual"), - DATE("date"), - GRAPHIC("graphic"), - DATA_MASK("data-mask"), - SNOW_ICE("snow-ice"), - LAND_WATER("land-water"), - WATER_MASK("water-mask"), - ISO_19115("iso-19115"); - - private final String role; - - Role(String role) { - this.role = role; - } - - @Override - public String toString() { - return role; - } - } - /** - * REQUIRED. URI to the asset object. Relative and absolute URI are both allowed. Trailing slashes are significant. - */ - protected String href; - protected String title; - protected String description; - protected String type; - /** - * The semantic roles of the asset, similar to the use of rel in links. - */ - protected Role role; -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/CitationModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/CitationModel.java deleted file mode 100644 index 42a85128..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/CitationModel.java +++ /dev/null @@ -1,16 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import lombok.Builder; -import lombok.Data; - -import java.util.List; - -@Data -@Builder -public class CitationModel { - - protected String suggestedCitation; - protected List useLimitations; - protected List otherConstraints; - -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ConceptModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ConceptModel.java deleted file mode 100644 index 5706898f..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ConceptModel.java +++ /dev/null @@ -1,23 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ConceptModel { - protected String id; - protected String url; - protected String description; - protected String title; - - @JsonInclude(JsonInclude.Include.NON_NULL) - @JsonProperty("ai:description") - protected String aiDescription; -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/LicenseModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/LicenseModel.java deleted file mode 100644 index 91182521..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/LicenseModel.java +++ /dev/null @@ -1,14 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import lombok.Builder; -import lombok.Data; - -@Data -@Builder -public class LicenseModel { - - protected String title; - protected String url; - protected String licenseGraphic; - -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java index 55205979..5a230011 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java @@ -1,8 +1,10 @@ package au.org.aodn.ogcapi.server.core.model; +import au.org.aodn.stac.model.AssetModel; import au.org.aodn.stac.model.ContactsModel; import au.org.aodn.stac.model.LinkModel; import au.org.aodn.stac.model.SummariesModel; +import au.org.aodn.stac.model.ThemesModel; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; @@ -24,7 +26,7 @@ public class StacCollectionModel { protected SummariesModel summaries; protected List links; protected List contacts; - protected List themes; + protected List themes; protected String license; protected Map assets; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java index 37ed9af6..da6fae92 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java @@ -2,6 +2,7 @@ import au.org.aodn.ogcapi.features.model.FeatureCollectionGeoJSON; import au.org.aodn.ogcapi.features.model.FeatureGeoJSON; +import au.org.aodn.stac.model.AssetModel; import au.org.aodn.stac.model.LinkModel; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/SummariesModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/SummariesModel.java deleted file mode 100644 index ca593054..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/SummariesModel.java +++ /dev/null @@ -1,57 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@JsonInclude(JsonInclude.Include.NON_NULL) -public class SummariesModel { - // Do not create constructor, it will create by lombook, you can use builder() to create object. - protected int score; - protected String status; - protected List credits; - protected String creation; - protected String revision; - - @JsonProperty("proj:geometry") - protected Map geometry; - - @JsonProperty("proj:geometry_noland") - protected Map geometryNoLand; - - @JsonProperty("temporal") - protected List> temporal; - - @JsonProperty("update_frequency") - protected String updateFrequency; - - @JsonProperty("dataset_group") - protected List datasetGroup; - - @JsonProperty("ai:description") - protected String aiDescription; - - @JsonProperty("ai:update_frequency") - protected String aiUpdateFrequency; - - @JsonProperty("scope") - protected Map scope; - - protected String statement; - - @JsonProperty("parameter_vocabs") - protected List parameterVocabs; - - @JsonProperty("ai:parameter_vocabs") - protected List aiParameterVocabs; -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ThemeModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ThemeModel.java deleted file mode 100644 index 9b22ff1e..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ThemeModel.java +++ /dev/null @@ -1,23 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import au.org.aodn.stac.model.Citation; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import java.util.List; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ThemeModel { - protected String scheme; - protected List concepts; - - // This is just a test to make sure the stac model can be used in this module, we can remove it when all the stac models are using the stacmodel from es-indexer - private void testStacmodelReference() { - Citation citation = Citation.builder().build(); - } - -} diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java index a6c6bfcb..4fed2eb5 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java @@ -4,11 +4,15 @@ import au.org.aodn.ogcapi.server.core.configuration.TestConfig; import au.org.aodn.ogcapi.server.core.model.*; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType; +import au.org.aodn.stac.model.AssetModel; +import au.org.aodn.stac.model.Citation; +import au.org.aodn.stac.model.ConceptModel; import au.org.aodn.stac.model.ContactsAddressModel; import au.org.aodn.stac.model.ContactsModel; import au.org.aodn.stac.model.ContactsPhoneModel; import au.org.aodn.stac.model.LinkModel; import au.org.aodn.stac.model.SummariesModel; +import au.org.aodn.stac.model.ThemesModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CollectionProperty; import au.org.aodn.ogcapi.server.core.parser.stac.CQLToStacFilterFactory; import au.org.aodn.ogcapi.server.core.service.ElasticSearch; @@ -94,7 +98,7 @@ public void verifyAddingPropertyWorks() { .aiGroup("ai-group") .description("description") .build(); - var theme = ThemeModel.builder() + var theme = ThemesModel.builder() .scheme("scheme") .concepts(Collections.singletonList( ConceptModel.builder().id("id").url("url").description("description").title("title").build() @@ -150,8 +154,8 @@ public void verifyAddingPropertyWorks() { Assertions.assertEquals(credits, collection.getProperties().get(CollectionProperty.credits)); Assertions.assertEquals(Collections.singletonList(contact), collection.getProperties().get(CollectionProperty.contacts)); Assertions.assertEquals(Collections.singletonList(theme), collection.getProperties().get(CollectionProperty.themes)); - Assertions.assertInstanceOf(CitationModel.class, collection.getProperties().get(CollectionProperty.citation)); - var citationToCheck = (CitationModel) collection.getProperties().get(CollectionProperty.citation); + Assertions.assertInstanceOf(Citation.class, collection.getProperties().get(CollectionProperty.citation)); + var citationToCheck = (Citation) collection.getProperties().get(CollectionProperty.citation); Assertions.assertEquals("this is suggested Citation", citationToCheck.getSuggestedCitation()); Assertions.assertEquals(Arrays.asList("this is useLimitations1", "this is useLimitations2"), citationToCheck.getUseLimitations()); Assertions.assertEquals(Arrays.asList("this is otherConstraints1", "this is otherConstraints2"), citationToCheck.getOtherConstraints()); From dbb7bde5505963ddab0c2134c0b869ba32d21208 Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Mon, 25 May 2026 23:54:14 +1000 Subject: [PATCH 04/11] update ExtentModel --- .../ogcapi/server/core/mapper/Converter.java | 24 ++++++++++++++++++- .../ogcapi/server/core/model/ExtentModel.java | 23 ------------------ .../core/model/StacCollectionModel.java | 1 + .../core/mapper/StacToCollectionTest.java | 1 + 4 files changed, 25 insertions(+), 24 deletions(-) delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/ExtentModel.java diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java index 843d09f5..b7fa6135 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java @@ -20,7 +20,10 @@ import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; +import java.time.Instant; import java.util.ArrayList; +import java.util.Date; +import java.util.List; import java.util.Map; import static au.org.aodn.ogcapi.server.core.util.GeometryUtils.createCentroid; @@ -42,6 +45,25 @@ class Param { T convert(F from, Filter param); + private static List> parseTemporal(List> raw) { + if (raw == null) { + return null; + } + List> out = new ArrayList<>(raw.size()); + for (List inner : raw) { + if (inner == null) { + out.add(null); + continue; + } + List innerOut = new ArrayList<>(inner.size()); + for (String s : inner) { + innerOut.add(s == null ? null : Date.from(Instant.parse(s))); + } + out.add(innerOut); + } + return out; + } + default au.org.aodn.ogcapi.features.model.Link getSelfCollectionLink(String hostname, String id) { au.org.aodn.ogcapi.features.model.Link self = new au.org.aodn.ogcapi.features.model.Link(); @@ -100,7 +122,7 @@ default Collection getCollection(D m, Filter fil } extent.setTemporal(new ExtentTemporal()); - extent.getTemporal().interval(m.getExtent().getTemporal()); + extent.getTemporal().interval(parseTemporal(m.getExtent().getTemporal())); collection.setExtent(extent); } diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ExtentModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ExtentModel.java deleted file mode 100644 index 52d04289..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ExtentModel.java +++ /dev/null @@ -1,23 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Builder; -import lombok.Data; - -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - -@Data -@Builder -public class ExtentModel { - protected List> bbox; - protected List> temporal; - - @JsonCreator - public ExtentModel(@JsonProperty("bbox") List> bbox, @JsonProperty("temporal") List> temporal) { - this.temporal = temporal; - this.bbox = bbox; - } -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java index 5a230011..d04b202d 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java @@ -2,6 +2,7 @@ import au.org.aodn.stac.model.AssetModel; import au.org.aodn.stac.model.ContactsModel; +import au.org.aodn.stac.model.ExtentModel; import au.org.aodn.stac.model.LinkModel; import au.org.aodn.stac.model.SummariesModel; import au.org.aodn.stac.model.ThemesModel; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java index 4fed2eb5..d18e2748 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java @@ -10,6 +10,7 @@ import au.org.aodn.stac.model.ContactsAddressModel; import au.org.aodn.stac.model.ContactsModel; import au.org.aodn.stac.model.ContactsPhoneModel; +import au.org.aodn.stac.model.ExtentModel; import au.org.aodn.stac.model.LinkModel; import au.org.aodn.stac.model.SummariesModel; import au.org.aodn.stac.model.ThemesModel; From 1bae6a1658d1d54cf46bc7f12231b7bdc50dbc57 Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Tue, 26 May 2026 10:14:57 +1000 Subject: [PATCH 05/11] update StacCollectionModel and StacItemModel --- .../ogcapi/server/core/mapper/Converter.java | 2 +- .../server/core/mapper/StacToCollection.java | 2 +- .../server/core/mapper/StacToCollections.java | 2 +- .../core/mapper/StacToFeatureCollection.java | 2 +- .../core/mapper/StacToInlineResponse2002.java | 2 +- .../core/mapper/StacToTileSetWmWGS84Q.java | 2 +- .../server/core/model/DataSearchResult.java | 1 + .../core/model/StacCollectionModel.java | 49 ------------ .../server/core/model/StacItemModel.java | 78 ------------------- .../core/service/CacheNoLandGeometry.java | 2 +- .../ogcapi/server/core/service/CacheWarm.java | 2 +- .../server/core/service/ElasticSearch.java | 2 +- .../core/service/ElasticSearchBase.java | 2 +- .../server/core/service/OGCApiService.java | 2 +- .../ogcapi/server/core/service/Search.java | 2 +- .../core/service/geoserver/wfs/WfsServer.java | 2 +- .../core/service/geoserver/wms/WmsServer.java | 2 +- .../ogcapi/server/features/RestServices.java | 2 +- .../core/mapper/StacToCollectionTest.java | 1 + .../server/core/parser/stac/ParserTest.java | 2 +- .../service/geoserver/wfs/WfsServerTest.java | 2 +- .../service/geoserver/wms/WmsServerTest.java | 2 +- 22 files changed, 20 insertions(+), 145 deletions(-) delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java index b7fa6135..9fb53457 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java @@ -3,7 +3,7 @@ import au.org.aodn.ogcapi.features.model.*; import au.org.aodn.ogcapi.server.core.model.ExtendedCollection; import au.org.aodn.ogcapi.server.core.model.ExtendedLink; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType; import au.org.aodn.ogcapi.server.core.model.enumeration.CollectionProperty; import au.org.aodn.ogcapi.server.core.parser.stac.GeometryVisitor; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollection.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollection.java index e14689ee..09214172 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollection.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollection.java @@ -1,7 +1,7 @@ package au.org.aodn.ogcapi.server.core.mapper; import au.org.aodn.ogcapi.features.model.Collection; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import org.mapstruct.Mapper; import org.opengis.filter.Filter; import org.springframework.beans.factory.annotation.Value; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollections.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollections.java index cb0f2b77..435b7800 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollections.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollections.java @@ -3,7 +3,7 @@ import au.org.aodn.ogcapi.features.model.Collection; import au.org.aodn.ogcapi.features.model.Collections; import au.org.aodn.ogcapi.server.core.model.ExtendedCollections; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.service.ElasticSearch; import org.mapstruct.Mapper; import org.opengis.filter.Filter; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToFeatureCollection.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToFeatureCollection.java index ad204b1c..378c4e38 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToFeatureCollection.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToFeatureCollection.java @@ -3,7 +3,7 @@ import au.org.aodn.ogcapi.features.model.FeatureCollectionGeoJSON; import au.org.aodn.ogcapi.features.model.FeatureGeoJSON; import au.org.aodn.ogcapi.features.model.PointGeoJSON; -import au.org.aodn.ogcapi.server.core.model.StacItemModel; +import au.org.aodn.stac.model.StacItemModel; import au.org.aodn.ogcapi.server.core.service.ElasticSearch; import org.mapstruct.Mapper; import org.openapitools.jackson.nullable.JsonNullable; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToInlineResponse2002.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToInlineResponse2002.java index af55aefc..a3f1684e 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToInlineResponse2002.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToInlineResponse2002.java @@ -1,6 +1,6 @@ package au.org.aodn.ogcapi.server.core.mapper; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType; import au.org.aodn.ogcapi.server.core.service.ElasticSearch; import au.org.aodn.ogcapi.tile.model.InlineResponse2002; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToTileSetWmWGS84Q.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToTileSetWmWGS84Q.java index deeaddcb..0df6ce0f 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToTileSetWmWGS84Q.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/StacToTileSetWmWGS84Q.java @@ -1,6 +1,6 @@ package au.org.aodn.ogcapi.server.core.mapper; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType; import au.org.aodn.ogcapi.server.core.service.ElasticSearch; import au.org.aodn.ogcapi.tile.model.TileSet; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/DataSearchResult.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/DataSearchResult.java index 7bd9427c..d43f1941 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/DataSearchResult.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/DataSearchResult.java @@ -4,6 +4,7 @@ import au.org.aodn.ogcapi.features.model.FeatureGeoJSON; import au.org.aodn.ogcapi.features.model.PointGeoJSON; import au.org.aodn.ogcapi.server.core.model.enumeration.FeatureProperty; +import au.org.aodn.stac.model.StacItemModel; import au.org.aodn.ogcapi.server.core.util.DatasetSummarizer; import org.openapitools.jackson.nullable.JsonNullable; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java deleted file mode 100644 index d04b202d..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacCollectionModel.java +++ /dev/null @@ -1,49 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import au.org.aodn.stac.model.AssetModel; -import au.org.aodn.stac.model.ContactsModel; -import au.org.aodn.stac.model.ExtentModel; -import au.org.aodn.stac.model.LinkModel; -import au.org.aodn.stac.model.SummariesModel; -import au.org.aodn.stac.model.ThemesModel; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.*; - -import java.util.List; -import java.util.Map; - -/** - * This is used to map the json from Elastic search to object - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class StacCollectionModel { - - protected String description; - protected String type; - protected ExtentModel extent; - protected SummariesModel summaries; - protected List links; - protected List contacts; - protected List themes; - protected String license; - protected Map assets; - - @JsonProperty("sci:citation") - protected String citation; - - @Getter - protected String title; - - @JsonProperty("id") - protected String uuid; - - @JsonProperty("stac_version") - protected String stacVersion; - - @JsonProperty("stac_extensions") - protected List stacExtensions; - -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java deleted file mode 100644 index da6fae92..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/StacItemModel.java +++ /dev/null @@ -1,78 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import au.org.aodn.ogcapi.features.model.FeatureCollectionGeoJSON; -import au.org.aodn.ogcapi.features.model.FeatureGeoJSON; -import au.org.aodn.stac.model.AssetModel; -import au.org.aodn.stac.model.LinkModel; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.math.BigDecimal; -import java.util.List; -import java.util.Map; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@JsonInclude(JsonInclude.Include.NON_NULL) -public class StacItemModel { - - @JsonProperty("type") - protected String type; - /** - * REQUIRED. Provider identifier. The ID should be unique within the Collection that contains the Item. - */ - @JsonProperty("id") - protected String uuid; - /** - * REQUIRED. Defines the full footprint of the asset represented by this item, formatted according to RFC 7946, - * section 3.1 if a geometry is provided or section 3.2 if no geometry is provided. - * Use to generate the vector tile, the STAC format is not optimized and hard to work with for Elastic search - */ - @JsonProperty("geometry") - protected Map geometry; - /** - * REQUIRED if geometry is not null, prohibited if geometry is null. Bounding Box of the asset represented by - * this Item, formatted according to RFC 7946, section 5. - */ - @JsonProperty("bbox") - protected List> bbox; - /** - * REQUIRED. A dictionary of additional metadata for the Item. - */ - @JsonProperty("properties") - protected Map properties; - /** - * REQUIRED. List of link objects to resources and related URLs. See the best practices for details on when the - * use self links is strongly recommended. - */ - protected List links; - - protected Map assets; - /** - * The id of the STAC Collection this Item references to. This field is required if a link with a collection relation type is present and is not allowed otherwise. - */ - @JsonProperty("collection") - protected String collection; - - @JsonProperty("stac_version") - protected String stacVersion; - - @JsonProperty("stac_extensions") - public String[] getStacExtension() { - return new String[] { - "https://stac-extensions.github.io/scientific/v1.0.0/schema.json", - "https://stac-extensions.github.io/contacts/v0.1.1/schema.json", - "https://stac-extensions.github.io/projection/v1.1.0/schema.json", - "https://stac-extensions.github.io/language/v1.0.0/schema.json", - "https://stac-extensions.github.io/themes/v1.0.0/schema.json", - "https://stac-extensions.github.io/web-map-links/v1.2.0/schema.json" - }; - } - -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheNoLandGeometry.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheNoLandGeometry.java index c032c0ac..ecb9e127 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheNoLandGeometry.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheNoLandGeometry.java @@ -1,6 +1,6 @@ package au.org.aodn.ogcapi.server.core.service; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLFields; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheWarm.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheWarm.java index 216dda46..4e052ffa 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheWarm.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheWarm.java @@ -1,6 +1,6 @@ package au.org.aodn.ogcapi.server.core.service; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.service.geoserver.wfs.WfsServer; import au.org.aodn.ogcapi.server.core.service.geoserver.wms.WmsServer; import au.org.aodn.ogcapi.server.core.util.GeometryUtils; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java index a484ef3a..9820aa95 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java @@ -2,7 +2,7 @@ import au.org.aodn.ogcapi.features.model.FeatureGeoJSON; import au.org.aodn.ogcapi.server.core.model.EsFeatureCollectionModel; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.SearchSuggestionsModel; import au.org.aodn.ogcapi.server.core.model.enumeration.*; import au.org.aodn.ogcapi.server.core.parser.elastic.CQLToElasticFilterFactory; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearchBase.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearchBase.java index 7432cbf2..cdc11561 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearchBase.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearchBase.java @@ -1,6 +1,6 @@ package au.org.aodn.ogcapi.server.core.service; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLFields; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLFieldsInterface; import au.org.aodn.ogcapi.server.core.model.enumeration.StacBasicField; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/OGCApiService.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/OGCApiService.java index 618a694d..3d88c439 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/OGCApiService.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/OGCApiService.java @@ -2,7 +2,7 @@ import au.org.aodn.ogcapi.features.model.FeatureCollectionGeoJSON; import au.org.aodn.ogcapi.server.core.exception.CustomException; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType; import au.org.aodn.ogcapi.server.core.model.enumeration.FeatureId; import au.org.aodn.ogcapi.server.core.model.enumeration.OGCMediaTypeMapper; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/Search.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/Search.java index 9420d2ad..e9f07379 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/Search.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/Search.java @@ -1,7 +1,7 @@ package au.org.aodn.ogcapi.server.core.service; import au.org.aodn.ogcapi.features.model.FeatureGeoJSON; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType; import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest; import co.elastic.clients.transport.endpoints.BinaryResponse; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServer.java index 7e2b002e..b735ed3e 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServer.java @@ -2,7 +2,7 @@ import au.org.aodn.ogcapi.server.core.exception.GeoserverFieldsNotFoundException; import au.org.aodn.ogcapi.server.core.exception.GeoserverLayersNotFoundException; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.stac.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest; import au.org.aodn.ogcapi.server.core.model.ogc.wfs.*; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServer.java index 0beac398..286374d0 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServer.java @@ -2,7 +2,7 @@ import au.org.aodn.ogcapi.server.core.exception.GeoserverFieldsNotFoundException; import au.org.aodn.ogcapi.server.core.exception.GeoserverLayersNotFoundException; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.stac.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest; import au.org.aodn.ogcapi.server.core.model.ogc.wfs.WfsField; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/features/RestServices.java b/server/src/main/java/au/org/aodn/ogcapi/server/features/RestServices.java index c1aa04a1..6ca11c74 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/features/RestServices.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/features/RestServices.java @@ -8,7 +8,7 @@ import au.org.aodn.ogcapi.server.core.model.ogc.wms.LayerInfo; import au.org.aodn.ogcapi.server.core.service.DasService; import au.org.aodn.ogcapi.server.core.mapper.StacToCollection; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.ogc.wfs.WfsFields; import au.org.aodn.ogcapi.server.core.service.ElasticSearch; import au.org.aodn.ogcapi.server.core.service.OGCApiService; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java index d18e2748..049c723d 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java @@ -12,6 +12,7 @@ import au.org.aodn.stac.model.ContactsPhoneModel; import au.org.aodn.stac.model.ExtentModel; import au.org.aodn.stac.model.LinkModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.stac.model.SummariesModel; import au.org.aodn.stac.model.ThemesModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CollectionProperty; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/parser/stac/ParserTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/parser/stac/ParserTest.java index 47812048..a1967aa9 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/parser/stac/ParserTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/parser/stac/ParserTest.java @@ -2,7 +2,7 @@ import au.org.aodn.ogcapi.server.BaseTestClass; import au.org.aodn.ogcapi.server.core.mapper.Converter; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType; import au.org.aodn.ogcapi.server.core.util.GeometryUtils; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServerTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServerTest.java index a3a6810b..88f67cd3 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServerTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServerTest.java @@ -1,7 +1,7 @@ package au.org.aodn.ogcapi.server.core.service.geoserver.wfs; import au.org.aodn.ogcapi.server.core.exception.GeoserverFieldsNotFoundException; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.stac.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest; import au.org.aodn.ogcapi.server.core.model.ogc.wfs.FeatureTypeInfo; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServerTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServerTest.java index d9736c19..f12abc51 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServerTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServerTest.java @@ -5,7 +5,7 @@ import au.org.aodn.ogcapi.server.core.configuration.TestConfig; import au.org.aodn.ogcapi.server.core.configuration.GeoServerConfig; import au.org.aodn.ogcapi.server.core.exception.GeoserverFieldsNotFoundException; -import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; +import au.org.aodn.stac.model.StacCollectionModel; import au.org.aodn.stac.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest; import au.org.aodn.ogcapi.server.core.model.ogc.wms.DescribeLayerResponse; From db5f769b860bb0607d864ed8bd5c456ee660cf2a Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Wed, 27 May 2026 23:27:17 +1000 Subject: [PATCH 06/11] update SearchSuggestionsModel --- .../ogcapi/server/core/mapper/Converter.java | 42 +++++----- .../core/model/SearchSuggestionsModel.java | 37 --------- .../server/core/service/ElasticSearch.java | 2 +- .../core/mapper/StacToCollectionTest.java | 76 +++++++++++++++++++ 4 files changed, 102 insertions(+), 55 deletions(-) delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/SearchSuggestionsModel.java diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java index 9fb53457..b76ff105 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java @@ -45,23 +45,33 @@ class Param { T convert(F from, Filter param); - private static List> parseTemporal(List> raw) { - if (raw == null) { + /** + * Parse temporal interval string to Date object, the string should be in ISO 8601 format, e.g. "2020-01-01T00:00:00Z/2020-12-31T23:59:59Z" + * Structure of the input: + * - Outer list = one or more temporal intervals. + * - Inner list = a [start, end] pair. STAC encodes an unbounded endpoint as null + * (e.g. [start, null] = "from start, ongoing"). + * + * @param intervalStrings + * @return + */ + private static List> parseTemporal(List> intervalStrings) { + if (intervalStrings == null) { return null; } - List> out = new ArrayList<>(raw.size()); - for (List inner : raw) { - if (inner == null) { - out.add(null); + List> intervals = new ArrayList<>(intervalStrings.size()); + for (List endpoints : intervalStrings) { + if (endpoints == null) { + intervals.add(null); continue; } - List innerOut = new ArrayList<>(inner.size()); - for (String s : inner) { - innerOut.add(s == null ? null : Date.from(Instant.parse(s))); + List parsedEndpoints = new ArrayList<>(endpoints.size()); + for (String timestamp : endpoints) { + parsedEndpoints.add(timestamp == null ? null : Date.from(Instant.parse(timestamp))); } - out.add(innerOut); + intervals.add(parsedEndpoints); } - return out; + return intervals; } default au.org.aodn.ogcapi.features.model.Link getSelfCollectionLink(String hostname, String id) { @@ -184,16 +194,14 @@ default Collection getCollection(D m, Filter fil // filter have values if user CQL contains BBox, hence our centroid point needs to be // the noland geometry intersect with BBox and centroid point will be within the BBox Geometry g = null; - if(filter != null) { + if (filter != null) { Object geo = filter.accept(visitor, input); if (geo instanceof PreparedGeometry) { g = ((PreparedGeometry) geo).getGeometry(); - } - else if (geo != null) { + } else if (geo != null) { g = (Geometry) geo; } - } - else { + } else { g = input.getGeometry(); } @@ -250,7 +258,7 @@ else if (geo != null) { collection.getProperties().put(CollectionProperty.aiUpdateFrequency, m.getSummaries().getAiUpdateFrequency()); } - if(m.getSummaries().getScope() != null) { + if (m.getSummaries().getScope() != null) { collection.getProperties().put(CollectionProperty.scope, m.getSummaries().getScope()); } diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/SearchSuggestionsModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/SearchSuggestionsModel.java deleted file mode 100644 index e8e44556..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/SearchSuggestionsModel.java +++ /dev/null @@ -1,37 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; - -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -@JsonIgnoreProperties(ignoreUnknown = true) -public class SearchSuggestionsModel { - private Map> searchSuggestions; - - @JsonProperty("abstract_phrases") - public List getAbstractPhrases() { return searchSuggestions.get("abstract_phrases"); } - - @JsonProperty("parameter_vocabs_sayt") - public List getParameterVocabs() { return searchSuggestions.get("parameter_vocabs_sayt"); } - - @JsonProperty("platform_vocabs_sayt") - public List getPlatformVocabs() { return searchSuggestions.get("platform_vocabs_sayt"); } - - @JsonProperty("organisation_vocabs_sayt") - public List getOrganisationVocabs() { return searchSuggestions.get("organisation_vocabs_sayt"); } - - @JsonProperty("search_suggestions") - private void setSearchSuggestions(Map> searchSuggestions) { - this.searchSuggestions = searchSuggestions; - } -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java index 9820aa95..b3d0e3ee 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java @@ -2,8 +2,8 @@ import au.org.aodn.ogcapi.features.model.FeatureGeoJSON; import au.org.aodn.ogcapi.server.core.model.EsFeatureCollectionModel; +import au.org.aodn.stac.model.SearchSuggestionsModel; import au.org.aodn.stac.model.StacCollectionModel; -import au.org.aodn.ogcapi.server.core.model.SearchSuggestionsModel; import au.org.aodn.ogcapi.server.core.model.enumeration.*; import au.org.aodn.ogcapi.server.core.parser.elastic.CQLToElasticFilterFactory; import au.org.aodn.ogcapi.server.core.parser.elastic.QueryHandler; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java index 049c723d..fc7f0cd2 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java @@ -30,6 +30,7 @@ import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; +import java.time.Instant; import java.util.*; import static au.org.aodn.ogcapi.server.BaseTestClass.readResourceFile; @@ -61,6 +62,81 @@ public void verifyBBoxEmptyOrNullWorks() { stacToCollection.convert(model, null); } + @Test + public void verifyTemporalIntervalParsing() { + StacToCollection stacToCollection = new StacToCollectionImpl(); + + // Two intervals: one bounded, one with an unbounded end (ongoing). + // Mirrors STAC's [start, null] convention for "from start, ongoing". + List> temporal = Arrays.asList( + Arrays.asList("2020-01-01T00:00:00Z", "2020-12-31T23:59:59Z"), + Arrays.asList("2021-06-15T12:00:00Z", null) + ); + + StacCollectionModel model = StacCollectionModel + .builder() + .extent(new ExtentModel(Collections.singletonList(Collections.emptyList()), temporal)) + .build(); + + ExtendedCollection collection = (ExtendedCollection) stacToCollection.convert(model, null); + + List> interval = collection.getExtent().getTemporal().getInterval(); + Assertions.assertNotNull(interval); + Assertions.assertEquals(2, interval.size()); + + Assertions.assertEquals(Date.from(Instant.parse("2020-01-01T00:00:00Z")), interval.get(0).get(0)); + Assertions.assertEquals(Date.from(Instant.parse("2020-12-31T23:59:59Z")), interval.get(0).get(1)); + + Assertions.assertEquals(Date.from(Instant.parse("2021-06-15T12:00:00Z")), interval.get(1).get(0)); + Assertions.assertNull(interval.get(1).get(1), "Unbounded interval end must remain null"); + } + + @Test + public void verifyTemporalIntervalParsingPreservesNullInnerList() { + StacToCollection stacToCollection = new StacToCollectionImpl(); + + // A null inner list should be preserved as null (not flattened or skipped). + List> temporal = new ArrayList<>(); + temporal.add(null); + temporal.add(Arrays.asList("2022-03-01T00:00:00Z", "2022-03-31T23:59:59Z")); + + StacCollectionModel model = StacCollectionModel + .builder() + .extent(new ExtentModel(Collections.singletonList(Collections.emptyList()), temporal)) + .build(); + + ExtendedCollection collection = (ExtendedCollection) stacToCollection.convert(model, null); + + List> interval = collection.getExtent().getTemporal().getInterval(); + Assertions.assertNotNull(interval); + Assertions.assertEquals(2, interval.size()); + Assertions.assertNull(interval.get(0), "Null inner interval list must be preserved as null"); + Assertions.assertEquals(Date.from(Instant.parse("2022-03-01T00:00:00Z")), interval.get(1).get(0)); + Assertions.assertEquals(Date.from(Instant.parse("2022-03-31T23:59:59Z")), interval.get(1).get(1)); + } + + @Test + public void verifyTemporalIntervalParsingNormalisesNonZOffset() { + StacToCollection stacToCollection = new StacToCollectionImpl(); + + // Instant.parse accepts RFC 3339 offsets beyond 'Z' and normalises to UTC, + // so 00:00+10:00 lands at the previous day 14:00Z. + List> temporal = Collections.singletonList( + Arrays.asList("2020-01-01T00:00:00+10:00", "2020-12-31T23:59:59+10:00") + ); + + StacCollectionModel model = StacCollectionModel + .builder() + .extent(new ExtentModel(Collections.singletonList(Collections.emptyList()), temporal)) + .build(); + + ExtendedCollection collection = (ExtendedCollection) stacToCollection.convert(model, null); + List> interval = collection.getExtent().getTemporal().getInterval(); + + Assertions.assertEquals(Date.from(Instant.parse("2019-12-31T14:00:00Z")), interval.get(0).get(0)); + Assertions.assertEquals(Date.from(Instant.parse("2020-12-31T13:59:59Z")), interval.get(0).get(1)); + } + @Test public void verifyAddingPropertyWorks() { StacToCollection stacToCollection = new StacToCollectionImpl(); From e158be32d9eb06fcd9c31dcc3494f978d32eed30 Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Wed, 27 May 2026 23:51:43 +1000 Subject: [PATCH 07/11] update schema json files --- .../org/aodn/ogcapi/server/BaseTestClass.java | 10 +- .../src/test/resources/data_index_schema.json | 37 -- .../portal_records_index_schema.json | 373 ------------------ .../test/resources/vocabs_index_schema.json | 112 ------ 4 files changed, 6 insertions(+), 526 deletions(-) delete mode 100644 server/src/test/resources/data_index_schema.json delete mode 100644 server/src/test/resources/portal_records_index_schema.json delete mode 100644 server/src/test/resources/vocabs_index_schema.json diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/BaseTestClass.java b/server/src/test/java/au/org/aodn/ogcapi/server/BaseTestClass.java index d4d7c07e..b7b0ea60 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/BaseTestClass.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/BaseTestClass.java @@ -113,10 +113,12 @@ protected void clearElasticIndex() { protected void createElasticIndex() { schemas.forEach(schema -> { - try { - // TODO: This file should come from indexer jar when CodeArtifact in place - File f = ResourceUtils.getFile(String.format("classpath:%s", schema.get("mapping"))); - try (Reader reader = new FileReader(f)) { + String resourcePath = "/schema/" + schema.get("mapping"); + try (InputStream stream = getClass().getResourceAsStream(resourcePath)) { + if (stream == null) { + throw new FileNotFoundException("Schema not found on classpath: " + resourcePath); + } + try (Reader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) { CreateIndexRequest req = CreateIndexRequest.of(b -> b .index(schema.get("name")) .withJson(reader) diff --git a/server/src/test/resources/data_index_schema.json b/server/src/test/resources/data_index_schema.json deleted file mode 100644 index c7c73430..00000000 --- a/server/src/test/resources/data_index_schema.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "mappings": { - "properties": { - "type": { - "type": "keyword" - }, - "features": { - "type": "nested", - "properties": { - "type": { - "type": "keyword" - }, - "geometry": { - "type": "geo_shape" - }, - "properties": { - "type": "object", - "properties": { - "date": { - "type": "date" - }, - "count": { - "type": "double" - }, - "collection": { - "type": "keyword" - }, - "key": { - "type": "keyword" - } - } - } - } - } - } - } -} diff --git a/server/src/test/resources/portal_records_index_schema.json b/server/src/test/resources/portal_records_index_schema.json deleted file mode 100644 index b0d9dec7..00000000 --- a/server/src/test/resources/portal_records_index_schema.json +++ /dev/null @@ -1,373 +0,0 @@ -{ - "settings": { - "analysis": { - "analyzer": { - "custom_analyser": { - "type": "custom", - "tokenizer": "standard", - "filter": [ - "lowercase", - "english_stop" - ] - }, - "shingle_analyser": { - "type": "custom", - "tokenizer": "standard", - "char_filter": [ - "html_strip" - ], - "filter": [ - "lowercase", - "asciifolding", - "remove_numbers", - "uuid_filter", - "non_standard_pattern_filter", - "et_al_stop", - "english_stop", - "length_filter", - "token_limit", - "shingle_filter", - "unique" - ] - } - }, - "filter": { - "english_stop": { - "type": "stop", - "stopwords": "_english_" - }, - "shingle_filter": { - "type": "shingle", - "min_shingle_size": 2, - "max_shingle_size": 4, - "output_unigrams": true - }, - "uuid_filter": { - "type": "pattern_replace", - "pattern": "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", - "replacement": "" - }, - "non_standard_pattern_filter": { - "type": "pattern_replace", - "pattern": ".*[^a-zA-Z- ].*", - "replacement": "" - }, - "remove_numbers": { - "type": "pattern_replace", - "pattern": "\\b\\d+\\b", - "replacement": "" - }, - "token_limit" : { - "type": "limit", - "max_token_count": 350 - }, - "length_filter": { - "type": "length", - "min": 2 - }, - "et_al_stop": { - "type": "stop", - "stopwords": ["et", "al", "et al", "et.", "al."] - } - } - } - }, - "mappings": { - "dynamic": true, - "properties": { - "id": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword" - } - }, - "analyzer": "keyword" - }, - "stac_version": { - "type": "keyword", - "index": false - }, - "type": { - "type": "keyword", - "index": false - }, - "title": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword" - } - } - }, - "search_suggestions": { - "type": "nested", - "properties": { - "abstract_phrases": { - "type": "search_as_you_type", - "analyzer": "custom_analyser" - }, - "parameter_vocabs_sayt": { - "type": "search_as_you_type", - "analyzer": "custom_analyser" - }, - "platform_vocabs_sayt": { - "type": "search_as_you_type", - "analyzer": "custom_analyser" - }, - "organisation_vocabs_sayt": { - "type": "search_as_you_type", - "analyzer": "custom_analyser" - } - } - }, - "parameter_vocabs": { - "type": "keyword" - }, - "platform_vocabs": { - "type": "keyword" - }, - "organisation_vocabs": { - "type": "keyword" - }, - "keywords": { - "type": "nested", - "properties": { - "keyword": { - "type": "text" - } - } - }, - "extent": { - "type": "nested", - "properties": { - "bbox": { - "type": "double" - }, - "temporal": { - "type": "date" - } - } - }, - "description": { - "type": "text" - }, - "license": { - "type": "keyword", - "index": false - }, - "links": { - "type": "nested", - "properties": { - "link": { - "type": "nested", - "properties": { - "href": { - "type": "keyword", - "index": false - }, - "rel": { - "type": "keyword", - "index": false - }, - "type": { - "type": "keyword", - "index": false - }, - "title": { - "type": "keyword" - }, - "description": { - "type": "keyword" - }, - "ai:group": { - "type": "keyword" - }, - "ai:role": { - "type": "keyword" - } - } - } - } - }, - "assets": { - "type": "flattened" - }, - "sci:citation": { - "type": "keyword", - "index": false - }, - "summaries": { - "properties": { - "ai:description": { - "type": "keyword", - "index": false - }, - "ai:update_frequency": { - "type": "keyword" - }, - "ai:parameter_vocabs": { - "type": "keyword" - }, - "ai:platform_vocabs": { - "type": "keyword" - }, - "score": { - "type": "long" - }, - "status": { - "type": "keyword" - }, - "credits": { - "type": "text" - }, - "scope": { - "type": "nested", - "properties": { - "code": { - "type": "keyword" - }, - "name": { - "type": "keyword" - } - } - }, - "dataset_provider": { - "type": "text" - }, - "dataset_group": { - "type": "keyword" - }, - "creation": { - "type": "date" - }, - "revision": { - "type": "date" - }, - "proj:geometry_noland": { - "type": "geo_shape" - }, - "proj:geometry": { - "type": "geo_shape" - }, - "temporal": { - "type": "nested", - "properties": { - "start": { - "type": "date" - }, - "end": { - "type": "date" - } - } - }, - "statement": { - "type": "keyword", - "index": false - } - } - }, - "contacts": { - "type": "nested", - "properties": { - "contact": { - "type": "nested", - "properties": { - "name": { - "type": "keyword", - "index": false - }, - "organization": { - "type": "keyword" - }, - "position": { - "type": "keyword", - "index": false - }, - "phones": { - "type": "nested", - "properties": { - "value": { - "type": "keyword", - "index": false - }, - "roles": { - "type": "keyword", - "index": false - } - } - }, - "emails": { - "type": "nested", - "properties": { - "value": { - "type": "keyword", - "index": false - }, - "roles": { - "type": "keyword", - "index": false - } - } - }, - "addresses": { - "type": "nested", - "properties": { - "delivery_point": { - "type": "keyword", - "index": false - }, - "city": { - "type": "keyword", - "index": false - }, - "administrative_area": { - "type": "keyword", - "index": false - }, - "postal_code": { - "type": "keyword", - "index": false - }, - "country": { - "type": "keyword", - "index": false - } - } - }, - "links": { - "type": "nested", - "properties": { - "link": { - "type": "nested", - "properties": { - "href": { - "type": "keyword" - }, - "rel": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "title": { - "type": "keyword" - }, - "description": { - "type": "keyword" - } - } - } - } - }, - "roles": { - "type": "keyword", - "index": false - } - } - } - } - } - } - } -} diff --git a/server/src/test/resources/vocabs_index_schema.json b/server/src/test/resources/vocabs_index_schema.json deleted file mode 100644 index 8055f597..00000000 --- a/server/src/test/resources/vocabs_index_schema.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "mappings": { - "dynamic": true, - "properties": { - "parameter_vocab": { - "properties": { - "label": { - "type": "text" - }, - "definition": { - "type": "text" - }, - "about": { - "type": "keyword" - }, - "narrower": { - "type": "nested", - "properties": { - "label": { - "type": "text" - }, - "about": { - "type": "keyword" - }, - "narrower": { - "type": "nested", - "properties": { - "label": { - "type": "text" - }, - "about": { - "type": "keyword" - } - } - } - } - } - } - }, - "platform_vocab": { - "properties": { - "label": { - "type": "text" - }, - "definition": { - "type": "text" - }, - "about": { - "type": "keyword" - }, - "narrower": { - "type": "nested", - "properties": { - "label": { - "type": "text" - }, - "about": { - "type": "keyword" - }, - "narrower": { - "type": "nested", - "properties": { - "label": { - "type": "text" - }, - "about": { - "type": "keyword" - } - } - } - } - } - } - }, - "organisation_vocab": { - "properties": { - "label": { - "type": "text" - }, - "definition": { - "type": "text" - }, - "about": { - "type": "keyword" - }, - "narrower": { - "type": "nested", - "properties": { - "label": { - "type": "text" - }, - "about": { - "type": "keyword" - }, - "narrower": { - "type": "nested", - "properties": { - "label": { - "type": "text" - }, - "about": { - "type": "keyword" - } - } - } - } - } - } - } - } - } -} From 24e2b1e2377b103acdd6e68e2b8003055d791997 Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Thu, 28 May 2026 11:33:43 +1000 Subject: [PATCH 08/11] remove dead files and forwarding new fields to properties --- .../ogcapi/server/core/mapper/Converter.java | 16 ++++++++ .../server/core/model/AddressModel.java | 30 -------------- .../server/core/model/ContactModel.java | 31 --------------- .../ogcapi/server/core/model/InfoModel.java | 20 ---------- .../ogcapi/server/core/model/LinkModel.java | 39 ------------------- .../model/enumeration/CollectionProperty.java | 6 ++- .../core/mapper/StacToCollectionTest.java | 37 ++++++++++++++++++ 7 files changed, 58 insertions(+), 121 deletions(-) delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/AddressModel.java delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/ContactModel.java delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/InfoModel.java delete mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/LinkModel.java diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java index b76ff105..2d9047cc 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java @@ -269,6 +269,22 @@ default Collection getCollection(D m, Filter fil if (m.getSummaries().getAiParameterVocabs() != null && !m.getSummaries().getAiParameterVocabs().isEmpty()) { collection.getProperties().put(CollectionProperty.aiParameterVocabs, m.getSummaries().getAiParameterVocabs()); } + + if (m.getSummaries().getPlatformVocabs() != null && !m.getSummaries().getPlatformVocabs().isEmpty()) { + collection.getProperties().put(CollectionProperty.platformVocabs, m.getSummaries().getPlatformVocabs()); + } + + if (m.getSummaries().getOrganisationVocabs() != null && !m.getSummaries().getOrganisationVocabs().isEmpty()) { + collection.getProperties().put(CollectionProperty.organisationVocabs, m.getSummaries().getOrganisationVocabs()); + } + + if (m.getSummaries().getAiPlatformVocabs() != null && !m.getSummaries().getAiPlatformVocabs().isEmpty()) { + collection.getProperties().put(CollectionProperty.aiPlatformVocabs, m.getSummaries().getAiPlatformVocabs()); + } + + if (m.getSummaries().getDatasetProvider() != null) { + collection.getProperties().put(CollectionProperty.datasetProvider, m.getSummaries().getDatasetProvider()); + } } return collection; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/AddressModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/AddressModel.java deleted file mode 100644 index b8cdb4d1..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/AddressModel.java +++ /dev/null @@ -1,30 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -//https://github.com/stac-extensions/contacts?tab=readme-ov-file#address-object -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@JsonInclude(JsonInclude.Include.NON_NULL) -public class AddressModel { - - @JsonProperty("delivery_point") - protected List deliveryPoint; - protected String city; - - @JsonProperty("administrative_area") - protected String administrativeArea; - - @JsonProperty("postal_code") - protected String postalCode; - protected String country; -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ContactModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ContactModel.java deleted file mode 100644 index 28ba6534..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ContactModel.java +++ /dev/null @@ -1,31 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import au.org.aodn.stac.model.LinkModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ContactModel { - - // Not include all fields according to this: https://github.com/stac-extensions/contacts - // The types of some fields are also not aligned with the spec. - // Currently only include the fields that are in use. - // May need to add more fields / modify some fields in the future. - protected String name; - protected String organization; - protected String identifier; - protected String position; - protected List emails; - protected List addresses; - protected List links; - protected List roles; - protected List phones; - -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/InfoModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/InfoModel.java deleted file mode 100644 index 919d87eb..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/InfoModel.java +++ /dev/null @@ -1,20 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -//https://github.com/stac-extensions/contacts?tab=readme-ov-file#info-object -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@JsonInclude(JsonInclude.Include.NON_NULL) -public class InfoModel { - protected String value; - protected List roles; -} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/LinkModel.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/LinkModel.java deleted file mode 100644 index 5ba6507a..00000000 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/LinkModel.java +++ /dev/null @@ -1,39 +0,0 @@ -package au.org.aodn.ogcapi.server.core.model; - -import au.org.aodn.ogcapi.server.core.util.LinkUtils; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class LinkModel { - protected String rel; - protected String href; - protected String type; - protected String title; - - @JsonProperty("ai:group") - protected String aiGroup; - - @JsonProperty("ai:role") - protected List aiRole; - - @JsonProperty("description") - protected String description; - - public void setTitle(String title) { - String[] parsed = LinkUtils.parseLinkTitleDescription(title); - this.title = parsed[0]; - // set description if the link has successfully parsed description - if (this.description == null && parsed[1] != null) { - this.description = parsed[1]; - } - } -} \ No newline at end of file diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/enumeration/CollectionProperty.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/enumeration/CollectionProperty.java index 3db1dc10..b7d59487 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/enumeration/CollectionProperty.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/enumeration/CollectionProperty.java @@ -26,7 +26,11 @@ public enum CollectionProperty { aiUpdateFrequency("ai:update_frequency"), scope("scope"), parameterVocabs("parameter_vocabs"), - aiParameterVocabs("ai:parameter_vocabs"); + aiParameterVocabs("ai:parameter_vocabs"), + platformVocabs("platform_vocabs"), + organisationVocabs("organisation_vocabs"), + aiPlatformVocabs("ai:platform_vocabs"), + datasetProvider("dataset_provider"); private final String value; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java index fc7f0cd2..6c2eedec 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java @@ -200,6 +200,10 @@ public void verifyAddingPropertyWorks() { scope.put("name", "IMOS publication"); List parameterVocabs = Arrays.asList("wave", "temperature"); + List platformVocabs = Arrays.asList("vessel", "satellite"); + List organisationVocabs = Arrays.asList("IMOS", "AODN"); + List aiPlatformVocabs = Arrays.asList("ai-vessel", "ai-satellite"); + String datasetProvider = "IMOS"; StacCollectionModel model = StacCollectionModel .builder() @@ -216,6 +220,10 @@ public void verifyAddingPropertyWorks() { .aiDescription(aiDescription) .scope(scope) .parameterVocabs(parameterVocabs) + .platformVocabs(platformVocabs) + .organisationVocabs(organisationVocabs) + .aiPlatformVocabs(aiPlatformVocabs) + .datasetProvider(datasetProvider) .build() ) .license("Attribution 4.0") @@ -246,6 +254,10 @@ public void verifyAddingPropertyWorks() { Assertions.assertEquals("document", ((Map) collection.getProperties().get(CollectionProperty.scope)).get("code")); Assertions.assertEquals(parameterVocabs, collection.getProperties().get(CollectionProperty.parameterVocabs)); + Assertions.assertEquals(platformVocabs, collection.getProperties().get(CollectionProperty.platformVocabs)); + Assertions.assertEquals(organisationVocabs, collection.getProperties().get(CollectionProperty.organisationVocabs)); + Assertions.assertEquals(aiPlatformVocabs, collection.getProperties().get(CollectionProperty.aiPlatformVocabs)); + Assertions.assertEquals(datasetProvider, collection.getProperties().get(CollectionProperty.datasetProvider)); Assertions.assertNotNull(collection.getLinks()); Assertions.assertEquals(3, collection.getLinks().size()); @@ -257,6 +269,31 @@ public void verifyAddingPropertyWorks() { Assertions.assertEquals(List.of("download"), convertedLink1.getAiRole()); } + @Test + public void verifyNewSummariesFieldsGuardsSkipEmptyAndNullValues() { + StacToCollection stacToCollection = new StacToCollectionImpl(); + + StacCollectionModel model = StacCollectionModel + .builder() + .summaries( + SummariesModel + .builder() + .platformVocabs(Collections.emptyList()) + .organisationVocabs(null) + .aiPlatformVocabs(Collections.emptyList()) + .datasetProvider(null) + .build() + ) + .build(); + + ExtendedCollection collection = (ExtendedCollection) stacToCollection.convert(model, null); + + Assertions.assertFalse(collection.getProperties().containsKey(CollectionProperty.platformVocabs)); + Assertions.assertFalse(collection.getProperties().containsKey(CollectionProperty.organisationVocabs)); + Assertions.assertFalse(collection.getProperties().containsKey(CollectionProperty.aiPlatformVocabs)); + Assertions.assertFalse(collection.getProperties().containsKey(CollectionProperty.datasetProvider)); + } + @Test public void verifyConvertWorks1() throws IOException, CQLException { String json = readResourceFile("classpath:databag/0c681199-06cd-435c-9468-be6998799b1f.json"); From e7f8abbced16fdeb2a3727eba47cfcd38933646e Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Thu, 28 May 2026 14:15:45 +1000 Subject: [PATCH 09/11] update model names --- .../au/org/aodn/ogcapi/server/core/mapper/Converter.java | 4 ++-- .../ogcapi/server/core/mapper/StacToCollectionTest.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java index 2d9047cc..395a95db 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java @@ -9,7 +9,7 @@ import au.org.aodn.ogcapi.server.core.parser.stac.GeometryVisitor; import au.org.aodn.ogcapi.server.core.util.ConstructUtils; import au.org.aodn.ogcapi.server.core.util.GeometryUtils; -import au.org.aodn.stac.model.Citation; +import au.org.aodn.stac.model.CitationModel; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -176,7 +176,7 @@ default Collection getCollection(D m, Filter fil } if (m.getCitation() != null && !m.getCitation().isEmpty()) { - ConstructUtils.constructByJsonString(m.getCitation(), Citation.class).ifPresent( + ConstructUtils.constructByJsonString(m.getCitation(), CitationModel.class).ifPresent( citation -> collection.getProperties().put(CollectionProperty.citation, citation) ); } diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java index 6c2eedec..4038a791 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/mapper/StacToCollectionTest.java @@ -5,7 +5,7 @@ import au.org.aodn.ogcapi.server.core.model.*; import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType; import au.org.aodn.stac.model.AssetModel; -import au.org.aodn.stac.model.Citation; +import au.org.aodn.stac.model.CitationModel; import au.org.aodn.stac.model.ConceptModel; import au.org.aodn.stac.model.ContactsAddressModel; import au.org.aodn.stac.model.ContactsModel; @@ -240,8 +240,8 @@ public void verifyAddingPropertyWorks() { Assertions.assertEquals(credits, collection.getProperties().get(CollectionProperty.credits)); Assertions.assertEquals(Collections.singletonList(contact), collection.getProperties().get(CollectionProperty.contacts)); Assertions.assertEquals(Collections.singletonList(theme), collection.getProperties().get(CollectionProperty.themes)); - Assertions.assertInstanceOf(Citation.class, collection.getProperties().get(CollectionProperty.citation)); - var citationToCheck = (Citation) collection.getProperties().get(CollectionProperty.citation); + Assertions.assertInstanceOf(CitationModel.class, collection.getProperties().get(CollectionProperty.citation)); + var citationToCheck = (CitationModel) collection.getProperties().get(CollectionProperty.citation); Assertions.assertEquals("this is suggested Citation", citationToCheck.getSuggestedCitation()); Assertions.assertEquals(Arrays.asList("this is useLimitations1", "this is useLimitations2"), citationToCheck.getUseLimitations()); Assertions.assertEquals(Arrays.asList("this is otherConstraints1", "this is otherConstraints2"), citationToCheck.getOtherConstraints()); From 3ed2af34081d0376f0e99f97592116eae147b391 Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Thu, 28 May 2026 15:18:15 +1000 Subject: [PATCH 10/11] update to latest released stacmodel version --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b3fda17d..aa7b3740 100644 --- a/pom.xml +++ b/pom.xml @@ -192,8 +192,7 @@ au.org.aodn stacmodel - feature-8455-update-stacmodel-2-SNAPSHOT - + 0.0.59 From d2dfc7f3609164baa37c5e74b05f944172d78f74 Mon Sep 17 00:00:00 2001 From: Lyn Long Date: Thu, 28 May 2026 15:35:07 +1000 Subject: [PATCH 11/11] update comment --- .../au/org/aodn/ogcapi/server/core/mapper/Converter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java index 395a95db..680b83df 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/mapper/Converter.java @@ -52,8 +52,9 @@ class Param { * - Inner list = a [start, end] pair. STAC encodes an unbounded endpoint as null * (e.g. [start, null] = "from start, ongoing"). * - * @param intervalStrings - * @return + * @param intervalStrings outer list of [start, end] string pairs + * @return outer list of [start, end] pairs preserving the input's null structure, + * or null if intervalStrings is null */ private static List> parseTemporal(List> intervalStrings) { if (intervalStrings == null) {