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
3 changes: 2 additions & 1 deletion cwms-data-api/src/main/java/cwms/cda/ApiServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@
import cwms.cda.api.TimeSeriesController;
import cwms.cda.api.TimeSeriesFilteredController;
import cwms.cda.api.TimeSeriesGroupController;
import cwms.cda.api.TimeSeriesVersionsController;
import cwms.cda.api.TimeSeriesIdentifierDescriptorController;
import cwms.cda.api.TimeSeriesRecentController;
import cwms.cda.api.TimeSeriesVersionsController;
import cwms.cda.api.TimeZoneController;
import cwms.cda.api.TurbineChangesDeleteController;
import cwms.cda.api.TurbineChangesGetController;
Expand Down Expand Up @@ -473,6 +473,7 @@ protected void configureRoutes() {

VerticalDatumController vdiController = new VerticalDatumController(metrics);
String vdiPath = format("/location/{%s}/vertical-datum", Controllers.LOCATION_ID);
get("/location/vertical-datum", vdiController::getAll);
get(vdiPath, ctx -> vdiController.getOne(ctx, ctx.pathParam(Controllers.LOCATION_ID)));
addCacheControl(vdiPath, 5, TimeUnit.MINUTES);
post(vdiPath, vdiController::create, requiredRoles);
Expand Down
4 changes: 2 additions & 2 deletions cwms-data-api/src/main/java/cwms/cda/api/Controllers.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@
import io.javalin.core.validation.Validator;
import io.javalin.http.Context;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -75,6 +73,8 @@ public final class Controllers {

public static final String LIKE = "like";

public static final String OVERWRITE = "overwrite";

public static final String UNIT_SYSTEM = "unit-system";

public static final String TIMESERIES_CATEGORY_LIKE = "timeseries-category-like";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
import static cwms.cda.api.Controllers.DELETE;
import static cwms.cda.api.Controllers.GET_ONE;
import static cwms.cda.api.Controllers.LOCATION_ID;
import static cwms.cda.api.Controllers.LOCATION_MASK;
import static cwms.cda.api.Controllers.OFFICE;
import static cwms.cda.api.Controllers.OVERWRITE;
import static cwms.cda.api.Controllers.RESULTS;
import static cwms.cda.api.Controllers.SIZE;
import static cwms.cda.api.Controllers.UNIT;
Expand All @@ -42,6 +44,7 @@
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.google.common.flogger.FluentLogger;
import cwms.cda.api.errors.AlreadyExists;
import cwms.cda.api.errors.CdaError;
import cwms.cda.api.errors.ExceptionTraceSupport;
import cwms.cda.data.dao.VerticalDatumDao;
Expand All @@ -59,6 +62,7 @@
import io.javalin.plugin.openapi.annotations.OpenApiRequestBody;
import io.javalin.plugin.openapi.annotations.OpenApiResponse;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
Expand All @@ -68,6 +72,7 @@ public final class VerticalDatumController implements CrudHandler {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
// NOTE: manually expanded due to limits of OpenApi Annotations.
private static final String VDI_PATH = "/location/{location-id}/vertical-datum";
private static final String VDI_ALL_PATH = "/location/vertical-datum";
private final MetricRegistry metrics;
private final Histogram requestResultSize;

Expand All @@ -81,9 +86,49 @@ private Timer.Context markAndTime(String subject) {
return Controllers.markAndTime(metrics, getClass().getName(), subject);
}

@OpenApi(
queryParams = {
@OpenApiParam(name = LOCATION_MASK, description = "Filters on the location ID."),
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office."),
@OpenApiParam(name = UNIT,
description = "Specifies the unit of measure for elevation/offsets (e.g., m or ft). Default is m.")
},
responses = {
@OpenApiResponse(status = Controllers.STATUS_200,
content = {@OpenApiContent(type = Formats.JSONV1, from = VerticalDatumInfo.class),
@OpenApiContent(type = Formats.JSON, from = VerticalDatumInfo.class),
@OpenApiContent(type = Formats.XMLV1, from = VerticalDatumInfo.class),
@OpenApiContent(type = Formats.XML, from = VerticalDatumInfo.class)})
},
description = "Returns Vertical Datum Info for all locations.",
path = VDI_ALL_PATH,
tags = {LOCATIONS_TAG}
)
@Override
public void getAll(@NotNull Context ctx) {
ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
String office = requiredParam(ctx, OFFICE);
String units = ctx.queryParamAsClass(UNIT, String.class).getOrDefault("m");
String locationMask = ctx.queryParamAsClass(LOCATION_MASK, String.class).getOrDefault(null);
try (Timer.Context ignored = markAndTime(GET_ONE)) {
DSLContext dsl = getDslContext(ctx);
VerticalDatumDao dao = new VerticalDatumDao(dsl);
List<VerticalDatumInfo> info = dao.retrieveVerticalDatumInfoList(office, locationMask, units);
String formatHeader = ctx.header(Header.ACCEPT);
ContentType contentType = Formats.parseHeader(formatHeader, VerticalDatumInfo.class);
ctx.contentType(contentType.toString());
String serialized = Formats.format(contentType, info, VerticalDatumInfo.class);
requestResultSize.update(serialized.length());
ctx.status(HttpServletResponse.SC_OK);

byte[] bytes = serialized.getBytes();
ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length));
ctx.res.getOutputStream().write(bytes);
} catch (IOException ex) {
CdaError error = ExceptionTraceSupport.buildError(ctx,
"Failed to process request to retrieve Vertical Datum Info", ex);
logger.atSevere().withCause(ex).log("Failed to process request to retrieve Vertical Datum Info");
ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error);
}
}

