From e7bd9746d59394f8132d8301511fc58e4214991d Mon Sep 17 00:00:00 2001 From: Yuxuan HU Date: Wed, 15 Oct 2025 16:11:01 +1100 Subject: [PATCH 1/2] add link description --- .../ogcapi/server/core/mapper/Converter.java | 22 +++++--- .../server/core/model/ExtendedLink.java | 8 +++ .../ogcapi/server/core/model/LinkModel.java | 3 ++ .../ogcapi/server/core/util/LinkUtils.java | 29 ++++++++++ .../core/mapper/StacToCollectionTest.java | 2 + .../server/core/util/LinkUtilsTest.java | 54 +++++++++++++++++++ 6 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/util/LinkUtils.java create mode 100644 server/src/test/java/au/org/aodn/ogcapi/server/core/util/LinkUtilsTest.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 a75d652a..a7b882d2 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 @@ -10,6 +10,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.ogcapi.server.core.util.LinkUtils; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -111,13 +112,20 @@ default Collection getCollection(D m, Filter fil collection.getLinks().addAll( m.getLinks() .stream() - .map(l -> new ExtendedLink() - .href(l.getHref()) - .type(l.getType()) - .rel(l.getRel()) - .title(l.getTitle()) - .aiGroup(l.getAiGroup()) - ) + .map(l -> { + // Parse title and description from the combined title + String[] parsed = LinkUtils.parseLinkTitleDescription(l.getTitle()); + String title = parsed[0]; + String description = parsed[1]; + + return new ExtendedLink() + .href(l.getHref()) + .type(l.getType()) + .rel(l.getRel()) + .title(title) + .description(description) + .aiGroup(l.getAiGroup()); + }) .toList() ); } diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ExtendedLink.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ExtendedLink.java index 64cdb612..1dce4263 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ExtendedLink.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ExtendedLink.java @@ -12,6 +12,9 @@ public class ExtendedLink extends Link { @JsonProperty("ai:group") private String aiGroup; + @JsonProperty("description") + private String description; + public ExtendedLink() { super(); } @@ -21,6 +24,11 @@ public ExtendedLink aiGroup(String aiGroup) { return this; } + public ExtendedLink description(String description) { + this.description = description; + return this; + } + @Override public ExtendedLink href(String href) { super.href(href); 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 67bbae08..5829c825 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 @@ -18,4 +18,7 @@ public class LinkModel { @JsonProperty("ai:group") protected String aiGroup; + + @JsonProperty("description") + protected String description; } 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 new file mode 100644 index 00000000..217e4c85 --- /dev/null +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/util/LinkUtils.java @@ -0,0 +1,29 @@ +package au.org.aodn.ogcapi.server.core.util; + +public class LinkUtils { + public static String[] parseLinkTitleDescription(String combinedTitle) { + // if combinedTitle is null, return null for both title and description + if (combinedTitle == null) { + return new String[]{null, null}; + } + // Otherwise, find the last bracket + int bracketCount = 0; + for (int i = combinedTitle.length() - 1; i >= 0; i--) { + if (combinedTitle.charAt(i) == ']') { + bracketCount++; + } else if (combinedTitle.charAt(i) == '[') { + bracketCount--; + if (bracketCount == 0) { + String title = combinedTitle.substring(0, i).trim(); + String description = combinedTitle.substring(i + 1, combinedTitle.length() - 1).trim(); + return new String[]{ + title, + description.isEmpty() ? null : description + }; + } + } + } + // return null description if no matching bracket found + return new String[]{combinedTitle, null}; + } +} 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 76908460..26ec9290 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 @@ -81,6 +81,7 @@ public void verifyAddingPropertyWorks() { .type("text/html") .title("Data Link") .aiGroup("data-access") + .description("description") .build(); var link2 = LinkModel.builder() .rel("self") @@ -88,6 +89,7 @@ public void verifyAddingPropertyWorks() { .type("application/json") .title("Self Link") .aiGroup("ai-group") + .description("description") .build(); var theme = ThemeModel.builder() .scheme("scheme") 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 new file mode 100644 index 00000000..791e79d0 --- /dev/null +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/LinkUtilsTest.java @@ -0,0 +1,54 @@ +package au.org.aodn.ogcapi.server.core.util; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +public class LinkUtilsTest { + @Test + void testParseLinkTitleDescription_normalCase() { + String[] result = LinkUtils.parseLinkTitleDescription("mnf:adcp_public_data[ADCP data for Southern Surveyor Voyage SS 09/2003]"); + + assertEquals("mnf:adcp_public_data", result[0]); + assertEquals("ADCP data for Southern Surveyor Voyage SS 09/2003", result[1]); + } + + @Test + void testParseLinkTitleDescription_emptyDescription() { + String[] result = LinkUtils.parseLinkTitleDescription("Ocean Radar page on IMOS website[]"); + + assertEquals("Ocean Radar page on IMOS website", result[0]); + assertNull(result[1]); + } + + @Test + void testParseLinkTitleDescription_titleWithBrackets() { + String[] result = LinkUtils.parseLinkTitleDescription("DATA ACCESS - GBR10 benthic habitat type [Geotiff direct download][]"); + + assertEquals("DATA ACCESS - GBR10 benthic habitat type [Geotiff direct download]", result[0]); + assertNull(result[1]); + } + + @Test + void testParseLinkTitleDescription_emptyTitleAndDescription() { + String[] result = LinkUtils.parseLinkTitleDescription(null); + + assertNull(result[0]); + assertNull(result[1]); + } + + @Test + void testParseLinkTitleDescription_multipleNestedBrackets() { + String[] result = LinkUtils.parseLinkTitleDescription("Title [level1 [level2]] [Final Description]"); + + assertEquals("Title [level1 [level2]]", result[0]); + assertEquals("Final Description", result[1]); + } + + @Test + void testParseLinkTitleDescription_whitespaceOnlyDescription() { + String[] result = LinkUtils.parseLinkTitleDescription("Title[ ]"); + + assertEquals("Title", result[0]); + assertNull(result[1]); + } +} From cfeacb80cac3acdea4230b7753c5846a0f8d2f9e Mon Sep 17 00:00:00 2001 From: Yuxuan HU Date: Thu, 16 Oct 2025 18:04:50 +1100 Subject: [PATCH 2/2] update link model --- .../ogcapi/server/core/mapper/Converter.java | 22 +++++++------------ .../ogcapi/server/core/model/LinkModel.java | 9 ++++++++ 2 files changed, 17 insertions(+), 14 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 a7b882d2..c6096360 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 @@ -112,20 +112,14 @@ default Collection getCollection(D m, Filter fil collection.getLinks().addAll( m.getLinks() .stream() - .map(l -> { - // Parse title and description from the combined title - String[] parsed = LinkUtils.parseLinkTitleDescription(l.getTitle()); - String title = parsed[0]; - String description = parsed[1]; - - return new ExtendedLink() - .href(l.getHref()) - .type(l.getType()) - .rel(l.getRel()) - .title(title) - .description(description) - .aiGroup(l.getAiGroup()); - }) + .map(l -> new ExtendedLink() + .href(l.getHref()) + .type(l.getType()) + .rel(l.getRel()) + .title(l.getTitle()) + .description(l.getDescription()) + .aiGroup(l.getAiGroup()) + ) .toList() ); } 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 5829c825..083cdce2 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 @@ -1,5 +1,6 @@ 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; @@ -21,4 +22,12 @@ public class LinkModel { @JsonProperty("description") protected String description; + + public void setTitle(String title) { + String[] parsed = LinkUtils.parseLinkTitleDescription(title); + this.title = parsed[0]; + if (this.description == null) { + this.description = parsed[1]; + } + } }