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

Issue 693 - Rating curve retrieval #909

Merged
merged 11 commits into from
Dec 19, 2024
41 changes: 25 additions & 16 deletions cwms-data-api/src/main/java/cwms/cda/api/RatingController.java
adamkorynta marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import static cwms.cda.api.Controllers.DATE_FORMAT;
import static cwms.cda.api.Controllers.DATUM;
import static cwms.cda.api.Controllers.DELETE;
import static cwms.cda.api.Controllers.EFFECTIVE_DATE;
import static cwms.cda.api.Controllers.END;
import static cwms.cda.api.Controllers.EXAMPLE_DATE;
import static cwms.cda.api.Controllers.FORMAT;
Expand Down Expand Up @@ -296,19 +297,16 @@ public void getAll(@NotNull Context ctx) {

ContentType contentType = Formats.parseHeaderAndQueryParm(header, format, RatingAliasMarker.class);

if (format.isEmpty())
{
if (format.isEmpty()) {
//Use the full content type here (i.e. application/json;version=2)
ctx.contentType(contentType.toString());
}
else
{
} else {
//Legacy content type only includes the basic type (i.e. application/json)
ctx.contentType(contentType.getType());
}

//At the moment, we still use the legacy formatting here, since we don't have a newer API for serializing/deserializing
//a collection of rating sets - unlike getOne.
//At the moment, we still use the legacy formatting here, since we don't have a newer API for
// serializing/deserializing a collection of rating sets - unlike getOne.
String legacyFormat = Formats.getLegacyTypeFromContentType(contentType);
String results = ratingDao.retrieveRatings(legacyFormat, names, unit, datum, office, start,
end, timezone);
Expand All @@ -322,7 +320,8 @@ public void getAll(@NotNull Context ctx) {

@OpenApi(
pathParams = {
@OpenApiParam(name = RATING_ID, required = true, description = "The rating-id of the effective dates to be retrieve. "),
@OpenApiParam(name = RATING_ID, required = true, description = "The rating-id of the effective "
+ "dates to be retrieve. "),
},
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description =
Expand All @@ -339,6 +338,10 @@ public void getAll(@NotNull Context ctx) {
+ "otherwise specified), as well as the time zone of any times in the"
+ " response. If this field is not specified, the default time zone "
+ "of UTC shall be used."),
@OpenApiParam(name = EFFECTIVE_DATE, description = "Specifies the "
adamkorynta marked this conversation as resolved.
Show resolved Hide resolved
+ "date to find the closest match to for retrieving a specific rating curve. This date is used "
+ "instead of the time window specified by start and end. "
+ "The format for this field is ISO 8601 extended."),
@OpenApiParam(name = METHOD, description = "Specifies "
+ "the retrieval method used. If no method is provided EAGER will be used.",
type = RatingSet.DatabaseLoadMethod.class),
Expand All @@ -354,8 +357,13 @@ public void getAll(@NotNull Context ctx) {
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");
Instant effectiveDate = null;
String effectiveDateParam = ctx.queryParam(EFFECTIVE_DATE);
if (effectiveDateParam != null) {
effectiveDate = DateUtils.parseUserDate(effectiveDateParam, timezone).toInstant();
}

Instant beginInstant = null;
String begin = ctx.queryParam(BEGIN);
Expand All @@ -369,11 +377,13 @@ public void getOne(@NotNull Context ctx, @NotNull String rating) {
endInstant = DateUtils.parseUserDate(end, timezone).toInstant();
}

String officeId = ctx.queryParam(OFFICE);

RatingSet.DatabaseLoadMethod method = ctx.queryParamAsClass(METHOD,
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, effectiveDate);
if (body != null) {
ctx.result(body);
ctx.status(HttpCode.OK);
Expand All @@ -385,7 +395,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, Instant effectiveDate) {
String retval = null;

try (final Timer.Context ignored = markAndTime("getRatingSetString")) {
Expand All @@ -398,7 +408,7 @@ private String getRatingSetString(Context ctx, RatingSet.DatabaseLoadMethod meth
if (isJson || isXml) {
ctx.contentType(contentType.toString());
try {
RatingSet ratingSet = getRatingSet(ctx, method, officeId, rating, begin, end);
RatingSet ratingSet = getRatingSet(ctx, method, officeId, rating, begin, end, effectiveDate);
if (ratingSet != null) {
if (isJson) {
retval = JsonRatingUtils.toJson(ratingSet);
Expand All @@ -424,8 +434,7 @@ private String getRatingSetString(Context ctx, RatingSet.DatabaseLoadMethod meth
} else {
CdaError re = new CdaError("Currently supporting only: " + Formats.JSONV2
+ " and " + Formats.XMLV2);
logger.log(Level.WARNING, "Provided accept header not recognized:"
+ acceptHeader, re);
logger.log(Level.WARNING, String.format("Provided accept header not recognized: %s", acceptHeader), re);
ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED);
ctx.json(CdaError.notImplemented());
}
Expand All @@ -437,13 +446,13 @@ private String getRatingSetString(Context ctx, RatingSet.DatabaseLoadMethod meth

private RatingSet getRatingSet(Context ctx, RatingSet.DatabaseLoadMethod method,
String officeId, String rating, Instant begin,
Instant end) throws IOException, RatingException {
Instant end, Instant effectiveDate) throws IOException, RatingException {
RatingSet ratingSet;
try (final Timer.Context ignored = markAndTime("getRatingSet")) {
DSLContext dsl = getDslContext(ctx);

RatingDao ratingDao = getRatingDao(dsl);
ratingSet = ratingDao.retrieve(method, officeId, rating, begin, end);
ratingSet = ratingDao.retrieve(method, officeId, rating, begin, end, effectiveDate);
}

return ratingSet;
Expand Down
4 changes: 2 additions & 2 deletions cwms-data-api/src/main/java/cwms/cda/data/dao/RatingDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@

public interface RatingDao {

static final Pattern officeMatcher = Pattern.compile(".*office-id=\"(.*?)\"");
Pattern officeMatcher = Pattern.compile(".*office-id=\"(.*?)\"");

void create(String ratingSet, boolean storeTemplate) throws IOException, RatingException;

RatingSet retrieve(RatingSet.DatabaseLoadMethod method, String officeId, String specificationId,
Instant start, Instant end) throws IOException, RatingException;
Instant start, Instant end, Instant effectiveDate) throws IOException, RatingException;

String retrieveRatings(String format, String names, String unit, String datum, String office,
String start, String end, String timezone);
Expand Down
69 changes: 53 additions & 16 deletions cwms-data-api/src/main/java/cwms/cda/data/dao/RatingSetDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,20 @@
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import hec.data.RatingException;
import hec.data.cwmsRating.RatingSet;
import java.io.IOException;
import java.sql.Connection;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.ZoneId;
import java.util.List;
import mil.army.usace.hec.cwms.rating.io.jdbc.ConnectionProvider;
import mil.army.usace.hec.cwms.rating.io.jdbc.RatingJdbcFactory;
import org.jooq.DSLContext;
import org.jooq.Result;
import org.jooq.exception.DataAccessException;
import usace.cwms.db.jooq.codegen.packages.CWMS_RATING_PACKAGE;
import usace.cwms.db.jooq.codegen.tables.AV_RATING_LOCAL;

import java.io.IOException;
import java.sql.Connection;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.List;

public class RatingSetDao extends JooqDao<RatingSet> implements RatingDao {

Expand All @@ -57,8 +60,7 @@ public void create(String ratingSetXml, boolean storeTemplate) throws IOExceptio
DSLContext context = getDslContext(c, office);
String errs = CWMS_RATING_PACKAGE.call_STORE_RATINGS_XML__5(context.configuration(),
ratingSetXml, "T", storeTemplate ? "T" : "F");
if (errs != null && !errs.isEmpty())
{
if (errs != null && !errs.isEmpty()) {
throw new DataAccessException(errs);
}
});
Expand All @@ -85,8 +87,9 @@ private static String extractOfficeId(String ratingSet) throws JsonProcessingExc

@Override
public RatingSet retrieve(RatingSet.DatabaseLoadMethod method, String officeId,
String specificationId, Instant startZdt, Instant endZdt
String specificationId, Instant startZdt, Instant endZdt, Instant effectiveDateParam
) throws IOException, RatingException {
AV_RATING_LOCAL view = AV_RATING_LOCAL.AV_RATING_LOCAL;

final RatingSet[] retval = new RatingSet[1];
try {
Expand All @@ -110,9 +113,43 @@ public RatingSet retrieve(RatingSet.DatabaseLoadMethod method, String officeId,

RatingSet.DatabaseLoadMethod finalMethod = method;

connection(dsl, c -> retval[0] =
RatingJdbcFactory.ratingSet(finalMethod, new RatingConnectionProvider(c), officeId,
specificationId, start, end, false));
if (effectiveDateParam != null) {

String ratingId = null;
Long difference = null;
Instant startInstant = null;
Instant endInstant = null;
Result<?> results = connectionResult(dsl, c ->
dsl.select(view.RATING_ID, view.EFFECTIVE_DATE, view.RATING_CODE).from(view)
adamkorynta marked this conversation as resolved.
Show resolved Hide resolved
.where(view.OFFICE_ID.eq(officeId)
.and(view.RATING_ID.eq(specificationId))
).fetch()
);
for (int i = 0; i < results.size(); i++) {
Timestamp effectiveDate = results.getValue(i, view.EFFECTIVE_DATE);
long effectiveDifference = Math.abs(effectiveDate.toInstant().toEpochMilli() - effectiveDateParam.toEpochMilli());
if (difference == null || effectiveDifference < difference) {
difference = effectiveDifference;
ratingId = results.getValue(i, view.RATING_ID);
startInstant = effectiveDate.toInstant().atZone(ZoneId.of("UTC")).toInstant();
endInstant = effectiveDate.toInstant().atZone(ZoneId.of("UTC")).toInstant();
}
}
if (ratingId == null) {
return null;
}
final Instant finalStartInstant = startInstant;
final String ratingIdFinal = ratingId;
final Instant finalEndInstant = endInstant;
connection(dsl, c -> retval[0] =
RatingJdbcFactory.ratingSet(finalMethod, new RatingConnectionProvider(c), officeId,
ratingIdFinal, finalStartInstant.toEpochMilli(),
finalEndInstant.toEpochMilli(), false));
} else {
connection(dsl, c -> retval[0] =
RatingJdbcFactory.ratingSet(finalMethod, new RatingConnectionProvider(c), officeId,
specificationId, start, end, false));
}

} catch (DataAccessException ex) {
Throwable cause = ex.getCause();
Expand Down Expand Up @@ -151,7 +188,7 @@ public void store(String ratingSetXml, boolean includeTemplate) throws IOExcepti
public void delete(String officeId, String specificationId, Instant start, Instant end) {
Timestamp startDate = new Timestamp(start.toEpochMilli());
Timestamp endDate = new Timestamp(end.toEpochMilli());
dsl.connection(c->
dsl.connection(c ->
CWMS_RATING_PACKAGE.call_DELETE_RATINGS(
getDslContext(c,officeId).configuration(), specificationId, startDate,
endDate, "UTC", officeId
Expand All @@ -170,15 +207,15 @@ public String retrieveRatings(String format, String names, String unit, String d
}

private static final class RatingConnectionProvider implements ConnectionProvider {
private final Connection c;
private final Connection conn;

private RatingConnectionProvider(Connection c) {
this.c = c;
private RatingConnectionProvider(Connection conn) {
this.conn = conn;
}

@Override
public Connection getConnection() {
return c;
return conn;
}

@Override
Expand Down
Loading
Loading