Skip to content
Draft
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
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 @@ -112,6 +112,7 @@ public final class Controllers {
public static final String REPLACE_BASE_CURVE = "replace-base-curve";
public static final String EFFECTIVE_DATE_EXACT = "use-exact-effective-date";


public static final String TIMESERIES_ID_REGEX = "timeseries-id-regex";
public static final String TIMESERIES_ID = "timeseries-id";
public static final String SNAP_FORWARD = "snap-forward";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import cwms.cda.data.dao.JsonRatingUtils;
import cwms.cda.data.dao.RatingDao;
import cwms.cda.data.dao.RatingSetDao;
import cwms.cda.data.dao.VerticalDatum;
import cwms.cda.data.dto.CwmsDTOBase;
import cwms.cda.data.dto.StatusResponse;
import cwms.cda.formatters.ContentType;
Expand All @@ -71,7 +72,9 @@
import cwms.cda.formatters.xml.XMLv2;
import cwms.cda.helpers.DateUtils;
import hec.data.RatingException;
import hec.data.cwmsRating.AbstractRating;
import hec.data.cwmsRating.RatingSet;
import hec.data.cwmsRating.TableRating;
import io.javalin.apibuilder.CrudHandler;
import io.javalin.core.util.Header;
import io.javalin.core.validation.JavalinValidation;
Expand All @@ -90,6 +93,7 @@
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.TransformerException;
import mil.army.usace.hec.cwms.rating.io.xml.RatingXmlFactory;
import mil.army.usace.hec.metadata.VerticalDatumException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jooq.DSLContext;
Expand Down Expand Up @@ -267,7 +271,9 @@ public void delete(@NotNull Context ctx, @NotNull String ratingSpecId) {
+ "\n* `NAVD88` The elevation values will in the "
+ "specified or default units above the NAVD-88 datum."
+ "\n* `NGVD29` The elevation values will be in the "
+ "specified or default units above the NGVD-29 datum."),
+ "specified or default units above the NGVD-29 datum."
+ "\n* `NATIVE` The elevation values will be in the "
+ "Location's native datum."),
@OpenApiParam(name = AT, description = "Specifies the "
+ "start of the time window for data to be included in the response. "
+ "If this field is not specified, any required time window begins 24"
Expand Down Expand Up @@ -364,6 +370,16 @@ public void getAll(@NotNull Context ctx) {
@OpenApiParam(name = METHOD, description = "Specifies "
+ "the retrieval method used. If no method is provided EAGER will be used.",
type = RatingSet.DatabaseLoadMethod.class),
@OpenApiParam(name = DATUM, description = "Specifies the "
+ "elevation datum of the response. This field affects only elevation"
+ " Ratings. Valid values for this field are:"
+ "\n* `NAVD88` The elevation values will in the "
+ "specified or default units above the NAVD-88 datum."
+ "\n* `NGVD29` The elevation values will be in the "
+ "specified or default units above the NGVD-29 datum."
+ "\n* `NATIVE` The elevation values will be in the "
+ "Location's native datum.",
type = VerticalDatum.class),
},
responses = {
@OpenApiResponse(status = STATUS_200, content = {
Expand All @@ -378,6 +394,7 @@ public void getOne(@NotNull Context ctx, @NotNull String rating) {
try (final Timer.Context ignored = markAndTime(GET_ONE)) {
String officeId = ctx.queryParam(OFFICE);
String timezone = ctx.queryParamAsClass(TIMEZONE, String.class).getOrDefault("UTC");
VerticalDatum verticalDatum = VerticalDatum.getVerticalDatum(ctx.queryParam(DATUM));

Instant beginInstant = null;
String begin = ctx.queryParam(BEGIN);
Expand All @@ -395,7 +412,7 @@ public void getOne(@NotNull Context ctx, @NotNull String rating) {
RatingSet.DatabaseLoadMethod.class)
.getOrDefault(RatingSet.DatabaseLoadMethod.EAGER);

String body = getRatingSetString(ctx, method, officeId, rating, beginInstant, endInstant);
String body = getRatingSetString(ctx, method, officeId, rating, beginInstant, endInstant, verticalDatum);
if (body != null) {
ctx.result(body);
ctx.status(HttpCode.OK);
Expand All @@ -407,7 +424,7 @@ public void getOne(@NotNull Context ctx, @NotNull String rating) {
@Nullable
private String getRatingSetString(Context ctx, RatingSet.DatabaseLoadMethod method,
String officeId, String rating, Instant begin,
Instant end) {
Instant end, VerticalDatum verticalDatum) {
String retval = null;

try (final Timer.Context ignored = markAndTime("getRatingSetString")) {
Expand All @@ -422,6 +439,28 @@ private String getRatingSetString(Context ctx, RatingSet.DatabaseLoadMethod meth
try {
RatingSet ratingSet = getRatingSet(ctx, method, officeId, rating, begin, end);
if (ratingSet != null) {
//Apply vertical datum conversion if needed
if (verticalDatum != null) {
try {
switch (verticalDatum)
{
case NAVD88:
ratingSet.toNAVD88();
break;
case NGVD29:
ratingSet.toNGVD29();
break;
case NATIVE:
ratingSet.toNativeVerticalDatum();
break;
default:
logger.log(Level.SEVERE, "Unknown vertical datum: " + verticalDatum);
break;
}
} catch (VerticalDatumException vde) {
logger.log(Level.WARNING, vde, () -> "Failed to convert rating " + rating + " to requested vertical datum: " + verticalDatum);
}
}
if (isJson) {
retval = JsonRatingUtils.toJson(ratingSet);
} else {
Expand Down
30 changes: 30 additions & 0 deletions cwms-data-api/src/main/java/cwms/cda/data/dao/VerticalDatum.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cwms.cda.data.dao;

public enum VerticalDatum
{
NAVD88("NAVD88"),
NGVD29("NGVD29"),
NATIVE("NATIVE");

private final String rule;

VerticalDatum(String rule) {
this.rule = rule;
}

public static VerticalDatum getVerticalDatum(String input) {
VerticalDatum retval = null;

if (input != null && !input.isBlank()) {
input = input.trim().replace("-", "");
retval = VerticalDatum.valueOf(input.toUpperCase());
}
return retval;
}

@Override
public String toString() {
return rule;
}

}
62 changes: 62 additions & 0 deletions cwms-data-api/src/test/java/cwms/cda/api/DataApiTestIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import cwms.cda.data.dao.DeleteRule;
import cwms.cda.data.dao.StreamDao;
import cwms.cda.data.dao.basin.BasinDao;
import cwms.cda.data.dao.VerticalDatum;
import cwms.cda.data.dto.Location;
import cwms.cda.data.dto.LocationCategory;
import cwms.cda.data.dto.LocationGroup;
Expand Down Expand Up @@ -80,6 +81,7 @@
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.extension.ExtendWith;
import usace.cwms.db.jooq.codegen.packages.CWMS_ENV_PACKAGE;
import usace.cwms.db.jooq.codegen.packages.CWMS_LOC_PACKAGE;
import usace.cwms.db.jooq.codegen.packages.CWMS_UTIL_PACKAGE;

/**
Expand Down Expand Up @@ -326,6 +328,66 @@ protected static void createLocation(String location, boolean active, String off
}, "cwms_20");
}

protected static void createLocationWithVerticalDatum(String location, boolean active, String office, VerticalDatum verticalDatum) throws SQLException
{
createLocation(location, active, office);
updateLocation(location, active, office, verticalDatum);
}

private static void updateLocation(String location, boolean active, String officeId, VerticalDatum verticalDatum) throws SQLException {

String P_LOCATION_ID = location;
String P_LOCATION_TYPE = "SITE";
Number P_ELEVATION = 11;
String P_ELEV_UNIT_ID = "m";

// Pretty sure this isn't supposed to have a dash. The create doesn't check. The default create just passes null.
// If it has a dash then the offsets don't work.
// select VERTICAL_DATUM, count(*) as COUNT
// from AT_PHYSICAL_LOCATION
// group by VERTICAL_DATUM
// order by COUNT desc
// has no entries with a dash in the name (unless we've run this test with a dash).
String P_VERTICAL_DATUM = verticalDatum.toString();
Number P_LATITUDE = 38.5757; // pretty sure that if these are 0,0 then its not inside the navd88 bounds and the offsets come back []
Number P_LONGITUDE = -121.4789;
String P_HORIZONTAL_DATUM = "WGS84";
String P_PUBLIC_NAME = "Integration Test Sac Dam";
String P_LONG_NAME= null;
String P_DESCRIPTION = "for testing";
String P_TIME_ZONE_ID = "UTC";
String P_COUNTY_NAME = "Sacramento";
String P_STATE_INITIAL = "CA";
String P_ACTIVE = active ? "T" : "F";
String P_DB_OFFICE_ID = officeId;

CwmsDatabaseContainer<?> db = CwmsDataApiSetupCallback.getDatabaseLink();
db.connection(c -> {
DSLContext dslContext = getDslContext(c, officeId);

// CWMS_LOC_PACKAGE.call_DELETE_LOCATION(dslContext.configuration(), P_LOCATION_ID, String.valueOf(DeleteRule.DELETE_LOC_CASCADE), P_DB_OFFICE_ID);
// CWMS_LOC_PACKAGE.call_CREATE_LOCATION(dslContext.configuration(),
// P_LOCATION_ID, P_LOCATION_TYPE, P_ELEVATION, P_ELEV_UNIT_ID, P_VERTICAL_DATUM, P_LATITUDE, P_LONGITUDE,
// P_HORIZONTAL_DATUM, P_PUBLIC_NAME, P_LONG_NAME, P_DESCRIPTION, P_TIME_ZONE_ID, P_COUNTY_NAME, P_STATE_INITIAL,
// P_ACTIVE, P_DB_OFFICE_ID);

String P_IGNORENULLS = "F";
CWMS_LOC_PACKAGE.call_UPDATE_LOCATION(dslContext.configuration(),
P_LOCATION_ID, P_LOCATION_TYPE, P_ELEVATION, P_ELEV_UNIT_ID, P_VERTICAL_DATUM, P_LATITUDE, P_LONGITUDE,
P_HORIZONTAL_DATUM, P_PUBLIC_NAME, P_LONG_NAME, P_DESCRIPTION, P_TIME_ZONE_ID, P_COUNTY_NAME, P_STATE_INITIAL,
P_ACTIVE, P_IGNORENULLS, P_DB_OFFICE_ID );

});

}

private static DSLContext getDslContext(Connection database, String officeId)
{
DSLContext dsl = DSL.using(database, SQLDialect.ORACLE18C);
CWMS_ENV_PACKAGE.call_SET_SESSION_OFFICE_ID(dsl.configuration(), officeId);
return dsl;
}

/**
* Creates a location saving the data for later deletion. With the following defaults:
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,25 @@

import cwms.cda.api.DataApiTestIT;
import cwms.cda.data.dao.JooqDao;
import cwms.cda.data.dao.VerticalDatum;
import cwms.cda.formatters.Formats;
import fixtures.TestAccounts;
import hec.data.cwmsRating.io.RatingSetContainer;
import hec.data.cwmsRating.io.RatingSpecContainer;
import io.restassured.filter.log.LogDetail;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import mil.army.usace.hec.cwms.rating.io.xml.RatingContainerXmlFactory;
import mil.army.usace.hec.cwms.rating.io.xml.RatingSetContainerXmlFactory;
import mil.army.usace.hec.cwms.rating.io.xml.RatingSpecXmlFactory;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import static cwms.cda.api.Controllers.*;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.is;
Expand Down Expand Up @@ -88,7 +89,7 @@ static void cleanUp()
static void store(boolean storeTemplate) throws Exception
{
//Make sure we always have something.
createLocation(EXISTING_LOC, true, SPK);
createLocationWithVerticalDatum(EXISTING_LOC, true, SPK, VerticalDatum.NAVD88);

String ratingXml = readResourceFile("cwms/cda/api/Zanesville_Stage_Flow_COE_Production.xml");
ratingXml = ratingXml.replaceAll("Zanesville", EXISTING_LOC);
Expand Down Expand Up @@ -416,6 +417,5 @@ void test_1206_rating_create_xml() throws IOException {
.log().ifValidationFails(LogDetail.ALL,true)
.statusCode(is(HttpServletResponse.SC_CREATED));
}

}

Loading
Loading