diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/project/ProjectChildLocationDao.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/project/ProjectChildLocationDao.java index 8d97702cf..03309d8a3 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dao/project/ProjectChildLocationDao.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/project/ProjectChildLocationDao.java @@ -27,8 +27,11 @@ import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dto.CwmsId; import cwms.cda.data.dto.project.ProjectChildLocations; - -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import org.jetbrains.annotations.Nullable; import org.jooq.DSLContext; @@ -48,7 +51,8 @@ public List retrieveProjectChildLocations(String office, return retrieveProjectChildLocations(office, projLike, ProjectKind.getMatchingKinds(kindRegex)); } - private List retrieveProjectChildLocations(String office, String projLike, Set kinds) { + private List retrieveProjectChildLocations( + String office, String projLike, Set kinds) { Map builderMap = new LinkedHashMap<>(); // proj-id-> @@ -64,25 +68,7 @@ private List retrieveProjectChildLocations(String office, .withOfficeId(office) .withName(projId) .build())); - switch (kind) { - case EMBANKMENT: - builder.withEmbankments(locs); - break; - case LOCK: - builder.withLocks(locs); - break; - case OUTLET: - builder.withOutlets(locs); - break; - case TURBINE: - builder.withTurbines(locs); - break; - case GATE: - builder.withGates(locs); - break; - default: - break; - } + builder.withLocations(kind, locs); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/project/LocationsWithProjectKind.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/project/LocationsWithProjectKind.java new file mode 100644 index 000000000..7bb190311 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/project/LocationsWithProjectKind.java @@ -0,0 +1,65 @@ +package cwms.cda.data.dto.project; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.data.dao.project.ProjectKind; +import cwms.cda.data.dto.CwmsId; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; +import java.util.ArrayList; +import java.util.List; + +@JsonDeserialize(builder = LocationsWithProjectKind.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +@FormattableWith(contentType = Formats.JSONV2, aliases = {Formats.JSON}, formatter = JsonV2.class) +public class LocationsWithProjectKind { + ProjectKind kind; + List locations; + + private LocationsWithProjectKind(Builder builder) { + kind = builder.kind; + locations = builder.locations; + } + + public ProjectKind getKind() { + return kind; + } + + public List getLocations() { + return locations; + } + + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static class Builder { + private ProjectKind kind; + private List locations = new ArrayList<>(); + + public Builder() { + + } + + public Builder withKind(ProjectKind kind) { + this.kind = kind; + return this; + } + + public Builder withLocations(List locations) { + if (locations == null) { + this.locations = null; + } else { + this.locations = new ArrayList<>(locations); + } + return this; + } + + public LocationsWithProjectKind build() { + return new LocationsWithProjectKind(this); + } + } +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/project/ProjectChildLocations.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/project/ProjectChildLocations.java index 576a52788..7c8303bf1 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dto/project/ProjectChildLocations.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/project/ProjectChildLocations.java @@ -24,18 +24,23 @@ package cwms.cda.data.dto.project; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.data.dao.project.ProjectKind; import cwms.cda.data.dto.CwmsDTOBase; import cwms.cda.data.dto.CwmsId; import cwms.cda.formatters.Formats; import cwms.cda.formatters.annotations.FormattableWith; import cwms.cda.formatters.json.JsonV2; -import java.util.Collections; +import java.util.ArrayList; +import java.util.EnumMap; import java.util.List; -import org.jetbrains.annotations.Nullable; +import java.util.Map; /** * This class holds a project and lists of the project child locations by kind. @@ -48,92 +53,132 @@ public class ProjectChildLocations extends CwmsDTOBase { private final CwmsId project; - private final List embankments; - private final List locks; - private final List outlets; - private final List turbines; - private final List gates; + @JsonIgnore + private EnumMap> locationsByKind; private ProjectChildLocations(Builder builder) { this.project = builder.project; - this.embankments = builder.embankments; - this.locks = builder.locks; - this.outlets = builder.outlets; - this.turbines = builder.turbines; - this.gates = builder.gates; + + if (builder.locationsByKind != null) { + this.locationsByKind = new EnumMap<>(builder.locationsByKind); + } } public CwmsId getProject() { return project; } + @JsonProperty + public List getLocationsByKind() { + List result = null; + + if (locationsByKind != null && !locationsByKind.isEmpty()) { + result = new ArrayList<>(); + + for (Map.Entry> entry : locationsByKind.entrySet()) { + result.add(new LocationsWithProjectKind.Builder() + .withKind(entry.getKey()) + .withLocations(entry.getValue()).build()); + } + } + + return result; + } + + public List getLocations(ProjectKind kind) { + if (locationsByKind != null && !locationsByKind.isEmpty()) { + return locationsByKind.get(kind); + } + return null; + } + + @JsonIgnore public List getEmbankments() { - return embankments; + return getLocations(ProjectKind.EMBANKMENT); } + @JsonIgnore public List getLocks() { - return locks; + return getLocations(ProjectKind.LOCK); } + @JsonIgnore public List getOutlets() { - return outlets; + return getLocations(ProjectKind.OUTLET); } + @JsonIgnore public List getTurbines() { - return turbines; + return getLocations(ProjectKind.TURBINE); } + @JsonIgnore public List getGates() { - return gates; + return getLocations(ProjectKind.GATE); } - + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) public static class Builder { private CwmsId project; - private List embankments; - private List locks; - private List outlets; - private List turbines; - private List gates; + + private EnumMap> locationsByKind; public Builder withProject(CwmsId project) { this.project = project; return this; } - public Builder withEmbankments(List embankments) { - this.embankments = wrapList(embankments); + public Builder withLocationsByKind(List locationsByKind) { + Builder retval = this; + if (locationsByKind != null) { + for (LocationsWithProjectKind item : locationsByKind) { + retval = retval.withLocations(item.getKind(), item.getLocations()); + } + } + + return retval; + } + + public Builder withLocations(ProjectKind kind, List locations) { + + if (locationsByKind == null) { + locationsByKind = new EnumMap<>(ProjectKind.class); + } + + if (locations != null) { + List locOfKind = locationsByKind.computeIfAbsent(kind, k -> new ArrayList<>()); + if (!locations.isEmpty()) { + locOfKind.addAll(locations); + } + } + return this; } + @JsonIgnore + public Builder withEmbankments(List embankments) { + return withLocations(ProjectKind.EMBANKMENT, embankments); + } + @JsonIgnore public Builder withLocks(List locks) { - this.locks = wrapList(locks); - return this; + return withLocations(ProjectKind.LOCK, locks); } + @JsonIgnore public Builder withOutlets(List outlets) { - this.outlets = outlets; - return this; + return withLocations(ProjectKind.OUTLET, outlets); } + @JsonIgnore public Builder withTurbines(List turbines) { - this.turbines = wrapList(turbines); - return this; + return withLocations(ProjectKind.TURBINE, turbines); } + @JsonIgnore public Builder withGates(List gates) { - this.gates = wrapList(gates); - return this; - } - - @Nullable - private static List wrapList(@Nullable List embankments) { - List retval = null; - if (embankments != null) { - retval = Collections.unmodifiableList(embankments); - } - return retval; + return withLocations(ProjectKind.GATE, gates); } public ProjectChildLocations build() { diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/project/LocationsWithProjectKindTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/project/LocationsWithProjectKindTest.java new file mode 100644 index 000000000..72492d461 --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/project/LocationsWithProjectKindTest.java @@ -0,0 +1,51 @@ +package cwms.cda.data.dto.project; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import cwms.cda.data.dao.project.ProjectKind; +import cwms.cda.data.dto.CwmsId; +import cwms.cda.formatters.json.JsonV2; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + + +public class LocationsWithProjectKindTest { + + @Test + void test_serialize() throws JsonProcessingException { + LocationsWithProjectKind.Builder builder = new LocationsWithProjectKind.Builder(); + builder.withKind(ProjectKind.EMBANKMENT); + List locs = new ArrayList<>(); + locs.add(new CwmsId.Builder().withName("Emb1").withOfficeId("SPK").build()); + locs.add(new CwmsId.Builder().withName("Emb2").withOfficeId("SPK").build()); + builder.withLocations(locs); + LocationsWithProjectKind locWithKind = builder.build(); + + ObjectMapper objectMapper = JsonV2.buildObjectMapper(); + String json = objectMapper.writeValueAsString(locWithKind); + assertNotNull(json); + + } + + @Test + void test_deserialize() throws IOException { + + InputStream stream = LocationsWithProjectKind.class.getClassLoader().getResourceAsStream( + "cwms/cda/data/dto/location_with_kind.json"); + assertNotNull(stream); + ObjectMapper objectMapper = JsonV2.buildObjectMapper(); + LocationsWithProjectKind locationsWithKind = objectMapper.readValue(stream, LocationsWithProjectKind.class); + assertNotNull(locationsWithKind); + assertEquals(ProjectKind.EMBANKMENT, locationsWithKind.getKind()); + assertEquals("TestEmbankment1", locationsWithKind.getLocations().get(0).getName()); + assertEquals("TestEmbankment2", locationsWithKind.getLocations().get(1).getName()); + + } + +} \ No newline at end of file diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/project/ProjectChildLocationsTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/project/ProjectChildLocationsTest.java index 3ac794246..9681c1b69 100644 --- a/cwms-data-api/src/test/java/cwms/cda/data/dto/project/ProjectChildLocationsTest.java +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/project/ProjectChildLocationsTest.java @@ -24,7 +24,11 @@ package cwms.cda.data.dto.project; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -45,7 +49,7 @@ class ProjectChildLocationsTest { public static final String OFFICE = "SPK"; @Test - void test_ctor(){ + void test_ctor() { CwmsId proj = buildId(OFFICE, "TestProject"); List embanks = new ArrayList<>(); @@ -82,7 +86,6 @@ void test_ctor(){ String json = Formats.format(new ContentType(Formats.JSON), projectChildLocations); - assertNotNull(json); } @@ -119,7 +122,7 @@ private ProjectChildLocations buildTestProjectChildLocations(String office, Stri } @Test - void test_list_serialization(){ + void test_list_serialization() { List list = new ArrayList<>(); list.add(buildTestProjectChildLocations(OFFICE, "TestProject1")); @@ -140,12 +143,12 @@ void test_list_deserialization() throws IOException { String input = IOUtils.toString(stream, StandardCharsets.UTF_8); ObjectMapper om = JsonV2.buildObjectMapper(); - List list = om.readValue(input, new TypeReference>(){}); + List list = om.readValue(input, new TypeReference>() { + }); assertNotNull(list); assertFalse(list.isEmpty()); } - @Test void testDeserialize() throws IOException { @@ -218,7 +221,8 @@ void testRoundtrip() throws IOException { assertProjectChildLocationsEqual(projectChildLocations1, projectChildLocations2); } - private static void assertProjectChildLocationsEqual(ProjectChildLocations projectChildLocations1, ProjectChildLocations projectChildLocations2) { + private static void assertProjectChildLocationsEqual(ProjectChildLocations projectChildLocations1, + ProjectChildLocations projectChildLocations2) { assertAll("ProjectChildLocations", () -> assertCwmsIdEqual(projectChildLocations1.getProject(), projectChildLocations2.getProject()), () -> assertListEqual(projectChildLocations1.getEmbankments(), projectChildLocations2.getEmbankments()), @@ -238,7 +242,7 @@ private static void assertCwmsIdEqual(CwmsId project1, CwmsId project2) { private static void assertListEqual(List locks1, List locks2) { assertEquals(locks1.size(), locks2.size()); - for(int i = 0; i < locks1.size(); i++){ + for (int i = 0; i < locks1.size(); i++) { assertCwmsIdEqual(locks1.get(i), locks2.get(i)); } } diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/location_with_kind.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/location_with_kind.json new file mode 100644 index 000000000..66bbcd981 --- /dev/null +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/location_with_kind.json @@ -0,0 +1,12 @@ +{ + "kind": "EMBANKMENT", + "locations": [ + { + "name": "TestEmbankment1" + }, + { + "office-id": "SPK", + "name": "TestEmbankment2" + } + ] +} \ No newline at end of file diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/project_children.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/project_children.json index 3d677d47e..93a35fb16 100644 --- a/cwms-data-api/src/test/resources/cwms/cda/data/dto/project_children.json +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/project_children.json @@ -3,46 +3,63 @@ "office-id": "SPK", "name": "TestProject" }, - "embankments": [ + "locations-by-kind": [ { - "office-id": "SPK", - "name": "TestEmbankment1" + "kind": "EMBANKMENT", + "locations": [ + { + "office-id": "SPK", + "name": "TestEmbankment1" + }, + { + "office-id": "SPK", + "name": "TestEmbankment2" + } + ] }, { - "office-id": "SPK", - "name": "TestEmbankment2" - } - ], - "locks": [ - { - "office-id": "SPK", - "name": "TestLock1" + "kind": "LOCK", + "locations": [ + { + "office-id": "SPK", + "name": "TestLock1" + }, + { + "office-id": "SPK", + "name": "TestLock2" + }, + { + "office-id": "SPK", + "name": "TestLock3" + } + ] }, { - "office-id": "SPK", - "name": "TestLock2" + "kind": "OUTLET", + "locations": [ + { + "office-id": "SPK", + "name": "TestOutlet1" + } + ] }, { - "office-id": "SPK", - "name": "TestLock3" - } - ], - "outlets": [ - { - "office-id": "SPK", - "name": "TestOutlet1" - } - ], - "turbines": [ - { - "office-id": "SPK", - "name": "TestTurbine1" - } - ], - "gates": [ + "kind": "TURBINE", + "locations": [ + { + "office-id": "SPK", + "name": "TestTurbine1" + } + ] + }, { - "office-id": "SPK", - "name": "TestGate1" + "kind": "GATE", + "locations": [ + { + "office-id": "SPK", + "name": "TestGate1" + } + ] } ] } \ No newline at end of file diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/project_children_list.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/project_children_list.json index d20a26db9..d497e21b1 100644 --- a/cwms-data-api/src/test/resources/cwms/cda/data/dto/project_children_list.json +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/project_children_list.json @@ -4,14 +4,19 @@ "office-id": "SPK", "name": "TestProject1" }, - "embankments": [ + "locations-by-kind": [ { - "office-id": "SPK", - "name": "TestEmbankment1" - }, - { - "office-id": "SPK", - "name": "TestEmbankment2" + "kind": "EMBANKMENT", + "locations": [ + { + "office-id": "SPK", + "name": "TestEmbankment1" + }, + { + "office-id": "SPK", + "name": "TestEmbankment2" + } + ] } ] }