Skip to content

Commit c4a59bf

Browse files
authored
CWMS-2197 Adds include alias flag for timeseries catalog (#1193)
1 parent e94b63e commit c4a59bf

13 files changed

Lines changed: 557 additions & 80 deletions

File tree

cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static com.codahale.metrics.MetricRegistry.name;
44
import static cwms.cda.api.Controllers.ACCEPT;
5+
import static cwms.cda.api.Controllers.INCLUDE_ALIASES;
56
import static cwms.cda.api.Controllers.BOUNDING_OFFICE_LIKE;
67
import static cwms.cda.api.Controllers.CURSOR;
78
import static cwms.cda.api.Controllers.EXCLUDE_EMPTY;
@@ -168,6 +169,10 @@ public void getAll(Context ctx) {
168169
description = "Posix <a href=\"regexp.html\">regular expression</a> matching "
169170
+ "against the location type."
170171
),
172+
@OpenApiParam(name = INCLUDE_ALIASES, type = Boolean.class,
173+
description = "Whether to add aliases to the catalog entries. "
174+
+ "Default is false. If true, the aliases will be added to the "
175+
+ "catalog entries in the response."),
171176
},
172177
pathParams = {
173178
@OpenApiParam(name = "dataset",
@@ -230,7 +235,8 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) {
230235

231236
String locationType = queryParamAsClass(ctx, new String[]{LOCATION_TYPE_LIKE},
232237
String.class, null, metrics, name(CatalogController.class.getName(), GET_ONE));
233-
238+
boolean includeAliases = ctx.queryParamAsClass(INCLUDE_ALIASES, Boolean.class)
239+
.getOrDefault(false);
234240
String acceptHeader = ctx.header(ACCEPT);
235241
ContentType contentType = Formats.parseHeader(acceptHeader, Catalog.class);
236242
Catalog cat = null;
@@ -254,6 +260,7 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) {
254260
.withExcludeEmpty(excludeExtents)
255261
.withLocationKind(locationKind)
256262
.withLocationType(locationType)
263+
.withIncludeAliases(includeAliases)
257264
.build();
258265

259266
cat = tsDao.getTimeSeriesCatalog(cursor, pageSize, parameters);

cwms-data-api/src/main/java/cwms/cda/api/Controllers.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ public final class Controllers {
146146
public static final String ISSUE_DATE = "issue-date";
147147
public static final String LOCATION_KIND_LIKE = "location-kind-like";
148148
public static final String LOCATION_TYPE_LIKE = "location-type-like";
149+
public static final String INCLUDE_ALIASES = "include-aliases";
149150
public static final String MIN_NUMBER = "min-number";
150151
public static final String MAX_NUMBER = "max-number";
151152
public static final String MIN_HEIGHT = "min-height";

cwms-data-api/src/main/java/cwms/cda/data/dao/CatalogRequestParameters.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class CatalogRequestParameters {
2020
private final boolean excludeEmpty;
2121
private final String locationKind;
2222
private final String locationType;
23+
private final boolean includeAliases;
2324

2425
private CatalogRequestParameters(Builder builder) {
2526
this.office = builder.office;
@@ -34,6 +35,7 @@ private CatalogRequestParameters(Builder builder) {
3435
this.excludeEmpty = builder.excludeEmpty;
3536
this.locationKind = builder.locationKind;
3637
this.locationType = builder.locationType;
38+
this.includeAliases = builder.includeAliases;
3739
}
3840

3941
public String getBoundingOfficeLike() {
@@ -84,6 +86,10 @@ public String getLocationType() {
8486
return locationType;
8587
}
8688

89+
public boolean includeAliases() {
90+
return includeAliases;
91+
}
92+
8793

8894
public static class Builder {
8995
String office;
@@ -98,6 +104,7 @@ public static class Builder {
98104
private boolean excludeEmpty = true;
99105
String locationKind;
100106
String locationType;
107+
private boolean includeAliases = false;
101108

102109
public Builder() {
103110

@@ -163,6 +170,11 @@ public Builder withLocationType(String locationType) {
163170
return this;
164171
}
165172

173+
public Builder withIncludeAliases(boolean includeAliases) {
174+
this.includeAliases = includeAliases;
175+
return this;
176+
}
177+
166178
public static Builder from(CatalogRequestParameters params) {
167179
// This NEEDS to include every field in the CatalogRequestParameters
168180
return new Builder()

cwms-data-api/src/main/java/cwms/cda/data/dao/TimeSeriesDaoImpl.java

Lines changed: 230 additions & 67 deletions
Large diffs are not rendered by default.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package cwms.cda.data.dto.catalog;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import com.fasterxml.jackson.annotation.JsonRootName;
5+
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
6+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
7+
import com.fasterxml.jackson.databind.annotation.JsonNaming;
8+
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
9+
import cwms.cda.formatters.Formats;
10+
import cwms.cda.formatters.annotations.FormattableWith;
11+
import cwms.cda.formatters.json.JsonV2;
12+
import java.util.Objects;
13+
14+
@JsonRootName("alias")
15+
@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class, aliases = {Formats.DEFAULT, Formats.JSON})
16+
@JsonDeserialize(builder = TimeSeriesAlias.Builder.class)
17+
@JsonInclude(JsonInclude.Include.NON_NULL)
18+
@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class)
19+
public final class TimeSeriesAlias {
20+
21+
@JacksonXmlProperty(isAttribute = true)
22+
private final String name;
23+
private final String value;
24+
25+
private TimeSeriesAlias(Builder builder) {
26+
this.name = builder.name;
27+
this.value = builder.value;
28+
}
29+
30+
public String getName() {
31+
return name;
32+
}
33+
34+
public String getValue() {
35+
return value;
36+
}
37+
38+
@Override
39+
public boolean equals(Object o) {
40+
if (this == o) {
41+
return true;
42+
}
43+
if (o == null || getClass() != o.getClass()) {
44+
return false;
45+
}
46+
TimeSeriesAlias that = (TimeSeriesAlias) o;
47+
return Objects.equals(name, that.name) && Objects.equals(value, that.value);
48+
}
49+
50+
@Override
51+
public int hashCode() {
52+
return Objects.hash(name, value);
53+
}
54+
55+
public static final class Builder {
56+
private String name;
57+
private String value;
58+
59+
public Builder() {
60+
}
61+
62+
public Builder withName(String name) {
63+
this.name = name;
64+
return this;
65+
}
66+
67+
public Builder withValue(String value) {
68+
this.value = value;
69+
return this;
70+
}
71+
72+
public TimeSeriesAlias build() {
73+
return new TimeSeriesAlias(this);
74+
}
75+
}
76+
}

cwms-data-api/src/main/java/cwms/cda/data/dto/catalog/TimeseriesCatalogEntry.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.math.BigDecimal;
44
import java.time.ZonedDateTime;
55
import java.util.ArrayList;
6+
import java.util.Collection;
67
import java.util.List;
78

89
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
@@ -29,6 +30,9 @@ public class TimeseriesCatalogEntry extends CatalogEntry {
2930
@JacksonXmlProperty(localName = "extents")
3031
private List<TimeSeriesExtents> extents;
3132

33+
@JacksonXmlElementWrapper(localName = "aliases")
34+
@JacksonXmlProperty(localName = "alias")
35+
private Collection<TimeSeriesAlias> aliases;
3236

3337
public String getName() {
3438
return this.name;
@@ -52,18 +56,23 @@ public List<TimeSeriesExtents> getExtents() {
5256
return extents;
5357
}
5458

59+
public Collection<TimeSeriesAlias> getAliases() {
60+
return aliases;
61+
}
62+
5563
private TimeseriesCatalogEntry() {
5664
super(null);
5765
}
5866

59-
private TimeseriesCatalogEntry(String office, String name, String units, String interval, Long intervalOffset, String timeZone, List<TimeSeriesExtents> extents) {
60-
super(office);
61-
this.name = name;
62-
this.units = units;
63-
this.interval = interval;
64-
this.intervalOffset = intervalOffset;
65-
this.timeZone = timeZone;
66-
this.extents = extents;
67+
private TimeseriesCatalogEntry(Builder builder) {
68+
super(builder.office);
69+
this.name = builder.tsName;
70+
this.units = builder. units;
71+
this.interval = builder.interval;
72+
this.intervalOffset = builder.intervalOffset;
73+
this.timeZone = builder.timeZone;
74+
this.extents = builder.extents;
75+
this.aliases = builder.aliases;
6776
}
6877

6978
public String getUnits() {
@@ -90,6 +99,7 @@ public static class Builder {
9099
private ZonedDateTime earliestTime;
91100
private ZonedDateTime latestTime;
92101
private List<TimeSeriesExtents> extents = null;
102+
private Collection<TimeSeriesAlias> aliases = null;
93103

94104
public Builder officeId(final String office) {
95105
this.office = office;
@@ -143,8 +153,17 @@ public Builder withExtents(final List<TimeSeriesExtents> newExtents) {
143153
return this;
144154
}
145155

156+
public Builder withAliases(final Collection<TimeSeriesAlias> aliases) {
157+
if (aliases == null) {
158+
this.aliases = null;
159+
} else {
160+
this.aliases = new ArrayList<>(aliases);
161+
}
162+
return this;
163+
}
164+
146165
public TimeseriesCatalogEntry build() {
147-
return new TimeseriesCatalogEntry(office, tsName, units, interval, intervalOffset, timeZone, extents);
166+
return new TimeseriesCatalogEntry(this);
148167
}
149168
}
150169
}

cwms-data-api/src/main/java/cwms/cda/formatters/xml/XMLv1.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public <T extends CwmsDTOBase> T parseContent(InputStream content, Class<T> type
8787
}
8888
}
8989

90-
private static @NotNull XmlMapper buildObjectMapper() {
90+
public static @NotNull XmlMapper buildObjectMapper() {
9191
XmlMapper retval = new XmlMapper();
9292

9393
retval.findAndRegisterModules();

cwms-data-api/src/test/java/cwms/cda/api/CatalogControllerTestIT.java

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
package cwms.cda.api;
22

3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.core.type.TypeReference;
5+
import com.fasterxml.jackson.databind.JsonNode;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
37
import static cwms.cda.api.Controllers.BOUNDING_OFFICE_LIKE;
48
import static cwms.cda.api.Controllers.EXCLUDE_EMPTY;
9+
import static cwms.cda.api.Controllers.INCLUDE_ALIASES;
510
import static cwms.cda.api.Controllers.LIKE;
611
import static cwms.cda.api.Controllers.LOCATION_CATEGORY_LIKE;
712
import static cwms.cda.api.Controllers.LOCATION_GROUP_LIKE;
813
import static cwms.cda.api.Controllers.LOCATION_KIND_LIKE;
914
import static cwms.cda.api.Controllers.TIMESERIES_CATEGORY_LIKE;
1015
import static cwms.cda.api.Controllers.TIMESERIES_GROUP_LIKE;
16+
import cwms.cda.data.dto.catalog.TimeSeriesAlias;
17+
import cwms.cda.data.dto.catalog.TimeseriesCatalogEntry;
18+
import cwms.cda.formatters.json.JsonV2;
19+
import java.util.List;
20+
import java.util.Objects;
21+
import java.util.stream.Collectors;
1122
import static org.junit.jupiter.api.Assertions.*;
1223

1324
import cwms.cda.data.dao.DeleteRule;
@@ -125,6 +136,80 @@ void test_no_aliased_results_returned() {
125136
.body("entries.size()",is(4));
126137
}
127138

139+
@Test
140+
void test_no_aliases_returned() {
141+
Integer numAliases = given().accept(Formats.JSONV2)
142+
.log().ifValidationFails(LogDetail.ALL, true)
143+
.queryParam(Controllers.OFFICE, OFFICE)
144+
.queryParam(EXCLUDE_EMPTY, false)
145+
.when()
146+
.get("/catalog/TIMESERIES")
147+
.then()
148+
.log().ifValidationFails(LogDetail.ALL, true)
149+
.assertThat()
150+
.statusCode(is(200))
151+
.extract()
152+
.jsonPath()
153+
.getObject("entries.aliases.aliases.size()", Integer.class);
154+
assertEquals(0, (int) numAliases, "Expected no aliases, but found some.");
155+
}
156+
157+
@Test
158+
void test_aliases_returned() {
159+
Integer numAliases = given().accept(Formats.JSONV2)
160+
.log().ifValidationFails(LogDetail.ALL, true)
161+
.queryParam(Controllers.OFFICE, OFFICE)
162+
.queryParam(EXCLUDE_EMPTY,false)
163+
.queryParam(INCLUDE_ALIASES,true)
164+
.when()
165+
.get("/catalog/TIMESERIES")
166+
.then()
167+
.log().ifValidationFails(LogDetail.ALL, true)
168+
.assertThat()
169+
.statusCode(is(200))
170+
.extract()
171+
.jsonPath()
172+
.getObject("entries.aliases.aliases.size()", Integer.class);
173+
assertTrue(numAliases > 0, "Expected aliases, but found none.");
174+
}
175+
176+
@Test
177+
void test_alias_is_correct() throws JsonProcessingException {
178+
Response response = given().accept(Formats.JSONV2)
179+
.log().ifValidationFails(LogDetail.ALL, true)
180+
.queryParam(Controllers.OFFICE, OFFICE)
181+
.queryParam(EXCLUDE_EMPTY, false)
182+
.queryParam(INCLUDE_ALIASES, true)
183+
.when()
184+
.get("/catalog/TIMESERIES");
185+
String json = response.body().asPrettyString();
186+
ObjectMapper om = JsonV2.buildObjectMapper();
187+
JsonNode root = om.readTree(json);
188+
JsonNode entriesNode = root.get("entries");
189+
String entriesJson = om.writeValueAsString(entriesNode);
190+
List<TimeseriesCatalogEntry> entries = om.readValue(entriesJson, new TypeReference<List<TimeseriesCatalogEntry>>() {});
191+
assertNotNull(entries);
192+
TimeseriesCatalogEntry alias = entries
193+
.stream()
194+
.filter(Objects::nonNull)
195+
.collect(Collectors.toSet()).stream()
196+
.filter(e -> e.getName().equals("Pine Flat-Outflow.Stage.Inst.15Minutes.0.one"))
197+
.findFirst()
198+
.orElse(null);
199+
assertNotNull(alias);
200+
assertTrue(alias.getAliases().contains(new TimeSeriesAlias.Builder()
201+
.withName("Test Category-LessThan3")
202+
.withValue("test alias 1")
203+
.build()));
204+
//make sure no entries exist with name "test alias 1"
205+
List<TimeseriesCatalogEntry> aliasesAsAnEntry = entries
206+
.stream()
207+
.filter(Objects::nonNull)
208+
.filter(e -> e.getName().equals("test alias 1"))
209+
.collect(Collectors.toList());
210+
assertTrue(aliasesAsAnEntry.isEmpty(), "Found entries with name 'test alias 1', which should not exist.");
211+
}
212+
128213

129214
@Test
130215
void test_queries_are_case_insensitive() {

0 commit comments

Comments
 (0)