@OpenApi(
Expand Down Expand Up @@ -117,7 +162,6 @@ public void getOne(@NotNull Context ctx, @NotNull String locationId) {
ContentType contentType = Formats.parseHeader(formatHeader, VerticalDatumInfo.class);
ctx.contentType(contentType.toString());
String serialized = Formats.format(contentType, info);
ctx.status(HttpServletResponse.SC_OK);
requestResultSize.update(serialized.length());
ctx.status(HttpServletResponse.SC_OK);

Expand All @@ -133,42 +177,54 @@ public void getOne(@NotNull Context ctx, @NotNull String locationId) {
}

@OpenApi(
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = VerticalDatumInfo.class, type = Formats.JSONV1),
@OpenApiContent(from = VerticalDatumInfo.class, type = Formats.XMLV1)
},
required = true),
queryParams = {
@OpenApiParam(name = LOCATION_ID, required = true, description = "Specifies the location id for this vertical-datum-info."),
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office.")
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = VerticalDatumInfo.class, type = Formats.JSONV1),
@OpenApiContent(from = VerticalDatumInfo.class, type = Formats.XMLV1)
},
description = "Create Vertical Datum Info for a Location",
method = HttpMethod.POST,
path = VDI_PATH,
tags = {LOCATIONS_TAG},
responses = {
@OpenApiResponse(status = Controllers.STATUS_201, description = "Vertical Datum Info successfully stored to CWMS.")
}
required = true),
queryParams = {
@OpenApiParam(name = LOCATION_ID, required = true, description = "Specifies the location id for this vertical-datum-info."),
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office."),
@OpenApiParam(name = OVERWRITE, type = Boolean.class, description = "If true, will overwrite any existing "
+ "vertical-datum-info for the specified location. Default is false.")
},
description = "Create Vertical Datum Info for a Location",
method = HttpMethod.POST,
path = VDI_PATH,
tags = {LOCATIONS_TAG},
responses = {
@OpenApiResponse(status = Controllers.STATUS_201,
description = "Vertical Datum Info successfully stored to CWMS.")
}
)
@Override
public void create(@NotNull Context ctx) {
try (Timer.Context ignored = markAndTime(CREATE)) {
String formatHeader = ctx.req.getContentType();
boolean overwrite = ctx.queryParamAsClass(OVERWRITE, Boolean.class).getOrDefault(false);
ContentType contentType = Formats.parseHeader(formatHeader, VerticalDatumInfo.class);
VerticalDatumInfo info = Formats.parseContent(contentType, ctx.body(), VerticalDatumInfo.class);
//allow locationId and office to be specified in either the body or as query params, but require them to be present in one of those places
String locationId = info.getLocation();
String office = info.getOffice();
if(locationId == null || locationId.isBlank()) {
if (locationId == null || locationId.isBlank()) {
locationId = requiredParam(ctx, LOCATION_ID);
}
if(office == null || office.isBlank()) {
if (office == null || office.isBlank()) {
office = requiredParam(ctx, OFFICE);
}
DSLContext dsl = getDslContext(ctx);
VerticalDatumDao dao = new VerticalDatumDao(dsl);
dao.createVerticalDatumInfo(office, locationId, info);
try {
dao.createVerticalDatumInfo(office, locationId, info);
} catch (AlreadyExists ex) {
if (overwrite) {
dao.updateVerticalDatumInfo(office, locationId, info);
} else {
throw ex;
}
}
StatusResponse re = new StatusResponse(office,
"Vertical Datum Info successfully stored to CWMS.", locationId);
ctx.status(HttpServletResponse.SC_CREATED).json(re);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,14 @@
import cwms.cda.api.errors.NotFoundException;
import cwms.cda.data.dto.VerticalDatumInfo;
import cwms.cda.formatters.xml.XMLv1;
import java.util.ArrayList;
import java.util.List;
import org.jooq.Condition;
import org.jooq.DSLContext;
import org.jooq.Record1;
import org.jooq.Result;
import usace.cwms.db.jooq.codegen.packages.CWMS_LOC_PACKAGE;
import usace.cwms.db.jooq.codegen.packages.CWMS_UTIL_PACKAGE;
import usace.cwms.db.jooq.codegen.tables.AV_VERT_DATUM_OFFSET;

/**
Expand All @@ -51,6 +56,44 @@ public VerticalDatumInfo retrieveVerticalDatumInfo(String officeId, String locat
});
}

public List<VerticalDatumInfo> retrieveVerticalDatumInfoList(String officeId, String locMask, String units) {
AV_VERT_DATUM_OFFSET view = AV_VERT_DATUM_OFFSET.AV_VERT_DATUM_OFFSET;
List<VerticalDatumInfo> resultList = new ArrayList<>();
return connectionResult(dsl, conn -> {
DSLContext ctx = getDslContext(conn, officeId);
Condition whereCondition = view.OFFICE_ID.eq(officeId);

if (locMask != null && !locMask.isEmpty()) {
whereCondition = whereCondition.and(view.LOCATION_ID.like(locMask));
}
Result<Record1<usace.cwms.db.jooq.codegen.tables.records.AV_VERT_DATUM_OFFSET>> result =
ctx.select(view).from(view)
.where(whereCondition)
.fetch();
for (Record1<usace.cwms.db.jooq.codegen.tables.records.AV_VERT_DATUM_OFFSET> rec : result) {
usace.cwms.db.jooq.codegen.tables.records.AV_VERT_DATUM_OFFSET tab = rec.value1();
String desc = tab.getDESCRIPTION();
VerticalDatumInfo vdi = new VerticalDatumInfo.Builder()
.withOffice(tab.getOFFICE_ID())
.withLocation(tab.getLOCATION_ID())
.withNativeDatum(tab.getVERTICAL_DATUM_ID_1())
.withLocalDatumName(tab.getVERTICAL_DATUM_ID_2())
.withOffset(desc.contains("ESTIMATE"), tab.getVERTICAL_DATUM_ID_2(), tab.getOFFSET())
.build();
if (!units.equalsIgnoreCase("m")) {
vdi = new VerticalDatumInfo.Builder()
.from(vdi)
.withUnit(units)
.withElevation(CWMS_UTIL_PACKAGE.call_CONVERT_UNITS(ctx.configuration(), vdi.getElevation(),
"m", units))
.build();
}
resultList.add(vdi);
}
return resultList;
});
}

public void createVerticalDatumInfo(String officeId, String locationId, VerticalDatumInfo vdi) {
connection(dsl, conn -> {
DSLContext ctx = getDslContext(conn, officeId);
Expand Down Expand Up @@ -98,7 +141,7 @@ private void verifyVerticalDatumInfoExists(DSLContext ctx, String officeId, Stri
.where(AV_VERT_DATUM_OFFSET.AV_VERT_DATUM_OFFSET.LOCATION_ID.eq(locationId))
.and(AV_VERT_DATUM_OFFSET.AV_VERT_DATUM_OFFSET.OFFICE_ID.eq(officeId))
.fetchOne();
if(result == null) {
if (result == null) {
throw new NotFoundException("No vertical datum info found for location " + locationId + " in office " + officeId);
}
}
Expand Down
Loading
Loading