Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Embankment API #670

Merged
merged 1 commit into from
Jun 5, 2024
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
@@ -0,0 +1,257 @@
/*
* MIT License
*
* Copyright (c) 2024 Hydrologic Engineering Center
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package cwms.cda.data.dto.location.kind;

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 cwms.cda.api.errors.FieldException;
import cwms.cda.data.dto.CwmsDTOBase;
import cwms.cda.data.dto.Location;
import cwms.cda.data.dto.LookupType;
import cwms.cda.formatters.Formats;
import cwms.cda.formatters.annotations.FormattableWith;
import cwms.cda.formatters.json.JsonV1;

import java.util.Objects;

@FormattableWith(contentType = Formats.JSON, formatter = JsonV1.class)
@JsonDeserialize(builder = Embankment.Builder.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class)
public final class Embankment implements CwmsDTOBase {
private final Double upstreamSideSlope;
private final Double downstreamSideSlope;
private final Double structureLength;
private final Double heightMax;
private final Double topWidth;
private final String unitsId;
private final LookupType downstreamProtType;
private final LookupType upstreamProtType;
private final LookupType structureType;
private final Location location;
private final String projectId;
private final String projectOfficeId;

private Embankment(Builder builder) {
this.projectId = builder.projectId;
this.projectOfficeId = builder.projectOfficeId;
this.location = builder.location;
this.structureType = builder.structureType;
this.upstreamProtType = builder.upstreamProtType;
this.downstreamProtType = builder.downstreamProtType;
this.unitsId = builder.unitsId;
this.topWidth = builder.topWidth;
this.heightMax = builder.heightMax;
this.structureLength = builder.structureLength;
this.downstreamSideSlope = builder.downstreamSideSlope;
this.upstreamSideSlope = builder.upstreamSideSlope;
}

public Double getUpstreamSideSlope() {
return upstreamSideSlope;
}

public Double getDownstreamSideSlope() {
return downstreamSideSlope;
}

public Double getStructureLength() {
return structureLength;
}

public Double getHeightMax() {
return heightMax;
}

public Double getTopWidth() {
return topWidth;
}

public String getUnitsId() {
return unitsId;
}

public LookupType getStructureType() {
return structureType;
}

public LookupType getUpstreamProtType() {
return upstreamProtType;
}

public LookupType getDownstreamProtType() {
return downstreamProtType;
}

public Location getLocation() {
return location;
}

public String getProjectId() {
return projectId;
}

public String getProjectOfficeId() {
return projectOfficeId;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

Embankment that = (Embankment) o;
return Objects.equals(getUpstreamSideSlope(), that.getUpstreamSideSlope())
&& Objects.equals(getDownstreamSideSlope(), that.getDownstreamSideSlope())
&& Objects.equals(getStructureLength(), that.getStructureLength())
&& Objects.equals(getHeightMax(), that.getHeightMax())
&& Objects.equals(getTopWidth(), that.getTopWidth())
&& Objects.equals(getUnitsId(), that.getUnitsId())
&& Objects.equals(getDownstreamProtType(), that.getDownstreamProtType())
&& Objects.equals(getUpstreamProtType(), that.getUpstreamProtType())
&& Objects.equals(getStructureType(), that.getStructureType())
&& Objects.equals(getLocation(), that.getLocation())
&& Objects.equals(getProjectId(), that.getProjectId())
&& Objects.equals(getProjectOfficeId(), that.getProjectOfficeId());
}

@Override
public int hashCode() {
int result = Objects.hashCode(getUpstreamSideSlope());
result = 31 * result + Objects.hashCode(getDownstreamSideSlope());
result = 31 * result + Objects.hashCode(getStructureLength());
result = 31 * result + Objects.hashCode(getHeightMax());
result = 31 * result + Objects.hashCode(getTopWidth());
result = 31 * result + Objects.hashCode(getUnitsId());
result = 31 * result + Objects.hashCode(getDownstreamProtType());
result = 31 * result + Objects.hashCode(getUpstreamProtType());
result = 31 * result + Objects.hashCode(getStructureType());
result = 31 * result + Objects.hashCode(getLocation());
result = 31 * result + Objects.hashCode(getProjectId());
result = 31 * result + Objects.hashCode(getProjectOfficeId());
return result;
}

@Override
public void validate() throws FieldException {
if (this.location == null) {
throw new FieldException("Location field can't be null");
}
if (this.projectId == null) {
throw new FieldException("Project location Id field can't be null");
}
if (this.projectOfficeId == null) {
throw new FieldException("Project office Id field can't be null");
}
if (this.structureType == null) {
throw new FieldException("Structure type field can't be null");
}
}

public static final class Builder {
private Double upstreamSideSlope;
private Double downstreamSideSlope;
private Double structureLength;
private Double heightMax;
private Double topWidth;
private String unitsId;
private LookupType downstreamProtType;
private LookupType upstreamProtType;
private LookupType structureType;
private Location location;
private String projectId;
private String projectOfficeId;

public Builder withUpstreamSideSlope(Double upstreamSideSlope) {
this.upstreamSideSlope = upstreamSideSlope;
return this;
}

public Builder withDownstreamSideSlope(Double downstreamSideSlope) {
this.downstreamSideSlope = downstreamSideSlope;
return this;
}

public Builder withStructureLength(Double structureLength) {
this.structureLength = structureLength;
return this;
}

public Builder withHeightMax(Double heightMax) {
this.heightMax = heightMax;
return this;
}

public Builder withTopWidth(Double topWidth) {
this.topWidth = topWidth;
return this;
}

public Builder withUnitsId(String unitsId) {
this.unitsId = unitsId;
return this;
}

public Builder withDownstreamProtType(LookupType downstreamProtType) {
this.downstreamProtType = downstreamProtType;
return this;
}

public Builder withUpstreamProtType(LookupType upstreamProtType) {
this.upstreamProtType = upstreamProtType;
return this;
}

public Builder withStructureType(LookupType structureType) {
this.structureType = structureType;
return this;
}

public Builder withLocation(Location location) {
this.location = location;
return this;
}

public Builder withProjectId(String projectId) {
this.projectId = projectId;
return this;
}

public Builder withProjectOfficeId(String projectOfficeId) {
this.projectOfficeId = projectOfficeId;
return this;
}

public Embankment build() {
return new Embankment(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* MIT License
*
* Copyright (c) 2024 Hydrologic Engineering Center
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package cwms.cda.data.dto.location.kind;

import cwms.cda.api.enums.Nation;
import cwms.cda.api.errors.FieldException;
import cwms.cda.data.dto.Location;
import cwms.cda.data.dto.LookupType;
import cwms.cda.formatters.Formats;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;

import static org.junit.jupiter.api.Assertions.*;

final class EmbankmentTest {

@Test
void testEmbankmentSerializationRoundTrip() {
Embankment embankment = buildTestEmbankment();
String serialized = Formats.format(Formats.parseHeader(Formats.JSON), embankment);
Embankment deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSON), serialized, Embankment.class);
assertEquals(embankment, deserialized, "Roundtrip serialization failed");
assertEquals(embankment.hashCode(), deserialized.hashCode(), "Roundtrip serialization failed");
}

@Test
void testEmbankmentSerializationRoundTripFromFile() throws Exception {
Embankment embankment = buildTestEmbankment();
InputStream resource = this.getClass().getResourceAsStream("/cwms/cda/data/dto/location/kind/embankment.json");
assertNotNull(resource);
String serialized = IOUtils.toString(resource, StandardCharsets.UTF_8);
Embankment deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSON), serialized, Embankment.class);
assertEquals(embankment, deserialized, "Roundtrip serialization failed");
}

@Test
void testValidate() {
Location location = buildTestLocation();
String projectId = "project";
assertAll(() -> {
Embankment embankment = new Embankment.Builder().build();
assertThrows(FieldException.class, embankment::validate,
"Expected validate() to throw FieldException because Location field can't be null, but it didn't");
}, () -> {
Embankment embankment = new Embankment.Builder().withLocation(location).build();
assertThrows(FieldException.class, embankment::validate,
"Expected validate() to throw FieldException because Project Id field can't be null, but it didn't");
}, () -> {
Embankment embankment = new Embankment.Builder().withLocation(location).withProjectId(projectId).build();
assertThrows(FieldException.class, embankment::validate,
"Expected validate() to throw FieldException because Project Office Id field can't be null, but it didn't");
}, () -> {
Embankment embankment = new Embankment.Builder().withLocation(location).withProjectId(projectId).withProjectOfficeId("SPK").build();
assertThrows(FieldException.class, embankment::validate,
"Expected validate() to throw FieldException because Structure type field can't be null, but it didn't");
}
);
}

private Embankment buildTestEmbankment() {
return new Embankment.Builder()
.withLocation(buildTestLocation())
.withHeightMax(5.0)
.withProjectId("PROJECT")
.withProjectOfficeId("LRD")
.withStructureLength(10.0)
.withStructureType(new LookupType.Builder()
.withOfficeId("CWMS")
.withDisplayValue("STRUCT")
.withTooltip("TOOLTIP_STRUCT")
.withActive(true)
.build())
.withDownstreamProtType(new LookupType.Builder()
.withOfficeId("SPK")
.withDisplayValue("DOWNSTREAM_PROT")
.withTooltip("TOOLTIP_DOWNSTREAM_PROT")
.withActive(false)
.build())
.withUpstreamProtType(new LookupType.Builder()
.withOfficeId("LRL")
.withDisplayValue("UPSTREAM_PROT")
.withTooltip("TOOLTIP_UPSTREAM_PROT")
.withActive(true)
.build())
.withUpstreamSideSlope(15.0)
.withUnitsId("ft")
.withTopWidth(20.0)
.withStructureLength(25.0)
.withDownstreamSideSlope(90.0)
.build();
}

private Location buildTestLocation() {
return new Location.Builder("TEST_LOCATION2", "EMBANKMENT", ZoneId.of("UTC"),
50.0, 50.0, "NVGD29", "LRL")
.withElevation(10.0)
.withLocationType("SITE")
.withCountyName("Sacramento")
.withNation(Nation.US)
.withActive(true)
.withStateInitial("CA")
.withBoundingOfficeId("LRL")
.withLongName("TEST_LOCATION")
.withPublishedLatitude(50.0)
.withPublishedLongitude(50.0)
.withDescription("for testing")
.build();
}
}
Loading
Loading