Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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

String locationType = queryParamAsClass(ctx, new String[]{LOCATION_TYPE_LIKE},
String.class, null, metrics, name(CatalogController.class.getName(), GET_ONE));

boolean includeAliases = ctx.queryParamAsClass(INCLUDE_ALIASES, Boolean.class)
.getOrDefault(false);
String acceptHeader = ctx.header(ACCEPT);
ContentType contentType = Formats.parseHeader(acceptHeader, Catalog.class);
Catalog cat = null;
Expand All @@ -254,6 +260,7 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) {
.withExcludeEmpty(excludeExtents)
.withLocationKind(locationKind)
.withLocationType(locationType)
.withIncludeAliases(includeAliases)
.build();

cat = tsDao.getTimeSeriesCatalog(cursor, pageSize, parameters);
Expand Down
1 change: 1 addition & 0 deletions cwms-data-api/src/main/java/cwms/cda/api/Controllers.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ public final class Controllers {
public static final String ISSUE_DATE = "issue-date";
public static final String LOCATION_KIND_LIKE = "location-kind-like";
public static final String LOCATION_TYPE_LIKE = "location-type-like";
public static final String INCLUDE_ALIASES = "include-aliases";
public static final String MIN_NUMBER = "min-number";
public static final String MAX_NUMBER = "max-number";
public static final String MIN_HEIGHT = "min-height";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class CatalogRequestParameters {
private final boolean excludeEmpty;
private final String locationKind;
private final String locationType;
private final boolean includeAliases;

private CatalogRequestParameters(Builder builder) {
this.office = builder.office;
Expand All @@ -34,6 +35,7 @@ private CatalogRequestParameters(Builder builder) {
this.excludeEmpty = builder.excludeEmpty;
this.locationKind = builder.locationKind;
this.locationType = builder.locationType;
this.includeAliases = builder.includeAliases;
}

public String getBoundingOfficeLike() {
Expand Down Expand Up @@ -84,6 +86,10 @@ public String getLocationType() {
return locationType;
}

public boolean includeAliases() {
return includeAliases;
}


public static class Builder {
String office;
Expand All @@ -98,6 +104,7 @@ public static class Builder {
private boolean excludeEmpty = true;
String locationKind;
String locationType;
private boolean includeAliases = false;

public Builder() {

Expand Down Expand Up @@ -163,6 +170,11 @@ public Builder withLocationType(String locationType) {
return this;
}

public Builder withIncludeAliases(boolean includeAliases) {
this.includeAliases = includeAliases;
return this;
}

public static Builder from(CatalogRequestParameters params) {
// This NEEDS to include every field in the CatalogRequestParameters
return new Builder()
Expand Down
297 changes: 230 additions & 67 deletions cwms-data-api/src/main/java/cwms/cda/data/dao/TimeSeriesDaoImpl.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package cwms.cda.data.dto.catalog;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import cwms.cda.formatters.Formats;
import cwms.cda.formatters.annotations.FormattableWith;
import cwms.cda.formatters.json.JsonV2;
import java.util.Objects;

@JsonRootName("alias")
@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class, aliases = {Formats.DEFAULT, Formats.JSON})
@JsonDeserialize(builder = TimeSeriesAlias.Builder.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class)
public final class TimeSeriesAlias {

@JacksonXmlProperty(isAttribute = true)
private final String name;
private final String value;

private TimeSeriesAlias(Builder builder) {
this.name = builder.name;
this.value = builder.value;
}

public String getName() {
return name;
}

public String getValue() {
return value;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TimeSeriesAlias that = (TimeSeriesAlias) o;
return Objects.equals(name, that.name) && Objects.equals(value, that.value);
}

@Override
public int hashCode() {
return Objects.hash(name, value);
}

public static final class Builder {
private String name;
private String value;

public Builder() {
}

public Builder withName(String name) {
this.name = name;
return this;
}

public Builder withValue(String value) {
this.value = value;
return this;
}

public TimeSeriesAlias build() {
return new TimeSeriesAlias(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.math.BigDecimal;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

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

@JacksonXmlElementWrapper(localName = "aliases")
@JacksonXmlProperty(localName = "alias")
private Collection<TimeSeriesAlias> aliases;

public String getName() {
return this.name;
Expand All @@ -52,18 +56,23 @@ public List<TimeSeriesExtents> getExtents() {
return extents;
}

public Collection<TimeSeriesAlias> getAliases() {
return aliases;
}

private TimeseriesCatalogEntry() {
super(null);
}

private TimeseriesCatalogEntry(String office, String name, String units, String interval, Long intervalOffset, String timeZone, List<TimeSeriesExtents> extents) {
super(office);
this.name = name;
this.units = units;
this.interval = interval;
this.intervalOffset = intervalOffset;
this.timeZone = timeZone;
this.extents = extents;
private TimeseriesCatalogEntry(Builder builder) {
super(builder.office);
this.name = builder.tsName;
this.units = builder. units;
this.interval = builder.interval;
this.intervalOffset = builder.intervalOffset;
this.timeZone = builder.timeZone;
this.extents = builder.extents;
this.aliases = builder.aliases;
}

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

public Builder officeId(final String office) {
this.office = office;
Expand Down Expand Up @@ -143,8 +153,17 @@ public Builder withExtents(final List<TimeSeriesExtents> newExtents) {
return this;
}

public Builder withAliases(final Collection<TimeSeriesAlias> aliases) {
if (aliases == null) {
this.aliases = null;
} else {
this.aliases = new ArrayList<>(aliases);
}
return this;
}

public TimeseriesCatalogEntry build() {
return new TimeseriesCatalogEntry(office, tsName, units, interval, intervalOffset, timeZone, extents);
return new TimeseriesCatalogEntry(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public <T extends CwmsDTOBase> T parseContent(InputStream content, Class<T> type
}
}

private static @NotNull XmlMapper buildObjectMapper() {
public static @NotNull XmlMapper buildObjectMapper() {
XmlMapper retval = new XmlMapper();

retval.findAndRegisterModules();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
package cwms.cda.api;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import static cwms.cda.api.Controllers.BOUNDING_OFFICE_LIKE;
import static cwms.cda.api.Controllers.EXCLUDE_EMPTY;
import static cwms.cda.api.Controllers.INCLUDE_ALIASES;
import static cwms.cda.api.Controllers.LIKE;
import static cwms.cda.api.Controllers.LOCATION_CATEGORY_LIKE;
import static cwms.cda.api.Controllers.LOCATION_GROUP_LIKE;
import static cwms.cda.api.Controllers.LOCATION_KIND_LIKE;
import static cwms.cda.api.Controllers.TIMESERIES_CATEGORY_LIKE;
import static cwms.cda.api.Controllers.TIMESERIES_GROUP_LIKE;
import cwms.cda.data.dto.catalog.TimeSeriesAlias;
import cwms.cda.data.dto.catalog.TimeseriesCatalogEntry;
import cwms.cda.formatters.json.JsonV2;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.*;

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

@Test
void test_no_aliases_returned() {
Integer numAliases = given().accept(Formats.JSONV2)
.log().ifValidationFails(LogDetail.ALL, true)
.queryParam(Controllers.OFFICE, OFFICE)
.queryParam(EXCLUDE_EMPTY, false)
.when()
.get("/catalog/TIMESERIES")
.then()
.log().ifValidationFails(LogDetail.ALL, true)
.assertThat()
.statusCode(is(200))
.extract()
.jsonPath()
.getObject("entries.aliases.aliases.size()", Integer.class);
assertEquals(0, (int) numAliases, "Expected no aliases, but found some.");
}

@Test
void test_aliases_returned() {
Integer numAliases = given().accept(Formats.JSONV2)
.log().ifValidationFails(LogDetail.ALL, true)
.queryParam(Controllers.OFFICE, OFFICE)
.queryParam(EXCLUDE_EMPTY,false)
.queryParam(INCLUDE_ALIASES,true)
.when()
.get("/catalog/TIMESERIES")
.then()
.log().ifValidationFails(LogDetail.ALL, true)
.assertThat()
.statusCode(is(200))
.extract()
.jsonPath()
.getObject("entries.aliases.aliases.size()", Integer.class);
assertTrue(numAliases > 0, "Expected aliases, but found none.");
}

@Test
void test_alias_is_correct() throws JsonProcessingException {
Response response = given().accept(Formats.JSONV2)
.log().ifValidationFails(LogDetail.ALL, true)
.queryParam(Controllers.OFFICE, OFFICE)
.queryParam(EXCLUDE_EMPTY, false)
.queryParam(INCLUDE_ALIASES, true)
.when()
.get("/catalog/TIMESERIES");
String json = response.body().asPrettyString();
ObjectMapper om = JsonV2.buildObjectMapper();
JsonNode root = om.readTree(json);
JsonNode entriesNode = root.get("entries");
String entriesJson = om.writeValueAsString(entriesNode);
List<TimeseriesCatalogEntry> entries = om.readValue(entriesJson, new TypeReference<List<TimeseriesCatalogEntry>>() {});
assertNotNull(entries);
TimeseriesCatalogEntry alias = entries
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toSet()).stream()
.filter(e -> e.getName().equals("Pine Flat-Outflow.Stage.Inst.15Minutes.0.one"))
.findFirst()
.orElse(null);
assertNotNull(alias);
assertTrue(alias.getAliases().contains(new TimeSeriesAlias.Builder()
.withName("Test Category-LessThan3")
.withValue("test alias 1")
.build()));
//make sure no entries exist with name "test alias 1"
List<TimeseriesCatalogEntry> aliasesAsAnEntry = entries
.stream()
.filter(Objects::nonNull)
.filter(e -> e.getName().equals("test alias 1"))
.collect(Collectors.toList());
assertTrue(aliasesAsAnEntry.isEmpty(), "Found entries with name 'test alias 1', which should not exist.");
}


@Test
void test_queries_are_case_insensitive() {
Expand Down
Loading
Loading