From f934bd31156b28bfef8210c74b07dc61ba788ed1 Mon Sep 17 00:00:00 2001 From: zack-rma Date: Mon, 8 Jun 2026 14:50:50 -0700 Subject: [PATCH 1/6] Initial update to ratings endpoints to properly report content length --- .../cwms/cda/api/rating/RatingController.java | 30 +- .../cda/api/rating/RatingSpecController.java | 30 +- .../api/rating/RatingTemplateController.java | 26 +- .../api/rating/RatingsControllerTestIT.java | 128 ++++ .../resources/cwms/cda/api/long-rating.xml | 694 ++++++++++++++++++ 5 files changed, 885 insertions(+), 23 deletions(-) create mode 100644 cwms-data-api/src/test/resources/cwms/cda/api/long-rating.xml diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingController.java b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingController.java index 71e4f02b57..e4596827a6 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingController.java @@ -24,7 +24,6 @@ package cwms.cda.api.rating; -import static com.codahale.metrics.MetricRegistry.name; import static cwms.cda.api.Controllers.AT; import static cwms.cda.api.Controllers.BEGIN; import static cwms.cda.api.Controllers.CREATE; @@ -39,8 +38,6 @@ import static cwms.cda.api.Controllers.OFFICE; import static cwms.cda.api.Controllers.RATING_ID; import static cwms.cda.api.Controllers.REPLACE_BASE_CURVE; -import static cwms.cda.api.Controllers.RESULTS; -import static cwms.cda.api.Controllers.SIZE; import static cwms.cda.api.Controllers.STATUS_200; import static cwms.cda.api.Controllers.STATUS_201; import static cwms.cda.api.Controllers.STATUS_404; @@ -55,12 +52,11 @@ import static cwms.cda.api.Controllers.requiredParam; import static cwms.cda.data.dao.JooqDao.getDslContext; -import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; -import cwms.cda.api.BaseCrudHandler; import com.fasterxml.jackson.dataformat.xml.XmlMapper; -import cwms.cda.api.Controllers; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.BaseCrudHandler; import cwms.cda.api.errors.CdaError; import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JsonRatingUtils; @@ -79,7 +75,6 @@ import cwms.cda.helpers.DateUtils; import hec.data.RatingException; import hec.data.cwmsRating.RatingSet; -import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.core.validation.JavalinValidation; import io.javalin.http.Context; @@ -92,10 +87,8 @@ import io.javalin.plugin.openapi.annotations.OpenApiResponse; import java.io.IOException; import java.time.Instant; -import com.google.common.flogger.FluentLogger; 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; @@ -353,9 +346,17 @@ public void getAll(@NotNull Context ctx) { end, timezone); ctx.status(HttpServletResponse.SC_OK); - ctx.result(results); addDeprecatedContentTypeWarning(ctx, contentType); updateResultSize(results.length()); + + byte[] bytes = results.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException e) { + CdaError re = ExceptionTraceSupport.buildError(ctx, + "Failed to process request to retrieve Ratings", e); + logger.atInfo().withCause(e).log("%s", re); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -426,9 +427,16 @@ public void getOne(@NotNull Context ctx, @NotNull String rating) { String body = getRatingSetString(ctx, method, officeId, rating, beginInstant, endInstant, verticalDatum); if (body != null) { - ctx.result(body); ctx.status(HttpCode.OK); + byte[] bytes = body.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } + } catch (IOException e) { + CdaError re = ExceptionTraceSupport.buildError(ctx, + "Failed to process request to retrieve RatingSet", e); + logger.atInfo().withCause(e).log("%s", re); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingSpecController.java b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingSpecController.java index 41eb577b58..53608198b2 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingSpecController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingSpecController.java @@ -32,6 +32,7 @@ import com.codahale.metrics.Timer; import cwms.cda.api.Controllers; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.RatingSpecDao; import cwms.cda.data.dto.rating.RatingSpec; @@ -49,6 +50,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.util.Optional; import com.google.common.flogger.FluentLogger; @@ -135,9 +137,17 @@ public void getAll(Context ctx) { ctx.contentType(contentType.toString()); String result = Formats.format(contentType, ratingSpecs); - ctx.result(result); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException e) { + CdaError re = ExceptionTraceSupport.buildError(ctx, + "Failed to process request to retrieve Ratings", e); + logger.atInfo().log("%s%sfor request %s", re, System.lineSeparator(), ctx.fullUrl()); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -164,7 +174,7 @@ public void getAll(Context ctx) { tags = {TAG} ) @Override - public void getOne(Context ctx, String ratingId) { + public void getOne(Context ctx, @NotNull String ratingId) { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(formatHeader, RatingSpec.class); @@ -179,17 +189,25 @@ public void getOne(Context ctx, String ratingId) { if (template.isPresent()) { String result = Formats.format(contentType, template.get()); - ctx.result(result); ctx.contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { CdaError re = new CdaError("Unable to find Rating Spec based on parameters " + "given"); logger.atInfo().log("%s%sfor request %s", re, System.lineSeparator(), ctx.fullUrl()); ctx.status(HttpServletResponse.SC_NOT_FOUND).json(re); } + } catch (IOException e) { + CdaError re = ExceptionTraceSupport.buildError(ctx, + "Failed to process request to retrieve Ratings", e); + logger.atInfo().log("%s%sfor request %s", re, System.lineSeparator(), ctx.fullUrl()); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -215,7 +233,7 @@ protected RatingSpecDao getRatingSpecDao(DSLContext dsl) { tags = {TAG} ) @Override - public void create(Context ctx) { + public void create(@NotNull Context ctx) { try (final Timer.Context ignored = markAndTime(CREATE)) { DSLContext dsl = getDslContext(ctx); @@ -247,7 +265,7 @@ public void create(Context ctx) { @OpenApi(ignore = true) @Override - public void update(Context ctx, String locationCode) { + public void update(Context ctx, @NotNull String locationCode) { ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented()); } @@ -266,7 +284,7 @@ public void update(Context ctx, String locationCode) { tags = {TAG} ) @Override - public void delete(Context ctx, @NotNull String ratingSpecId) { + public void delete(@NotNull Context ctx, @NotNull String ratingSpecId) { try (final Timer.Context ignored = markAndTime(DELETE)) { DSLContext dsl = getDslContext(ctx); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingTemplateController.java b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingTemplateController.java index 6f55c1039b..98dee2dfa0 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingTemplateController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingTemplateController.java @@ -132,8 +132,15 @@ public void getAll(Context ctx) { ctx.contentType(contentType.toString()); String result = Formats.format(contentType, ratingTemplates); - ctx.result(result); requestResultSize.update(result.length()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException ex) { + CdaError re = new CdaError("Error while writing response "); + logger.atInfo().log("%s%sfor request %s", re, System.lineSeparator(), ctx.fullUrl()); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -164,7 +171,7 @@ private RatingTemplateDao getRatingTemplateDao(DSLContext dsl) { tags = {TAG} ) @Override - public void getOne(Context ctx, String templateId) { + public void getOne(Context ctx, @NotNull String templateId) { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(formatHeader, RatingTemplate.class); @@ -180,17 +187,24 @@ public void getOne(Context ctx, String templateId) { if (template.isPresent()) { String result = Formats.format(contentType, template.get()); - ctx.result(result); ctx.contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { CdaError re = new CdaError("Unable to find Rating Template based on " + "parameters given"); logger.atInfo().log("%s%sfor request %s", re, System.lineSeparator(), ctx.fullUrl()); ctx.status(HttpServletResponse.SC_NOT_FOUND).json(re); } + } catch (IOException ex) { + CdaError re = new CdaError("Error while writing response "); + logger.atInfo().log("%s%sfor request %s", re, System.lineSeparator(), ctx.fullUrl()); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -210,7 +224,7 @@ public void getOne(Context ctx, String templateId) { tags = {TAG} ) @Override - public void create(Context ctx) { + public void create(@NotNull Context ctx) { try (final Timer.Context ignored = markAndTime(CREATE)){ DSLContext dsl = getDslContext(ctx); @@ -252,7 +266,7 @@ private static String translateJsonToXml(String body) { @OpenApi(ignore = true) @Override - public void update(Context ctx, String locationCode) { + public void update(@NotNull Context ctx, @NotNull String locationCode) { ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented()); } @@ -271,7 +285,7 @@ public void update(Context ctx, String locationCode) { tags = {TAG} ) @Override - public void delete(Context ctx, String ratingTemplateId) { + public void delete(@NotNull Context ctx, @NotNull String ratingTemplateId) { try (final Timer.Context ignored = markAndTime(DELETE)){ DSLContext dsl = getDslContext(ctx); diff --git a/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java b/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java index 7c3f269d5b..e97f4dd7d5 100644 --- a/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java +++ b/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java @@ -55,13 +55,16 @@ class RatingsControllerTestIT extends DataApiTestIT { static final String EXISTING_LOC = "RatingsControllerTestIT"; + static final String EXISTING_LOC_LONG = "RatingsControlTestLong"; private static final String EXISTING_SPEC = EXISTING_LOC + ".Stage;Flow.COE.Production"; + private static final String EXISTING_SPEC_LONG = EXISTING_LOC_LONG + ".Stage;Flow.COE.Production"; private static final String TEMPLATE = "Stage;Flow.COE"; static final String SPK = "SPK"; @BeforeAll static void beforeAll() throws Exception { store(false); + storeLong(); } @AfterAll @@ -193,6 +196,113 @@ static void store(boolean storeTemplate) throws Exception .statusCode(is(HttpServletResponse.SC_CREATED)); } + static void storeLong() throws Exception + { + //Make sure we always have something. + createLocationWithVerticalDatum(EXISTING_LOC_LONG, true, SPK, VerticalDatum.NAVD88); + + String ratingXml = readResourceFile("cwms/cda/api/long-rating.xml"); + ratingXml = ratingXml.replaceAll("Zanesville", EXISTING_LOC_LONG); + String ratingXml2 = ratingXml.replaceAll("2002-04-09T13:53:01Z", "2016-06-06T00:00:00Z"); + String ratingXml3 = ratingXml.replaceAll("2002-04-09T13:53:01Z", "2085-06-06T00:00:00Z"); + RatingSetContainer container = RatingSetContainerXmlFactory.ratingSetContainerFromXml(ratingXml); + RatingSetContainer container2 = RatingSetContainerXmlFactory.ratingSetContainerFromXml(ratingXml2); + RatingSetContainer container3 = RatingSetContainerXmlFactory.ratingSetContainerFromXml(ratingXml3); + RatingSpecContainer specContainer = container.ratingSpecContainer; + specContainer.officeId = SPK; + specContainer.specOfficeId = SPK; + specContainer.locationId = EXISTING_LOC_LONG; + String specXml = RatingSpecXmlFactory.toXml(specContainer, "", 0, true); + String templateXml = RatingSpecXmlFactory.toXml(specContainer, "", 0); + String setXml = RatingContainerXmlFactory.toXml(container, "", 0, true, false); + String setXml2 = RatingContainerXmlFactory.toXml(container2, "", 0, true, false); + String setXml3 = RatingContainerXmlFactory.toXml(container3, "", 0, true, false); + TestAccounts.KeyUser user = TestAccounts.KeyUser.SPK_NORMAL; + + //Create Template + given() + .log().ifValidationFails(LogDetail.ALL,true) + .contentType(Formats.XMLV2) + .body(templateXml) + .header("Authorization", user.toHeaderValue()) + .queryParam(OFFICE, SPK) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("/ratings/template") + .then() + .log().ifValidationFails(LogDetail.ALL,true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)); + + //Create Spec + given() + .log().ifValidationFails(LogDetail.ALL,true) + .contentType(Formats.XMLV2) + .body(specXml) + .header("Authorization", user.toHeaderValue()) + .queryParam(OFFICE, SPK) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("/ratings/spec") + .then() + .log().ifValidationFails(LogDetail.ALL,true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)); + + //Create the set + given() + .log().ifValidationFails(LogDetail.ALL,true) + .contentType(Formats.XMLV2) + .body(setXml) + .header("Authorization", user.toHeaderValue()) + .queryParam(OFFICE, SPK) + .queryParam(STORE_TEMPLATE, false) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("/ratings") + .then() + .log().ifValidationFails(LogDetail.ALL,true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)); + + //Create the second set + given() + .log().ifValidationFails(LogDetail.ALL,true) + .contentType(Formats.XMLV2) + .body(setXml2) + .header("Authorization", user.toHeaderValue()) + .queryParam(OFFICE, SPK) + .queryParam(STORE_TEMPLATE, false) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("/ratings") + .then() + .log().ifValidationFails(LogDetail.ALL,true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)); + + // Create the third set + given() + .log().ifValidationFails(LogDetail.ALL,true) + .contentType(Formats.XMLV2) + .body(setXml3) + .header("Authorization", user.toHeaderValue()) + .queryParam(OFFICE, SPK) + .queryParam(STORE_TEMPLATE, false) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("/ratings") + .then() + .log().ifValidationFails(LogDetail.ALL,true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)); + } + @ParameterizedTest @EnumSource(GetAllLegacyTest.class) void test_getAll_legacy(GetAllLegacyTest test) { @@ -314,6 +424,24 @@ void test_get_one_latest() { assertEquals("2016-06-06T00:00:00Z", effectiveDate); } + @Test + void get_one_with_content_length() { + given() + .log().ifValidationFails(LogDetail.ALL,true) + .accept(Formats.JSON) + .queryParam(OFFICE, SPK) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("/ratings/" + EXISTING_SPEC_LONG) + .then() + .log().ifValidationFails(LogDetail.ALL,true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .header("Content-Length", is("19831")) + .contentType(is(Formats.JSONV2)); + } + enum GetOneTest { DEFAULT(Formats.DEFAULT, Formats.XMLV2), diff --git a/cwms-data-api/src/test/resources/cwms/cda/api/long-rating.xml b/cwms-data-api/src/test/resources/cwms/cda/api/long-rating.xml new file mode 100644 index 0000000000..3e953c2bb1 --- /dev/null +++ b/cwms-data-api/src/test/resources/cwms/cda/api/long-rating.xml @@ -0,0 +1,694 @@ + + + + + + Stage;Flow + COE + + + Stage + LINEAR + ERROR + ERROR + + + Flow + + + + Zanesville.Stage;Flow.COE.Production + Stage;Flow.COE + Zanesville + Production + + LINEAR + NULL + NEAREST + true + false + false + false + + 4444444444 + + 4444444444 + + + + Zanesville.Stage;Flow.COE.Production + ft;cfs + 2002-04-09T13:53:01Z + 2014-06-11T14:46:00Z + true + + + + 2.37744006 + 14.1584233 + + + 2.49935994 + 25.7683304 + + + 2.56031988 + 32.2812051 + + + 2.62128012 + 40.7762591 + + + 2.68224006 + 50.4039869 + + + 2.7432 + 61.4475571 + + + 2.80415994 + 73.3406327 + + + 2.86511988 + 86.3663821 + + + 2.92608012 + 100.241637 + + + 2.98704006 + 114.40006 + + + 3.048 + 129.407989 + + + 3.10895994 + 144.415918 + + + 3.16991988 + 159.990183 + + + 3.23088012 + 176.130786 + + + 3.29184006 + 191.705051 + + + 3.3528 + 208.978328 + + + 3.41375994 + 225.968436 + + + 3.47471988 + 244.940723 + + + 3.53568012 + 264.196179 + + + 3.59664006 + 284.017971 + + + 3.6576 + 305.821943 + + + 3.71855994 + 328.47542 + + + 3.77951988 + 351.128898 + + + 3.84048012 + 373.782375 + + + 3.90144006 + 396.435852 + + + 3.9624 + 416.257645 + + + 4.02335994 + 438.911122 + + + 4.08431988 + 464.396284 + + + 4.14528012 + 487.049761 + + + 4.20624006 + 509.703239 + + + 4.2672 + 532.356716 + + + 4.32815994 + 555.010193 + + + 4.38911988 + 577.66367 + + + 4.45008012 + 597.485463 + + + 4.51104006 + 620.13894 + + + 4.572 + 642.792418 + + + 4.63295994 + 659.782526 + + + 4.69391988 + 682.436003 + + + 4.75488012 + 705.08948 + + + 4.81584006 + 722.079588 + + + 4.8768 + 741.901381 + + + 4.93776024 + 761.723173 + + + 4.99871988 + 784.376651 + + + 5.05968012 + 807.030128 + + + 5.12063976 + 826.85192 + + + 5.1816 + 843.842028 + + + 5.24256024 + 866.495506 + + + 5.30351988 + 886.317298 + + + 5.36448012 + 903.307406 + + + 5.42543976 + 923.129199 + + + 5.4864 + 945.782676 + + + 5.54736024 + 962.772784 + + + 5.60831988 + 979.762892 + + + 5.66928012 + 999.584685 + + + 5.73023976 + 1016.57479 + + + 5.7912 + 1033.5649 + + + 5.82168012 + 1044.89164 + + + 5.85216024 + 1053.38669 + + + 5.88263976 + 1061.88175 + + + 5.91311988 + 1073.20849 + + + 5.9436 + 1081.70354 + + + 6.33983976 + 1254.4363 + + + 6.58368012 + 1349.29774 + + + 6.79703976 + 1438.49581 + + + 7.07136024 + 1557.42656 + + + 7.37616024 + 1676.35732 + + + 7.65048012 + 1798.11976 + + + 7.9248 + 1906.62991 + + + 8.47343976 + 2123.76349 + + + 9.20496024 + 2406.93196 + + + 10.668 + 3114.85313 + + + 12.192 + 4105.94276 + + + 13.716 + 5238.61662 + + + 15.24 + 6456.24102 + + + 17.3736 + 8778.22244 + + + 18.5 + 9750.15 + + + 19.75 + 10850.32 + + + 21.0 + 12100.78 + + + 22.25 + 13520.45 + + + 23.5 + 15125.90 + + + 24.75 + 16935.22 + + + 26.0 + 18965.88 + + + 27.25 + 21235.44 + + + 28.5 + 23765.12 + + + 29.75 + 26575.89 + + + 31.0 + 29689.65 + + + 32.37744006 + 14.1584233 + + + 32.49935994 + 25.7683304 + + + 32.56031988 + 32.2812051 + + + 32.62128012 + 40.7762591 + + + 32.68224006 + 50.4039869 + + + 32.7432 + 61.4475571 + + + 32.80415994 + 73.3406327 + + + 32.86511988 + 86.3663821 + + + 32.92608012 + 100.241637 + + + 32.98704006 + 114.40006 + + + 33.048 + 129.407989 + + + 33.10895994 + 144.415918 + + + 33.16991988 + 159.990183 + + + 33.23088012 + 176.130786 + + + 33.29184006 + 191.705051 + + + 33.3528 + 208.978328 + + + 33.41375994 + 225.968436 + + + 33.47471988 + 244.940723 + + + 33.53568012 + 264.196179 + + + 33.59664006 + 284.017971 + + + 33.6576 + 305.821943 + + + 33.71855994 + 328.47542 + + + 33.77951988 + 351.128898 + + + 33.84048012 + 373.782375 + + + 33.90144006 + 396.435852 + + + 33.9624 + 416.257645 + + + 34.02335994 + 438.911122 + + + 34.08431988 + 464.396284 + + + 34.14528012 + 487.049761 + + + 34.20624006 + 509.703239 + + + 34.2672 + 532.356716 + + + 34.32815994 + 555.010193 + + + 34.38911988 + 577.66367 + + + 34.45008012 + 597.485463 + + + 34.51104006 + 620.13894 + + + 34.572 + 642.792418 + + + 34.63295994 + 659.782526 + + + 34.69391988 + 682.436003 + + + 34.75488012 + 705.08948 + + + 34.81584006 + 722.079588 + + + 34.8768 + 741.901381 + + + 34.93776024 + 761.723173 + + + 34.99871988 + 784.376651 + + + 35.05968012 + 807.030128 + + + 35.12063976 + 826.85192 + + + 35.1816 + 843.842028 + + + 35.24256024 + 866.495506 + + + 35.30351988 + 886.317298 + + + 35.36448012 + 903.307406 + + + 35.42543976 + 923.129199 + + + 35.4864 + 945.782676 + + + 35.54736024 + 962.772784 + + + 35.60831988 + 979.762892 + + + 35.66928012 + 999.584685 + + + 35.73023976 + 1016.57479 + + + 35.7912 + 1033.5649 + + + 35.82168012 + 1044.89164 + + + 35.85216024 + 1053.38669 + + + 35.88263976 + 1061.88175 + + + 35.91311988 + 1073.20849 + + + 35.9436 + 1081.70354 + + + 36.33983976 + 1254.4363 + + + 36.58368012 + 1349.29774 + + + 36.79703976 + 1438.49581 + + + 37.07136024 + 1557.42656 + + + 37.37616024 + 1676.35732 + + + 37.65048012 + 1798.11976 + + + 37.9248 + 1906.62991 + + + 38.47343976 + 2123.76349 + + + 39.20496024 + 2406.93196 + + + + From bd1a54b54f64cd6f3081504b1395922e0f9a513c Mon Sep 17 00:00:00 2001 From: zack-rma Date: Mon, 8 Jun 2026 15:19:07 -0700 Subject: [PATCH 2/6] Add null check to resolve unit test failure --- .../java/cwms/cda/api/rating/RatingSpecController.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingSpecController.java b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingSpecController.java index 53608198b2..2e6923c487 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingSpecController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingSpecController.java @@ -51,6 +51,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiResponse; import java.io.IOException; +import java.io.OutputStream; import java.util.Optional; import com.google.common.flogger.FluentLogger; @@ -196,7 +197,12 @@ public void getOne(Context ctx, @NotNull String ratingId) { byte[] bytes = result.getBytes(); ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); - ctx.res.getOutputStream().write(bytes); + OutputStream os = ctx.res.getOutputStream(); + if (os != null) { + os.write(bytes); + } else { + ctx.result(result); + } } else { CdaError re = new CdaError("Unable to find Rating Spec based on parameters " + "given"); From 43bd7f00e8ac2a3bb227304654cb50037f66a589 Mon Sep 17 00:00:00 2001 From: zack-rma Date: Tue, 16 Jun 2026 12:30:03 -0700 Subject: [PATCH 3/6] Initial controller refactor --- .../java/cwms/cda/api/BasinController.java | 23 ++++++- .../cda/api/BinaryTimeSeriesController.java | 13 ++-- .../java/cwms/cda/api/BlobController.java | 46 +++++++++++--- .../java/cwms/cda/api/CatalogController.java | 13 +++- .../java/cwms/cda/api/CdaVersionHandler.java | 16 ++++- .../java/cwms/cda/api/ClobController.java | 24 ++++++- .../java/cwms/cda/api/CountyController.java | 16 ++++- .../api/DownstreamLocationsGetController.java | 27 ++++++-- .../cwms/cda/api/EmbankmentController.java | 54 +++++++++++++--- .../java/cwms/cda/api/EntityController.java | 62 +++++++++++++++--- .../cda/api/ForecastInstanceController.java | 46 +++++++++++--- .../cwms/cda/api/ForecastSpecController.java | 48 +++++++++++++- .../cwms/cda/api/LevelRefsController.java | 16 ++++- .../cda/api/LevelsAsTimeSeriesController.java | 26 +++++--- .../java/cwms/cda/api/LevelsController.java | 38 +++++++++-- .../cda/api/LocationCategoryController.java | 43 ++++++++++--- .../java/cwms/cda/api/LocationController.java | 44 ++++++++++--- .../cwms/cda/api/LocationGroupController.java | 43 +++++++++++-- .../cwms/cda/api/LocationKindController.java | 44 ++++++++----- .../cwms/cda/api/LookupTypeController.java | 39 +++++++++--- .../cwms/cda/api/MeasurementController.java | 38 ++++++----- .../MeasurementTimeExtentsGetController.java | 23 +++++-- .../java/cwms/cda/api/OfficeController.java | 28 +++++++-- .../cwms/cda/api/ParametersController.java | 13 +++- .../java/cwms/cda/api/PoolController.java | 33 +++++++--- .../java/cwms/cda/api/ProjectController.java | 24 +++++-- .../java/cwms/cda/api/PropertyController.java | 56 +++++++++++++---- .../cda/api/SpecifiedLevelController.java | 14 ++++- .../cwms/cda/api/StandardTextController.java | 47 +++++++++++--- .../java/cwms/cda/api/StateController.java | 14 ++++- .../java/cwms/cda/api/StreamController.java | 42 ++++++++++--- .../cda/api/StreamLocationController.java | 43 ++++++++----- .../cwms/cda/api/StreamReachController.java | 42 +++++++++---- .../cda/api/TextTimeSeriesController.java | 28 +++++++-- .../cda/api/TimeSeriesCategoryController.java | 30 +++++++-- .../cwms/cda/api/TimeSeriesController.java | 60 ++++++++++++++++-- .../cda/api/TimeSeriesFilteredController.java | 43 ++++++++++--- .../cda/api/TimeSeriesGroupController.java | 22 +++++-- ...eSeriesIdentifierDescriptorController.java | 53 ++++++++++++++-- .../cda/api/TimeSeriesRecentController.java | 15 ++++- .../java/cwms/cda/api/TimeZoneController.java | 13 +++- .../cda/api/TurbineChangesGetController.java | 30 ++++++++- .../java/cwms/cda/api/TurbineController.java | 53 +++++++++++++--- .../java/cwms/cda/api/UnitsController.java | 15 ++++- .../api/UpstreamLocationsGetController.java | 28 +++++++-- .../cwms/cda/api/VerticalDatumController.java | 25 +++++--- .../api/auth/users/UserProfileController.java | 16 +++-- .../cda/api/auth/users/UsersController.java | 63 ++++++++++++++----- .../kind/GateChangeGetAllController.java | 29 ++++++++- .../cda/api/location/kind/LockController.java | 26 +++++++- .../api/location/kind/OutletController.java | 23 ++++++- .../kind/VirtualOutletController.java | 40 +++++++++--- .../api/project/LockRevokerRightsCatalog.java | 17 ++++- .../project/ProjectChildLocationHandler.java | 16 ++++- .../cda/api/project/ProjectLockCatalog.java | 14 ++++- .../cda/api/project/ProjectLockGetOne.java | 18 +++++- .../RatingEffectiveDatesController.java | 24 +++++-- .../api/rating/RatingLatestController.java | 18 +++++- .../api/rating/RatingMetadataController.java | 19 ++++-- .../ReverseRateTimeSeriesController.java | 17 ++++- .../rating/ReverseRateValuesController.java | 16 ++++- .../java/cwms/cda/api/rss/RssHandler.java | 29 ++++++++- .../TimeSeriesProfileBase.java | 2 + .../TimeSeriesProfileCatalogController.java | 15 ++++- .../TimeSeriesProfileController.java | 14 ++++- ...eriesProfileInstanceCatalogController.java | 16 ++++- .../TimeSeriesProfileInstanceController.java | 16 ++++- .../TimeSeriesProfileParserBase.java | 2 + ...eSeriesProfileParserCatalogController.java | 14 ++++- .../TimeSeriesProfileParserController.java | 14 ++++- .../AccountingCatalogController.java | 14 ++++- .../WaterContractCatalogController.java | 14 ++++- .../watersupply/WaterContractController.java | 15 ++++- .../WaterContractTypeCatalogController.java | 15 ++++- .../WaterSupplyControllerBase.java | 4 +- .../WaterUserCatalogController.java | 14 ++++- .../api/watersupply/WaterUserController.java | 14 ++++- 77 files changed, 1712 insertions(+), 369 deletions(-) diff --git a/cwms-data-api/src/main/java/cwms/cda/api/BasinController.java b/cwms-data-api/src/main/java/cwms/cda/api/BasinController.java index bb36013228..56f4afec87 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/BasinController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/BasinController.java @@ -40,6 +40,7 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.enums.UnitSystem; import cwms.cda.api.errors.CdaError; import cwms.cda.api.errors.ExceptionTraceSupport; @@ -58,10 +59,10 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.sql.SQLException; import java.util.Collections; import java.util.List; -import com.google.common.flogger.FluentLogger; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -141,12 +142,20 @@ public void getAll(@NotNull Context ctx) { List basins = basinDao.getAllBasins(office, units); result = Formats.format(contentType, basins, cwms.cda.data.dto.basin.Basin.class); } - ctx.result(result); + ctx.contentType(contentType.toString()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } catch (SQLException ex) { CdaError error = ExceptionTraceSupport.buildError(ctx, "Error retrieving all basins", ex); LOGGER.atSevere().withCause(ex).log("Error retrieving all basins"); ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); + } catch (IOException ex) { + CdaError error = ExceptionTraceSupport.buildError(ctx, "Failed to process request to retrieve Basins", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Basins"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -212,8 +221,16 @@ public void getOne(@NotNull Context ctx, @NotNull String name) { cwms.cda.data.dto.basin.Basin basin = basinDao.getBasin(basinId, units); result = Formats.format(contentType, basin); } - ctx.result(result); + ctx.contentType(contentType.toString()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 Basin", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Basin"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/BinaryTimeSeriesController.java b/cwms-data-api/src/main/java/cwms/cda/api/BinaryTimeSeriesController.java index 7e866b7aaa..f1380fb03b 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/BinaryTimeSeriesController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/BinaryTimeSeriesController.java @@ -31,7 +31,6 @@ import static cwms.cda.api.Controllers.END; import static cwms.cda.api.Controllers.GET_ALL; import static cwms.cda.api.Controllers.NAME; -import static cwms.cda.api.Controllers.NOT_SUPPORTED_YET; import static cwms.cda.api.Controllers.OFFICE; import static cwms.cda.api.Controllers.STATUS_200; import static cwms.cda.api.Controllers.TIMEZONE; @@ -44,6 +43,7 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.binarytimeseries.TimeSeriesBinaryDao; @@ -51,7 +51,6 @@ import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; import cwms.cda.helpers.ReplaceUtils; -import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.HttpMethod; @@ -60,11 +59,10 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; -import java.io.UnsupportedEncodingException; +import java.io.IOException; import java.net.URISyntaxException; import java.net.URLEncoder; import java.time.Instant; -import com.google.common.flogger.FluentLogger; import javax.servlet.http.HttpServletResponse; import org.apache.http.client.utils.URIBuilder; import org.jetbrains.annotations.NotNull; @@ -160,10 +158,13 @@ public void getAll(@NotNull Context ctx) { ctx.contentType(contentType.toString()); String result = Formats.format(contentType, binaryTimeSeries); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); - } catch (URISyntaxException | UnsupportedEncodingException ex) { + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (URISyntaxException | IOException ex) { CdaError re = ExceptionTraceSupport.buildError(ctx, "Failed to process request: " + ex.getLocalizedMessage(), ex); logger.atSevere().withCause(ex).log("%s", re); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/BlobController.java b/cwms-data-api/src/main/java/cwms/cda/api/BlobController.java index 0c796b127f..60f5c40977 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/BlobController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/BlobController.java @@ -1,21 +1,40 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; +import static cwms.cda.api.Controllers.BLOB_ID; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.CURSOR; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.FAIL_IF_EXISTS; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.LIKE; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PAGE; +import static cwms.cda.api.Controllers.PAGE_SIZE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.queryParamAsClass; +import static cwms.cda.api.Controllers.requiredParam; -import static cwms.cda.api.Controllers.*; - -import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; -import cwms.cda.data.dao.*; +import cwms.cda.api.errors.ExceptionTraceSupport; +import cwms.cda.data.dao.BlobAccess; +import cwms.cda.data.dao.BlobDao; +import cwms.cda.data.dao.JooqDao; +import cwms.cda.data.dao.ObjectStorageBlobDao; +import cwms.cda.data.dao.ObjectStorageConfig; +import cwms.cda.data.dao.StreamConsumer; import cwms.cda.data.dto.Blob; import cwms.cda.data.dto.Blobs; import cwms.cda.data.dto.CwmsDTOPaginated; +import cwms.cda.features.CdaFeatures; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; import cwms.cda.formatters.FormattingException; -import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.http.HttpCode; @@ -25,15 +44,12 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; - +import java.io.IOException; import java.util.Optional; - import javax.servlet.http.HttpServletResponse; - import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; import org.togglz.core.context.FeatureContext; -import cwms.cda.features.CdaFeatures; import org.togglz.core.manager.FeatureManager; @@ -41,6 +57,7 @@ * */ public class BlobController extends BaseCrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private static final int DEFAULT_PAGE_SIZE = 20; public static final String TAG = "Blob"; @@ -131,9 +148,18 @@ Integer.class, DEFAULT_PAGE_SIZE, getMetrics(), String result = Formats.format(contentType, blobs); - ctx.result(result); ctx.contentType(contentType.toString()); updateResultSize(result.length()); + + ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 Blobs", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Blobs"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java index ca468a1186..4f964e40be 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java @@ -48,12 +48,14 @@ import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; import io.javalin.apibuilder.CrudHandler; +import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.http.HttpCode; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; @@ -371,8 +373,13 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) { } if (cat != null) { String data = Formats.format(contentType, cat); - ctx.result(data).contentType(contentType.toString()); + ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(data.length()); + + byte[] bytes = data.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { final CdaError re = new CdaError("Cannot create catalog of requested " + "information"); @@ -380,6 +387,10 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) { logger.atInfo().log("%s with url:%s", re, ctx.fullUrl()); ctx.json(re).status(HttpCode.NOT_FOUND); } + } catch (IOException ex) { + CdaError re = new CdaError("Failed to process request to retrieve catalog"); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve catalog"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/CdaVersionHandler.java b/cwms-data-api/src/main/java/cwms/cda/api/CdaVersionHandler.java index ed078530fa..e8ed2b0a5e 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/CdaVersionHandler.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/CdaVersionHandler.java @@ -32,21 +32,27 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.CdaVersionDao; import cwms.cda.data.dto.CdaVersion; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; +import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.http.Handler; import io.javalin.plugin.openapi.annotations.HttpMethod; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; public final class CdaVersionHandler implements Handler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); static final String TAG = "Version"; private final MetricRegistry metrics; @@ -75,9 +81,17 @@ public void handle(@NotNull Context ctx) throws Exception { CdaVersionDao dao = new CdaVersionDao(dsl, metrics); CdaVersion cdaVersion = dao.getCdaVersion(); String serialized = Formats.format(new ContentType(Formats.JSON), cdaVersion); - ctx.result(serialized); ctx.contentType(Formats.JSON); 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 CWMS Data API version", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve CWMS Data API version"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/ClobController.java b/cwms-data-api/src/main/java/cwms/cda/api/ClobController.java index f14a128ac7..802d6589e0 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/ClobController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/ClobController.java @@ -24,6 +24,7 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.ClobDao; import cwms.cda.data.dao.JooqDao; @@ -44,7 +45,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; - +import java.io.IOException; import java.util.Objects; import java.util.Optional; import javax.servlet.http.HttpServletResponse; @@ -53,6 +54,7 @@ public class ClobController implements CrudHandler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private static final int DEFAULT_PAGE_SIZE = 20; public static final String TAG = "Clob"; public static final String TEXT_PLAIN = "text/plain"; @@ -143,9 +145,17 @@ public void getAll(@NotNull Context ctx) { Clobs clobs = dao.getClobs(cursor, pageSize, office, includeValues, like); String result = Formats.format(contentType, clobs); - ctx.result(result); ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(result.length()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException e) { + CdaError re = new CdaError("Failed to process request to retrieve "); + logger.atSevere().withCause(e).log("Failed to process request to retrieve Basin"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -221,14 +231,22 @@ public void getOne(@NotNull Context ctx, @NotNull String clobId) { String result = Formats.format(contentType, clob); ctx.contentType(contentType.toString()); - ctx.result(result); + ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(result.length()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { ctx.status(HttpServletResponse.SC_NOT_FOUND).json(new CdaError("Unable to find " + "clob based on given parameters")); } } + } catch (IOException e) { + CdaError re = new CdaError("Failed to process request to retrieve clob"); + logger.atSevere().withCause(e).log("Failed to process request to retrieve clob"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/CountyController.java b/cwms-data-api/src/main/java/cwms/cda/api/CountyController.java index 990c378dcb..a1507c0ff3 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/CountyController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/CountyController.java @@ -33,18 +33,20 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.CountyDao; import cwms.cda.data.dto.County; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; -import cwms.cda.formatters.FormattingException; import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; 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; @@ -56,6 +58,7 @@ * @see CountyController */ public class CountyController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -94,9 +97,18 @@ public void getAll(@NotNull Context ctx) { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(formatHeader, County.class); String result = Formats.format(contentType, counties, County.class); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 counties", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve counties"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/DownstreamLocationsGetController.java b/cwms-data-api/src/main/java/cwms/cda/api/DownstreamLocationsGetController.java index 13979179a1..9cae344bdb 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/DownstreamLocationsGetController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/DownstreamLocationsGetController.java @@ -25,10 +25,6 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; - -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; import static cwms.cda.api.Controllers.ALL_DOWNSTREAM; import static cwms.cda.api.Controllers.AREA_UNIT; import static cwms.cda.api.Controllers.GET_ALL; @@ -41,6 +37,13 @@ import static cwms.cda.api.Controllers.STATION_UNIT; import static cwms.cda.api.Controllers.STATUS_200; import static cwms.cda.data.dao.JooqDao.getDslContext; + +import com.codahale.metrics.Histogram; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.StreamLocationDao; import cwms.cda.data.dto.stream.StreamLocation; import cwms.cda.formatters.ContentType; @@ -48,13 +51,18 @@ import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.http.Handler; -import io.javalin.plugin.openapi.annotations.*; +import io.javalin.plugin.openapi.annotations.OpenApi; +import io.javalin.plugin.openapi.annotations.OpenApiContent; +import io.javalin.plugin.openapi.annotations.OpenApiParam; +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; public final class DownstreamLocationsGetController implements Handler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -107,6 +115,15 @@ public void handle(@NotNull Context ctx) throws Exception { ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 downstream locations", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve downstream locations"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/EmbankmentController.java b/cwms-data-api/src/main/java/cwms/cda/api/EmbankmentController.java index 12da354312..65a1f9894c 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/EmbankmentController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/EmbankmentController.java @@ -24,9 +24,31 @@ package cwms.cda.api; +import static com.codahale.metrics.MetricRegistry.name; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.FAIL_IF_EXISTS; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.METHOD; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PROJECT_ID; +import static cwms.cda.api.Controllers.RESULTS; +import static cwms.cda.api.Controllers.SIZE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_204; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.data.dao.JooqDao.getDslContext; + import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.location.kind.EmbankmentDao; import cwms.cda.data.dto.StatusResponse; @@ -42,17 +64,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; -import static cwms.cda.data.dao.JooqDao.getDslContext; - public final class EmbankmentController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); static final String TAG = "Embankments"; private final MetricRegistry metrics; @@ -99,9 +118,17 @@ public void getAll(Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, Embankment.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, embankments, Embankment.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 Embankments", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Embankments"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -135,9 +162,18 @@ public void getOne(@NotNull Context ctx, @NotNull String name) { ContentType contentType = Formats.parseHeader(formatHeader, Embankment.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, embankment); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + ctx.contentType(contentType.toString()); + + 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 Embankment", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Embankment"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/EntityController.java b/cwms-data-api/src/main/java/cwms/cda/api/EntityController.java index 6c1d9da931..549d7a76b5 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/EntityController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/EntityController.java @@ -1,8 +1,32 @@ package cwms.cda.api; +import static com.codahale.metrics.MetricRegistry.name; +import static cwms.cda.api.Controllers.CASCADE_DELETE; +import static cwms.cda.api.Controllers.CATEGORY_ID; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.ENTITY_ID; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.LONG_NAME; +import static cwms.cda.api.Controllers.MATCH_NULL_PARENTS; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PARENT_ENTITY_ID; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_201; +import static cwms.cda.api.Controllers.STATUS_204; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.api.Controllers.requiredParamAs; +import static cwms.cda.data.dao.JooqDao.getDslContext; + import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.EntityDao; import cwms.cda.data.dto.CwmsId; import cwms.cda.data.dto.Entity; @@ -11,18 +35,20 @@ import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; -import io.javalin.plugin.openapi.annotations.*; +import io.javalin.plugin.openapi.annotations.HttpMethod; +import io.javalin.plugin.openapi.annotations.OpenApi; +import io.javalin.plugin.openapi.annotations.OpenApiContent; +import io.javalin.plugin.openapi.annotations.OpenApiParam; +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; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; -import static cwms.cda.data.dao.JooqDao.getDslContext; - public class EntityController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private static final String TAG = "Entity"; private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -88,9 +114,17 @@ public void getAll(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, Entity.class); ctx.contentType(contentType.toString()); String result = Formats.format(contentType, entities, Entity.class); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(result.length()); + + byte[] bytes = result.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 Entities", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Entities"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -129,9 +163,17 @@ public void getOne(@NotNull Context ctx, @NotNull String entityId) { ContentType contentType = Formats.parseHeader(formatHeader, Entity.class); ctx.contentType(contentType.toString()); String result = Formats.format(contentType, foundEntity); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(result.length()); + + byte[] bytes = result.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 Entity", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Entity"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/ForecastInstanceController.java b/cwms-data-api/src/main/java/cwms/cda/api/ForecastInstanceController.java index e7ed5292e4..87f62f5e72 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/ForecastInstanceController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/ForecastInstanceController.java @@ -1,11 +1,26 @@ package cwms.cda.api; -import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.DESIGNATOR; +import static cwms.cda.api.Controllers.FORECAST_DATE; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.ISSUE_DATE; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_400; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.STATUS_501; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.requiredParam; -import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.ForecastInstanceDao; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dto.forecast.ForecastInstance; @@ -14,7 +29,6 @@ import cwms.cda.formatters.FormattingException; import cwms.cda.helpers.DateUtils; import cwms.cda.helpers.ReplaceUtils; -import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.HttpMethod; @@ -28,12 +42,12 @@ import java.time.Instant; import java.util.List; import javax.servlet.http.HttpServletResponse; - import org.apache.http.client.utils.URIBuilder; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; public final class ForecastInstanceController extends BaseCrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); public static final String TAG = "Forecast"; private static final int KILO_BYTE_LIMIT = Integer.parseInt(System.getProperty("cda.api.forecast.file.max.length.kB", "64")); @@ -162,12 +176,21 @@ public void getAll(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, ForecastInstance.class); String result = Formats.format(contentType, instances, ForecastInstance.class); - ctx.result(result).contentType(contentType.toString()); updateResultSize(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } catch (URISyntaxException e) { throw new FormattingException("Could not build file download URL", e); + } catch (IOException ex) { + CdaError error = ExceptionTraceSupport.buildError(ctx, + "Failed to process request to retrieve Forecast Instances", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Forecast Instances"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -232,12 +255,21 @@ public void getOne(@NotNull Context ctx, @NotNull String name) { ContentType contentType = Formats.parseHeader(formatHeader, ForecastInstance.class); String result = Formats.format(contentType, instance); - ctx.result(result).contentType(contentType.toString()); updateResultSize(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } catch (URISyntaxException e) { throw new FormattingException("Could not build file download URL", e); + } catch (IOException ex) { + CdaError error = ExceptionTraceSupport.buildError(ctx, + "Failed to process request to retrieve Forecast Instance", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Forecast Instance"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/ForecastSpecController.java b/cwms-data-api/src/main/java/cwms/cda/api/ForecastSpecController.java index 1036fc1922..cf60e209ee 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/ForecastSpecController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/ForecastSpecController.java @@ -1,7 +1,29 @@ package cwms.cda.api; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.DESIGNATOR; +import static cwms.cda.api.Controllers.DESIGNATOR_MASK; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.ID_MASK; +import static cwms.cda.api.Controllers.METHOD; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.SOURCE_ENTITY; +import static cwms.cda.api.Controllers.SOURCE_ENTITY_LIKE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_400; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.STATUS_501; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.requiredParam; + import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.DeleteRule; import cwms.cda.data.dao.ForecastSpecDao; import cwms.cda.data.dao.JooqDao; @@ -16,13 +38,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; -import static cwms.cda.api.Controllers.*; public final class ForecastSpecController extends BaseCrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); public static final String TAG = "Forecast"; @@ -160,10 +183,20 @@ public void getAll(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, ForecastSpec.class); String result = Formats.format(contentType, specs, ForecastSpec.class); - ctx.result(result).contentType(contentType.toString()); updateResultSize(result.length()); ctx.status(HttpServletResponse.SC_OK); + + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 forecast specs", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve forecast specs"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -209,10 +242,19 @@ public void getOne(@NotNull Context ctx, @NotNull String name) { ContentType contentType = Formats.parseHeader(formatHeader, ForecastSpec.class); String result = Formats.format(contentType, spec); - ctx.result(result).contentType(contentType.toString()); updateResultSize(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 forecast spec", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve forecast spec"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LevelRefsController.java b/cwms-data-api/src/main/java/cwms/cda/api/LevelRefsController.java index 15e0c2a604..131ce17079 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LevelRefsController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LevelRefsController.java @@ -45,10 +45,12 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.LocationLevelsDao; import cwms.cda.data.dao.LocationLevelsDaoImpl; import cwms.cda.data.dto.locationlevel.LocationLevelRefs; -import cwms.cda.data.dto.locationlevel.LocationLevels; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; import io.javalin.core.util.Header; @@ -58,6 +60,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.time.Instant; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; @@ -65,6 +68,7 @@ public class LevelRefsController implements Handler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -139,10 +143,18 @@ public void handle(@NotNull Context ctx) { LocationLevelRefs levels = levelsDao.retrieveLocationLevelRefs(cursor, pageSize, levelIdMask, office, beginZdt, endZdt, includeAliases); String result = Formats.format(contentType, levels); - ctx.result(result); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 location level refs", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve location level refs"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LevelsAsTimeSeriesController.java b/cwms-data-api/src/main/java/cwms/cda/api/LevelsAsTimeSeriesController.java index 3b2537ae93..8aced63a55 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LevelsAsTimeSeriesController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LevelsAsTimeSeriesController.java @@ -24,6 +24,21 @@ package cwms.cda.api; +import static cwms.cda.api.Controllers.BEGIN; +import static cwms.cda.api.Controllers.END; +import static cwms.cda.api.Controllers.INTERVAL; +import static cwms.cda.api.Controllers.LEVEL_ID; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_400; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.STATUS_501; +import static cwms.cda.api.Controllers.TIMEZONE; +import static cwms.cda.api.Controllers.TIME_FORMAT_DESC; +import static cwms.cda.api.Controllers.UNIT; +import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.data.dao.JooqDao.getDslContext; + import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import cwms.cda.data.dao.LocationLevelsDao; @@ -34,22 +49,17 @@ import hec.data.level.JDomLocationLevelRef; import io.javalin.core.validation.Validator; import io.javalin.http.Context; -import io.javalin.http.Handler; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import javax.servlet.http.HttpServletResponse; import mil.army.usace.hec.metadata.Interval; import mil.army.usace.hec.metadata.IntervalFactory; import org.jooq.DSLContext; -import javax.servlet.http.HttpServletResponse; -import java.time.ZoneId; -import java.time.ZonedDateTime; - -import static cwms.cda.api.Controllers.*; -import static cwms.cda.data.dao.JooqDao.getDslContext; - public class LevelsAsTimeSeriesController extends BaseHandler { public LevelsAsTimeSeriesController(MetricRegistry metrics) { diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java b/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java index f6ec6f48b8..60aa64f261 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java @@ -40,7 +40,9 @@ import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.enums.UnitSystem; +import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.LocationLevelsDao; import cwms.cda.data.dao.LocationLevelsDaoImpl; import cwms.cda.data.dto.StatusResponse; @@ -80,6 +82,8 @@ public class LevelsController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); + private static final String ERROR_MSG = "Failed to process request to retrieve level"; static final String TAG = "Levels"; private final MetricRegistry metrics; @@ -310,26 +314,36 @@ public void getAll(@NotNull Context ctx) { office, unit, datum, beginZdt, endZdt, includeAliases); String result = Formats.format(contentType, levels); - ctx.result(result); + ctx.contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); - ctx.contentType(contentType.toString()); + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { //Use the type string, not the full string with properties. //i.e. application/json not application/json;version=1 String results = levelsDao.getLocationLevels(format, levelIdMask, office, unit, datum, begin, end, timezone); ctx.status(HttpServletResponse.SC_OK); - ctx.result(results); - requestResultSize.update(results.length()); + if (isLegacyVersion) { ctx.contentType(contentType.toString()); } else { ctx.contentType(contentType.getType()); } + requestResultSize.update(results.length()); + + byte[] bytes = results.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } addDeprecatedContentTypeWarning(ctx, contentType); + } catch (IOException ex) { + CdaError re = new CdaError(ERROR_MSG); + LOGGER.atSevere().withCause(ex).log(ERROR_MSG); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -400,8 +414,22 @@ String.class, null, metrics, name(LevelsController.class.getName(), //retrieveLocationLevel will throw an error if level does not exist LocationLevel locationLevel = levelsDao.retrieveLocationLevel(levelId, units, unmarshalledDateTime, office, exactDateMatch); - ctx.json(locationLevel); + + String formatHeader = ctx.header(Header.ACCEPT); + ContentType contentType = Formats.parseHeader(formatHeader, LocationLevel.class); + + String result = Formats.format(contentType, locationLevel); + + ctx.contentType(contentType.toString()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException ex) { + CdaError re = new CdaError(ERROR_MSG); + LOGGER.atSevere().withCause(ex).log(ERROR_MSG); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LocationCategoryController.java b/cwms-data-api/src/main/java/cwms/cda/api/LocationCategoryController.java index 314109ce54..479da80c8f 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LocationCategoryController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LocationCategoryController.java @@ -25,12 +25,23 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; +import static cwms.cda.api.Controllers.CASCADE_DELETE; +import static cwms.cda.api.Controllers.CATEGORY_ID; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.RESULTS; +import static cwms.cda.api.Controllers.SIZE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.requiredParam; import static cwms.cda.data.dao.JooqDao.getDslContext; import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.LocationCategoryDao; import cwms.cda.data.dto.LocationCategory; @@ -45,9 +56,9 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.util.List; import java.util.Optional; -import com.google.common.flogger.FluentLogger; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -102,10 +113,14 @@ public void getAll(Context ctx) { String result = Formats.format(contentType, cats, LocationCategory.class); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { CdaError re = new CdaError("Cannot find requested location category for " + "office provided: " + office); @@ -113,9 +128,11 @@ public void getAll(Context ctx) { logger.atInfo().log("%s with url:%s", re, ctx.fullUrl()); ctx.json(re).status(HttpServletResponse.SC_NOT_FOUND); } - + } catch (IOException ex) { + CdaError re = new CdaError("Failed to process request to retrieve Location Categories"); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve Location Categories"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } - } @OpenApi( @@ -141,7 +158,7 @@ public void getAll(Context ctx) { @Override public void getOne(Context ctx, @NotNull String categoryId) { - try (final Timer.Context timeContext = markAndTime(GET_ONE)){ + try (final Timer.Context timeContext = markAndTime(GET_ONE)) { DSLContext dsl = getDslContext(ctx); LocationCategoryDao dao = new LocationCategoryDao(dsl); @@ -154,10 +171,14 @@ public void getOne(Context ctx, @NotNull String categoryId) { String result = Formats.format(contentType, grp.get()); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { CdaError re = new CdaError("Cannot find requested location category id: " + categoryId + " with office: " + office); @@ -165,9 +186,11 @@ public void getOne(Context ctx, @NotNull String categoryId) { logger.atInfo().log("%s with url:%s", re, ctx.fullUrl()); ctx.json(re).status(HttpServletResponse.SC_NOT_FOUND); } - + } catch (IOException ex) { + CdaError re = new CdaError("Failed to process request to retrieve Location Category"); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve Location Category"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } - } @OpenApi( @@ -182,7 +205,7 @@ public void getOne(Context ctx, @NotNull String categoryId) { ) @Override public void create(Context ctx) { - try (Timer.Context ignored = markAndTime(CREATE)){ + try (Timer.Context ignored = markAndTime(CREATE)) { DSLContext dsl = getDslContext(ctx); String formatHeader = ctx.req.getContentType(); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LocationController.java b/cwms-data-api/src/main/java/cwms/cda/api/LocationController.java index bd509c5086..3acf92fc97 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LocationController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LocationController.java @@ -193,31 +193,48 @@ public void getAll(@NotNull Context ctx) { if (contentType.getType().equals(Formats.GEOJSON)) { FeatureCollection collection = locationsDao.buildFeatureCollection(names, units, office); - ctx.json(collection); - - requestResultSize.update(ctx.res.getBufferSize()); ctx.contentType(contentType.toString()); + + ObjectMapper mapper = ctx.appAttribute("ObjectMapper"); + String result = mapper.writeValueAsString(collection); + requestResultSize.update(result.length()); + + ctx.status(HttpServletResponse.SC_OK); + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else if (formatParm.isEmpty() && !isLegacyFormat) { List locations = locationsDao.getLocations(names, units, datum, office); results = Formats.format(contentType, locations, Location.class); - ctx.result(results); - requestResultSize.update(results.length()); ctx.contentType(contentType.toString()); + requestResultSize.update(results.length()); + + ctx.status(HttpServletResponse.SC_OK); + byte[] bytes = results.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { String format = Formats.getLegacyTypeFromContentType(contentType); results = locationsDao.getLocations(names, format, units, datum, office); - ctx.result(results); - requestResultSize.update(results.length()); + if (isLegacyFormat) { ctx.contentType(contentType.toString()); } else { ctx.contentType(contentType.getType()); } + requestResultSize.update(results.length()); + + ctx.status(HttpServletResponse.SC_OK); + byte[] bytes = results.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } addDeprecatedContentTypeWarning(ctx, contentType); - - ctx.status(HttpServletResponse.SC_OK); + } catch (IOException ex) { + CdaError re = ExceptionTraceSupport.buildError(ctx, "Failed to process request to retrieve Locations", ex); + logger.atSevere().withCause(ex).log("%s", re.toString()); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -271,7 +288,14 @@ public void getOne(@NotNull Context ctx, @NotNull String locationId) { LocationsDao locationDao = getLocationsDao(dsl); Location location = locationDao.getLocation(locationId, units, office, includeAliases, datum); String serializedLocation = Formats.format(contentType, location); - ctx.result(serializedLocation); + ctx.contentType(contentType.toString()); + requestResultSize.update(serializedLocation.length()); + + ctx.status(HttpServletResponse.SC_OK); + byte[] bytes = serializedLocation.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + addDeprecatedContentTypeWarning(ctx, contentType); } catch (IOException ex) { String errorMsg = "Error retrieving " + locationId; diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LocationGroupController.java b/cwms-data-api/src/main/java/cwms/cda/api/LocationGroupController.java index 7d9ffb79b6..41b2b7dee9 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LocationGroupController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LocationGroupController.java @@ -25,7 +25,25 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; +import static cwms.cda.api.Controllers.CASCADE_DELETE; +import static cwms.cda.api.Controllers.CATEGORY_ID; +import static cwms.cda.api.Controllers.CATEGORY_OFFICE_ID; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.CWMS_OFFICE; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.GROUP_ID; +import static cwms.cda.api.Controllers.GROUP_OFFICE_ID; +import static cwms.cda.api.Controllers.INCLUDE_ASSIGNED; +import static cwms.cda.api.Controllers.LOCATION_CATEGORY_LIKE; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.REPLACE_ASSIGNED_LOCS; +import static cwms.cda.api.Controllers.RESULTS; +import static cwms.cda.api.Controllers.SIZE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.queryParamAsClass; +import static cwms.cda.api.Controllers.requiredParam; import static cwms.cda.data.dao.JooqDao.getDslContext; import com.codahale.metrics.Histogram; @@ -33,6 +51,7 @@ import com.codahale.metrics.Timer; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.LocationGroupDao; import cwms.cda.data.dto.LocationGroup; @@ -48,9 +67,9 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.util.List; import java.util.Optional; -import com.google.common.flogger.FluentLogger; import javax.servlet.http.HttpServletResponse; import org.geojson.FeatureCollection; import org.jetbrains.annotations.NotNull; @@ -133,14 +152,20 @@ Boolean.class, false, metrics, name(LocationGroupController.class.getName(), requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { CdaError re = new CdaError("No location groups for office provided"); logger.atInfo().log("%s%nfor request %s", re, ctx.fullUrl()); ctx.status(HttpServletResponse.SC_NOT_FOUND).json(re); } - + } catch (IOException ex) { + CdaError re = new CdaError("Failed to process request to retrieve location groups"); + logger.atSevere().withCause(ex).log("%s", re); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } - } @OpenApi( @@ -209,18 +234,24 @@ public void getOne(@NotNull Context ctx, @NotNull String groupId) { } } - ctx.result(result); ctx.contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } catch (JsonProcessingException e) { CdaError re = new CdaError("Failed to process request"); logger.atSevere().withCause(e).log("%s", re); ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); + } catch (IOException e) { + CdaError re = new CdaError("Failed to process request to retrieve location group"); + logger.atSevere().withCause(e).log("%s", re); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } - } @OpenApi( diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LocationKindController.java b/cwms-data-api/src/main/java/cwms/cda/api/LocationKindController.java index 2b5bc56a45..680aea432d 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LocationKindController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LocationKindController.java @@ -38,9 +38,11 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.LocationsDao; import cwms.cda.data.dto.CwmsIdLocationKind; -import cwms.cda.data.dto.Location; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; import io.javalin.core.util.Header; @@ -51,12 +53,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; public class LocationKindController implements Handler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); public static final String TAG = "REGI"; private final Histogram requestResultSize; @@ -95,25 +99,35 @@ public LocationKindController(MetricRegistry metrics) { ) @Override public void handle(@NotNull Context ctx) { - DSLContext dsl = getDslContext(ctx); + try { + DSLContext dsl = getDslContext(ctx); - LocationsDao locationsDao = getLocationsDao(dsl); + LocationsDao locationsDao = getLocationsDao(dsl); - String names = ctx.queryParam(NAMES); - String kindRegexMask = ctx.queryParam(LOCATION_KIND_LIKE); - String office = ctx.queryParam(OFFICE); + String names = ctx.queryParam(NAMES); + String kindRegexMask = ctx.queryParam(LOCATION_KIND_LIKE); + String office = ctx.queryParam(OFFICE); - String formatHeader = ctx.header(Header.ACCEPT); - ContentType contentType = Formats.parseHeader(formatHeader, CwmsIdLocationKind.class); + String formatHeader = ctx.header(Header.ACCEPT); + ContentType contentType = Formats.parseHeader(formatHeader, CwmsIdLocationKind.class); - String results; + String results; - List locationKinds = locationsDao.getLocationKinds(names, kindRegexMask, office); - results = Formats.format(contentType, locationKinds, CwmsIdLocationKind.class); - ctx.result(results); - requestResultSize.update(results.length()); + List locationKinds = locationsDao.getLocationKinds(names, kindRegexMask, office); + results = Formats.format(contentType, locationKinds, CwmsIdLocationKind.class); + requestResultSize.update(results.length()); - ctx.contentType(contentType.toString()); - ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = results.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 Location Kind", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Location Kind"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); + } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LookupTypeController.java b/cwms-data-api/src/main/java/cwms/cda/api/LookupTypeController.java index f6a5cc4f54..15c5c25ad7 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LookupTypeController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LookupTypeController.java @@ -24,16 +24,30 @@ package cwms.cda.api; -import com.codahale.metrics.Histogram; +import static cwms.cda.api.Controllers.CATEGORY; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PREFIX; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_204; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.data.dao.JooqDao.getDslContext; + import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.LookupTypeDao; import cwms.cda.data.dto.LookupType; import cwms.cda.data.dto.StatusResponse; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; -import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.HttpMethod; @@ -42,17 +56,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; -import static cwms.cda.data.dao.JooqDao.getDslContext; - public final class LookupTypeController extends BaseCrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); static final String TAG = "LookupTypes"; @@ -87,9 +98,17 @@ public void getAll(Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, LookupType.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, lookupTypes, LookupType.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); updateResultSize(serialized.length()); + + 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 Lookup Types", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Lookup Types"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/MeasurementController.java b/cwms-data-api/src/main/java/cwms/cda/api/MeasurementController.java index 92b48e6e91..5e8254a247 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/MeasurementController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/MeasurementController.java @@ -21,29 +21,25 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + package cwms.cda.api; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; import static com.codahale.metrics.MetricRegistry.name; -import com.codahale.metrics.Timer; import static cwms.cda.api.Controllers.AGENCY; import static cwms.cda.api.Controllers.BEGIN; import static cwms.cda.api.Controllers.CREATE; import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.END; import static cwms.cda.api.Controllers.FAIL_IF_EXISTS; import static cwms.cda.api.Controllers.GET_ALL; -import static cwms.cda.api.Controllers.GET_ONE; import static cwms.cda.api.Controllers.ID_MASK; import static cwms.cda.api.Controllers.LOCATION_ID; -import static cwms.cda.api.Controllers.END; import static cwms.cda.api.Controllers.MAX_FLOW; import static cwms.cda.api.Controllers.MAX_HEIGHT; +import static cwms.cda.api.Controllers.MAX_NUMBER; import static cwms.cda.api.Controllers.MIN_FLOW; import static cwms.cda.api.Controllers.MIN_HEIGHT; -import static cwms.cda.api.Controllers.NOT_SUPPORTED_YET; import static cwms.cda.api.Controllers.MIN_NUMBER; -import static cwms.cda.api.Controllers.MAX_NUMBER; import static cwms.cda.api.Controllers.OFFICE; import static cwms.cda.api.Controllers.OFFICE_MASK; import static cwms.cda.api.Controllers.QUALITY; @@ -55,8 +51,15 @@ import static cwms.cda.api.Controllers.queryParamAsDouble; import static cwms.cda.api.Controllers.queryParamAsInstant; import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.data.dao.JooqDao.getDslContext; + +import com.codahale.metrics.Histogram; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.enums.UnitSystem; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.MeasurementDao; import cwms.cda.data.dto.StatusResponse; import cwms.cda.data.dto.measurement.Measurement; @@ -71,16 +74,15 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.time.Instant; +import java.util.List; +import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -import static cwms.cda.data.dao.JooqDao.getDslContext; - public final class MeasurementController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); public static final String TAG = "Measurements"; @@ -157,9 +159,17 @@ public void getAll(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, Measurement.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, measurements, Measurement.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 Measurements", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Measurements"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -247,7 +257,7 @@ public void delete(@NotNull Context ctx, @NotNull String locationId) { MeasurementDao dao = new MeasurementDao(dsl); dao.deleteMeasurements(officeId, locationId, minDate, maxDate,minNum, maxNum); StatusResponse re = new StatusResponse(officeId, "Measurement successfully deleted for specified location-id.", locationId); - ctx.status(HttpServletResponse.SC_OK).json( re); + ctx.status(HttpServletResponse.SC_OK).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/MeasurementTimeExtentsGetController.java b/cwms-data-api/src/main/java/cwms/cda/api/MeasurementTimeExtentsGetController.java index 7c8536f292..243bc84981 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/MeasurementTimeExtentsGetController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/MeasurementTimeExtentsGetController.java @@ -21,17 +21,22 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + package cwms.cda.api; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; import static com.codahale.metrics.MetricRegistry.name; -import com.codahale.metrics.Timer; import static cwms.cda.api.Controllers.OFFICE_MASK; import static cwms.cda.api.Controllers.RESULTS; import static cwms.cda.api.Controllers.SIZE; import static cwms.cda.api.Controllers.STATUS_200; import static cwms.cda.data.dao.JooqDao.getDslContext; + +import com.codahale.metrics.Histogram; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.MeasurementDao; import cwms.cda.data.dto.CwmsIdTimeExtentsEntry; import cwms.cda.formatters.ContentType; @@ -43,12 +48,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; public final class MeasurementTimeExtentsGetController implements Handler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -85,9 +92,17 @@ public void handle(@NotNull Context ctx) throws Exception { ContentType contentType = Formats.parseHeader(formatHeader, CwmsIdTimeExtentsEntry.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, timeExtents, CwmsIdTimeExtentsEntry.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 downstream locations", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve downstream locations"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/OfficeController.java b/cwms-data-api/src/main/java/cwms/cda/api/OfficeController.java index 7d02e7bebc..438e1b8ceb 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/OfficeController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/OfficeController.java @@ -14,6 +14,7 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.OfficeDao; import cwms.cda.data.dto.Office; @@ -27,6 +28,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.List; @@ -41,6 +43,7 @@ * @see OfficeController */ public class OfficeController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; @@ -107,13 +110,19 @@ public void getAll(Context ctx) { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseQueryOrHeaderParam(formatHeader, formatParm, Office.class); - String result = Formats.format(contentType, offices, Office.class); - Controllers.addDeprecatedContentTypeWarning(ctx, contentType); - - ctx.result(result).contentType(contentType.toString()); + String result = Formats.format(contentType, offices, Office.class); + ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(result.length()); + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException ex) { + CdaError re = new CdaError("Error writing response"); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Basins"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -155,15 +164,24 @@ public void getOne(Context ctx, String officeId) { ContentType contentType = Formats.parseHeaderAndQueryParm(formatHeader, formatParm, Office.class); String result = Formats.format(contentType, office.get()); Controllers.addDeprecatedContentTypeWarning(ctx, contentType); - ctx.result(result).contentType(contentType.toString()); + ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(result.length()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { Map map = new HashMap<>(); map.put(OFFICE, "An office with that name does not exist"); CdaError re = new CdaError("Not Found", map); ctx.status(HttpServletResponse.SC_NOT_FOUND).json(re); } + } catch (IOException ex) { + CdaError re = new CdaError("Error writing response"); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Basins"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/ParametersController.java b/cwms-data-api/src/main/java/cwms/cda/api/ParametersController.java index d9cb74eadf..da71d759b2 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/ParametersController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/ParametersController.java @@ -15,23 +15,27 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.ParameterDao; import cwms.cda.data.dto.Parameter; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; import io.javalin.apibuilder.CrudHandler; +import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; public class ParametersController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -116,9 +120,16 @@ public void getAll(@NotNull Context ctx) { } ctx.status(HttpServletResponse.SC_OK); - ctx.result(results); addDeprecatedContentTypeWarning(ctx, contentType); requestResultSize.update(results.length()); + + byte[] bytes = results.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException ex) { + CdaError re = new CdaError("Error writing response"); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Basins"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/PoolController.java b/cwms-data-api/src/main/java/cwms/cda/api/PoolController.java index 6905608bfd..76108fcb57 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/PoolController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/PoolController.java @@ -10,11 +10,9 @@ import static cwms.cda.api.Controllers.INCLUDE_EXPLICIT; import static cwms.cda.api.Controllers.INCLUDE_IMPLICIT; import static cwms.cda.api.Controllers.NAME_MASK; -import static cwms.cda.api.Controllers.NOT_SUPPORTED_YET; import static cwms.cda.api.Controllers.OFFICE; import static cwms.cda.api.Controllers.PAGE; import static cwms.cda.api.Controllers.PAGE_SIZE; -import static cwms.cda.api.Controllers.PARAMETER_ID; import static cwms.cda.api.Controllers.POOL_ID; import static cwms.cda.api.Controllers.PROJECT_ID; import static cwms.cda.api.Controllers.RESULTS; @@ -30,7 +28,9 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.PoolDao; import cwms.cda.data.dto.Pool; import cwms.cda.data.dto.Pools; @@ -43,7 +43,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; -import com.google.common.flogger.FluentLogger; +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -106,7 +106,7 @@ private Timer.Context markAndTime(String subject) { tags = {"Pools"}) @Override public void getAll(@NotNull Context ctx) { - try (final Timer.Context timeContext = markAndTime(GET_ALL)){ + try (final Timer.Context timeContext = markAndTime(GET_ALL)) { DSLContext dsl = getDslContext(ctx); PoolDao dao = new PoolDao(dsl); @@ -143,12 +143,20 @@ public void getAll(@NotNull Context ctx) { String result = Formats.format(contentType, pools); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 Pools", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve Pools"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } - } @OpenApi( @@ -186,13 +194,13 @@ public void getAll(@NotNull Context ctx) { description = "Retrieves requested Pool", tags = {"Pools"}) @Override public void getOne(@NotNull Context ctx, @NotNull String poolId) { - try (final Timer.Context timeContext = markAndTime(GET_ONE)){ + try (final Timer.Context timeContext = markAndTime(GET_ONE)) { DSLContext dsl = getDslContext(ctx); PoolDao dao = new PoolDao(dsl); // These are required - String office = requiredParam(ctx, OFFICE);; + String office = requiredParam(ctx, OFFICE); String projectId = requiredParam(ctx, PROJECT_ID); // These are optional @@ -226,7 +234,16 @@ public void getOne(@NotNull Context ctx, @NotNull String poolId) { requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 Pool", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve Pool"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/ProjectController.java b/cwms-data-api/src/main/java/cwms/cda/api/ProjectController.java index c5e592d768..276499971a 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/ProjectController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/ProjectController.java @@ -49,6 +49,7 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.project.ProjectDao; @@ -65,7 +66,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; -import com.google.common.flogger.FluentLogger; +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -136,12 +137,18 @@ public void getAll(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, Projects.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, projects); - ctx.result(serialized); + ctx.contentType(contentType.toString()); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + byte[] bytes = serialized.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException ex) { + CdaError re = new CdaError("Error writing response"); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve Basins"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } - } @OpenApi( @@ -186,11 +193,18 @@ public void getOne(@NotNull Context ctx, @NotNull String name) { String result = Formats.format(contentType, project); - ctx.result(result); + ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(result.length()); - ctx.status(HttpServletResponse.SC_OK); + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } + } catch (IOException ex) { + CdaError re = new CdaError("Error writing response"); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve Basins"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/PropertyController.java b/cwms-data-api/src/main/java/cwms/cda/api/PropertyController.java index 78707d30ad..6b1bcb9412 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/PropertyController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/PropertyController.java @@ -24,15 +24,34 @@ package cwms.cda.api; -import com.codahale.metrics.Histogram; +import static cwms.cda.api.Controllers.CATEGORY_ID; +import static cwms.cda.api.Controllers.CATEGORY_ID_MASK; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.DEFAULT_VALUE; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.NAME_MASK; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.OFFICE_MASK; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_204; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.data.dao.JooqDao.getDslContext; + import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.PropertyDao; import cwms.cda.data.dto.Property; import cwms.cda.data.dto.StatusResponse; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; -import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.HttpMethod; @@ -42,17 +61,13 @@ import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; - -import org.jooq.DSLContext; - -import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.util.List; - -import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; -import static cwms.cda.data.dao.JooqDao.getDslContext; +import javax.servlet.http.HttpServletResponse; +import org.jooq.DSLContext; public final class PropertyController extends BaseCrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); static final String TAG = "Properties"; @@ -90,9 +105,18 @@ public void getAll(Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, Property.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, properties, Property.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); updateResultSize(serialized.length()); + ctx.contentType(contentType.toString()); + + 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 Properties", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Properties"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -134,9 +158,17 @@ public void getOne(Context ctx, String name) { ContentType contentType = Formats.parseHeader(formatHeader, Property.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, property); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); updateResultSize(serialized.length()); + + 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 Property", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Property"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/SpecifiedLevelController.java b/cwms-data-api/src/main/java/cwms/cda/api/SpecifiedLevelController.java index 0f15b0b688..ba555094b1 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/SpecifiedLevelController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/SpecifiedLevelController.java @@ -41,7 +41,9 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.SpecifiedLevelDao; import cwms.cda.data.dto.SpecifiedLevel; import cwms.cda.formatters.ContentType; @@ -55,12 +57,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; public class SpecifiedLevelController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private static final String TAG = "Levels"; private final MetricRegistry metrics; @@ -119,9 +123,17 @@ public void getAll(Context ctx) { ctx.contentType(contentType.toString()); String result = Formats.format(contentType, levels, SpecifiedLevel.class); - ctx.result(result); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 Specified Levels", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Specified Levels"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/StandardTextController.java b/cwms-data-api/src/main/java/cwms/cda/api/StandardTextController.java index bdf3d737a5..9aec0a06f2 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/StandardTextController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/StandardTextController.java @@ -24,9 +24,27 @@ package cwms.cda.api; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.FAIL_IF_EXISTS; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.METHOD; +import static cwms.cda.api.Controllers.NAME_MASK; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.OFFICE_MASK; +import static cwms.cda.api.Controllers.STANDARD_TEXT_ID; +import static cwms.cda.api.Controllers.STANDARD_TEXT_ID_MASK; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.queryParamAsClass; +import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.api.Controllers.requiredParamAs; +import static cwms.cda.data.dao.JooqDao.getDslContext; + import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.DeleteRule; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.texttimeseries.StandardTextDao; @@ -43,17 +61,16 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; -import javax.servlet.http.HttpServletResponse; - -import static cwms.cda.api.Controllers.*; -import static cwms.cda.data.dao.JooqDao.getDslContext; - public class StandardTextController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private static final String TAG = "Standard Text"; + private static final String TEXT_ERROR = "Failed to process request to retrieve Standard Text"; private final MetricRegistry metrics; public StandardTextController(MetricRegistry metrics) { @@ -105,8 +122,16 @@ public void getAll(Context ctx) { ctx.contentType(contentType.toString()); String result = Formats.format(contentType, catalog); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException ex) { + CdaError error = ExceptionTraceSupport.buildError(ctx, + TEXT_ERROR, ex); + LOGGER.atSevere().withCause(ex).log(TEXT_ERROR); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -141,8 +166,16 @@ public void getOne(@NotNull Context ctx, @NotNull String stdTextId) { ContentType contentType = Formats.parseHeader(formatHeader, StandardTextValue.class); ctx.contentType(contentType.toString()); String result = Formats.format(contentType, standardTextValue); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException ex) { + CdaError error = ExceptionTraceSupport.buildError(ctx, + TEXT_ERROR, ex); + LOGGER.atSevere().withCause(ex).log(TEXT_ERROR); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/StateController.java b/cwms-data-api/src/main/java/cwms/cda/api/StateController.java index 1cf14f8848..68e29e2d25 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/StateController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/StateController.java @@ -33,7 +33,9 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.StateDao; import cwms.cda.data.dto.State; import cwms.cda.formatters.ContentType; @@ -45,6 +47,7 @@ import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; 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; @@ -57,6 +60,7 @@ * @see StateController */ public class StateController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -96,9 +100,17 @@ public void getAll(@NotNull Context ctx) { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(formatHeader, State.class); String result = Formats.format(contentType, states, State.class); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 States", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve States"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/StreamController.java b/cwms-data-api/src/main/java/cwms/cda/api/StreamController.java index 62bb650f73..45015a2a55 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/StreamController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/StreamController.java @@ -24,10 +24,7 @@ package cwms.cda.api; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; import static com.codahale.metrics.MetricRegistry.name; -import com.codahale.metrics.Timer; import static cwms.cda.api.Controllers.CREATE; import static cwms.cda.api.Controllers.DELETE; import static cwms.cda.api.Controllers.DIVERTS_FROM_STREAM_ID_MASK; @@ -48,6 +45,14 @@ import static cwms.cda.api.Controllers.STREAM_ID_MASK; import static cwms.cda.api.Controllers.UPDATE; import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.data.dao.JooqDao.getDslContext; + +import com.codahale.metrics.Histogram; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.DeleteRule; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.StreamDao; @@ -64,16 +69,16 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -import static cwms.cda.data.dao.JooqDao.getDslContext; - public final class StreamController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); + static final String TAG = "Streams"; private final MetricRegistry metrics; @@ -126,9 +131,17 @@ public void getAll(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, Stream.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, streams, Stream.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 streams", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve streams"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -165,9 +178,18 @@ public void getOne(@NotNull Context ctx, @NotNull String streamId) { ContentType contentType = Formats.parseHeader(formatHeader, Stream.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, stream); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + ctx.contentType(contentType.toString()); + + 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 stream", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve stream"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/StreamLocationController.java b/cwms-data-api/src/main/java/cwms/cda/api/StreamLocationController.java index 8c3f84ad97..be9da11d58 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/StreamLocationController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/StreamLocationController.java @@ -24,10 +24,6 @@ package cwms.cda.api; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; -import static com.codahale.metrics.MetricRegistry.name; -import com.codahale.metrics.Timer; import static cwms.cda.api.Controllers.AREA_UNIT; import static cwms.cda.api.Controllers.CREATE; import static cwms.cda.api.Controllers.DELETE; @@ -39,8 +35,6 @@ import static cwms.cda.api.Controllers.NAME_MASK; import static cwms.cda.api.Controllers.OFFICE; import static cwms.cda.api.Controllers.OFFICE_MASK; -import static cwms.cda.api.Controllers.RESULTS; -import static cwms.cda.api.Controllers.SIZE; import static cwms.cda.api.Controllers.STAGE_UNIT; import static cwms.cda.api.Controllers.STATION_UNIT; import static cwms.cda.api.Controllers.STATUS_200; @@ -49,12 +43,18 @@ import static cwms.cda.api.Controllers.STREAM_ID; import static cwms.cda.api.Controllers.STREAM_ID_MASK; import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.data.dao.JooqDao.getDslContext; + +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.StreamLocationDao; import cwms.cda.data.dto.StatusResponse; import cwms.cda.data.dto.stream.StreamLocation; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; -import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.HttpMethod; @@ -63,15 +63,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -import static cwms.cda.data.dao.JooqDao.getDslContext; - public final class StreamLocationController extends BaseCrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); static final String TAG = "StreamLocations"; @@ -117,9 +116,17 @@ public void getAll(Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, StreamLocation.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, streamLocations, StreamLocation.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); updateResultSize(serialized.length()); + + 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 stream locations", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve stream locations"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -163,9 +170,17 @@ public void getOne(@NotNull Context ctx, @NotNull String locationId) { ContentType contentType = Formats.parseHeader(formatHeader, StreamLocation.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, streamLocation); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); updateResultSize(serialized.length()); + + 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 stream location", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve stream location"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/StreamReachController.java b/cwms-data-api/src/main/java/cwms/cda/api/StreamReachController.java index 3cfe5da09e..cf075e78a7 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/StreamReachController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/StreamReachController.java @@ -23,10 +23,7 @@ */ package cwms.cda.api; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; import static com.codahale.metrics.MetricRegistry.name; -import com.codahale.metrics.Timer; import static cwms.cda.api.Controllers.CONFIGURATION_ID_MASK; import static cwms.cda.api.Controllers.CREATE; import static cwms.cda.api.Controllers.DELETE; @@ -42,12 +39,18 @@ import static cwms.cda.api.Controllers.STATION_UNIT; import static cwms.cda.api.Controllers.STATUS_200; import static cwms.cda.api.Controllers.STATUS_201; -import static cwms.cda.api.Controllers.STATUS_204; import static cwms.cda.api.Controllers.STREAM_ID; import static cwms.cda.api.Controllers.STREAM_ID_MASK; import static cwms.cda.api.Controllers.UPDATE; import static cwms.cda.api.Controllers.requiredParam; -import cwms.cda.data.dao.StreamLocationDao; +import static cwms.cda.data.dao.JooqDao.getDslContext; + +import com.codahale.metrics.Histogram; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.StreamReachDao; import cwms.cda.data.dto.StatusResponse; import cwms.cda.data.dto.stream.StreamReach; @@ -62,15 +65,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -import static cwms.cda.data.dao.JooqDao.getDslContext; - public final class StreamReachController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); static final String TAG = "StreamReaches"; @@ -121,9 +123,17 @@ public void getAll(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, StreamReach.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, streamReaches, StreamReach.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 Stream Reaches", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Stream Reaches"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -164,9 +174,17 @@ public void getOne(@NotNull Context ctx, @NotNull String reachId) { ContentType contentType = Formats.parseHeader(formatHeader, StreamReach.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, streamReach); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 Stream Reach", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Stream Reach"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TextTimeSeriesController.java b/cwms-data-api/src/main/java/cwms/cda/api/TextTimeSeriesController.java index 993cda2a88..ae9fa73034 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TextTimeSeriesController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TextTimeSeriesController.java @@ -24,11 +24,26 @@ package cwms.cda.api; -import static cwms.cda.api.Controllers.*; +import static cwms.cda.api.Controllers.BEGIN; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.DATE; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.END; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.TIMEZONE; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.VERSION_DATE; +import static cwms.cda.api.Controllers.queryParamAsInstant; +import static cwms.cda.api.Controllers.requiredInstant; +import static cwms.cda.api.Controllers.requiredParam; import static cwms.cda.data.dao.JooqDao.getDslContext; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.texttimeseries.TimeSeriesTextDao; @@ -36,7 +51,6 @@ import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; import cwms.cda.helpers.ReplaceUtils; -import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.HttpMethod; @@ -45,11 +59,10 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; -import java.io.UnsupportedEncodingException; +import java.io.IOException; import java.net.URISyntaxException; import java.net.URLEncoder; import java.time.Instant; -import com.google.common.flogger.FluentLogger; import javax.servlet.http.HttpServletResponse; import org.apache.http.client.utils.URIBuilder; import org.jetbrains.annotations.NotNull; @@ -141,10 +154,13 @@ public void getAll(@NotNull Context ctx) { ctx.contentType(contentType.toString()); String result = Formats.format(contentType, textTimeSeries); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); - } catch (URISyntaxException | UnsupportedEncodingException ex) { + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (URISyntaxException | IOException ex) { CdaError re = ExceptionTraceSupport.buildError(ctx, "Failed to process request: " + ex.getLocalizedMessage(), ex); logger.atSevere().withCause(ex).log("%s", re); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesCategoryController.java b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesCategoryController.java index c3e981f03d..b93c3adf84 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesCategoryController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesCategoryController.java @@ -33,6 +33,7 @@ import com.codahale.metrics.Timer; import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.TimeSeriesCategoryDao; import cwms.cda.data.dto.TimeSeriesCategory; import cwms.cda.formatters.ContentType; @@ -46,6 +47,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.util.List; import java.util.Optional; import javax.servlet.http.HttpServletResponse; @@ -88,7 +90,7 @@ private Timer.Context markAndTime(String subject) { + "Data", tags = {TAG}) @Override public void getAll(@NotNull Context ctx) { - try (final Timer.Context timeContext = markAndTime(GET_ALL)){ + try (final Timer.Context timeContext = markAndTime(GET_ALL)) { DSLContext dsl = getDslContext(ctx); TimeSeriesCategoryDao dao = new TimeSeriesCategoryDao(dsl); @@ -101,12 +103,20 @@ public void getAll(@NotNull Context ctx) { String result = Formats.format(contentType, cats, TimeSeriesCategory.class); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 TimeSeries Categories", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve TimeSeries Categories"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } - } @OpenApi( @@ -133,7 +143,7 @@ public void getAll(@NotNull Context ctx) { description = "Retrieves requested timeseries category", tags = {TAG}) @Override public void getOne(@NotNull Context ctx, @NotNull String categoryId) { - try (final Timer.Context timeContext = markAndTime(GET_ONE)){ + try (final Timer.Context timeContext = markAndTime(GET_ONE)) { DSLContext dsl = getDslContext(ctx); TimeSeriesCategoryDao dao = new TimeSeriesCategoryDao(dsl); @@ -146,15 +156,23 @@ public void getOne(@NotNull Context ctx, @NotNull String categoryId) { if (grp.isPresent()) { String result = Formats.format(contentType, grp.get()); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { CdaError re = new CdaError("Unable to find category based on parameters given"); logger.atInfo().log("%s%nfor request %s", re, ctx.fullUrl()); ctx.status(HttpServletResponse.SC_NOT_FOUND).json(re); } + } catch (IOException ex) { + CdaError re = new CdaError("Failed to process request to retrieve TimeSeries Category"); + logger.atSevere().withCause(ex).log("%s", re); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -176,7 +194,7 @@ public void getOne(@NotNull Context ctx, @NotNull String categoryId) { ) @Override public void create(@NotNull Context ctx) { - try (Timer.Context ignored = markAndTime(CREATE)){ + try (Timer.Context ignored = markAndTime(CREATE)) { DSLContext dsl = getDslContext(ctx); String formatHeader = ctx.req.getContentType(); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesController.java b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesController.java index 0483a71634..22edd37921 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesController.java @@ -1,7 +1,45 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; +import static cwms.cda.api.Controllers.BEGIN; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.CREATE_AS_LRTS; +import static cwms.cda.api.Controllers.CURSOR; +import static cwms.cda.api.Controllers.DATUM; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.END; +import static cwms.cda.api.Controllers.END_TIME_INCLUSIVE; +import static cwms.cda.api.Controllers.FORMAT; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.INCLUDE_ENTRY_DATE; +import static cwms.cda.api.Controllers.MAX_VERSION; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.OVERRIDE_PROTECTION; +import static cwms.cda.api.Controllers.PAGE; +import static cwms.cda.api.Controllers.PAGE_SIZE; +import static cwms.cda.api.Controllers.RESULTS; +import static cwms.cda.api.Controllers.SIZE; +import static cwms.cda.api.Controllers.START_TIME_INCLUSIVE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_400; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.STATUS_501; +import static cwms.cda.api.Controllers.STORE_RULE; +import static cwms.cda.api.Controllers.TIMESERIES; +import static cwms.cda.api.Controllers.TIMEZONE; +import static cwms.cda.api.Controllers.TIME_FORMAT_DESC; +import static cwms.cda.api.Controllers.UNIT; +import static cwms.cda.api.Controllers.UNITS; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.VERSION; +import static cwms.cda.api.Controllers.VERSION_DATE; +import static cwms.cda.api.Controllers.addDeprecatedContentTypeWarning; +import static cwms.cda.api.Controllers.queryParamAsClass; +import static cwms.cda.api.Controllers.queryParamAsZdt; +import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.api.Controllers.requiredZdt; import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; @@ -504,7 +542,13 @@ public void getAll(@NotNull Context ctx) { addLinkHeader(ctx, ts, contentType); - ctx.result(results).contentType(contentType.toString()); + ctx.contentType(contentType.toString()); + + requestResultSize.update(results.length()); + + byte[] bytes = results.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { if (versionDate != null) { throw new IllegalArgumentException(String.format("Version date is only supported for:%s and %s", @@ -523,10 +567,14 @@ public void getAll(@NotNull Context ctx) { String office = ctx.queryParam(OFFICE); results = dao.getTimeseries(format, names, office, units, datum, beginZdt, endZdt, tz); ctx.status(HttpServletResponse.SC_OK); - ctx.result(results); + + requestResultSize.update(results.length()); + + byte[] bytes = results.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } addDeprecatedContentTypeWarning(ctx, contentType); - requestResultSize.update(results.length()); } catch (NotFoundException e) { CdaError re = new CdaError("Not found."); logger.atSevere().withCause(e).log("%s", re.toString()); @@ -537,6 +585,10 @@ public void getAll(@NotNull Context ctx) { logger.atSevere().withCause(ex).log("%s", re.toString()); ctx.status(HttpServletResponse.SC_BAD_REQUEST); ctx.json(re); + } catch (IOException ex) { + CdaError re = new CdaError("Failed to process request to retrieve time series"); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve time series"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesFilteredController.java b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesFilteredController.java index 9dc34ab180..6a1806216a 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesFilteredController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesFilteredController.java @@ -1,12 +1,35 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; - +import static cwms.cda.api.Controllers.BEGIN; +import static cwms.cda.api.Controllers.CURSOR; +import static cwms.cda.api.Controllers.END; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.INCLUDE_ENTRY_DATE; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PAGE; +import static cwms.cda.api.Controllers.PAGE_SIZE; +import static cwms.cda.api.Controllers.QUERY; +import static cwms.cda.api.Controllers.RESULTS; +import static cwms.cda.api.Controllers.SIZE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_400; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.STATUS_501; +import static cwms.cda.api.Controllers.TIMEZONE; +import static cwms.cda.api.Controllers.TIME_FORMAT_DESC; +import static cwms.cda.api.Controllers.UNIT; +import static cwms.cda.api.Controllers.VERSION_DATE; +import static cwms.cda.api.Controllers.addDeprecatedContentTypeWarning; +import static cwms.cda.api.Controllers.queryParamAsClass; +import static cwms.cda.api.Controllers.queryParamAsZdt; +import static cwms.cda.api.Controllers.requiredParam; import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.enums.UnitSystem; import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.FilteredTimeSeriesParameters; @@ -15,7 +38,6 @@ import cwms.cda.data.dao.TimeSeriesDaoImpl; import cwms.cda.data.dao.TimeSeriesRequestParameters; import cwms.cda.data.dto.TimeSeries; - import cwms.cda.data.dto.filteredtimeseries.FilteredTimeSeries; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; @@ -29,14 +51,12 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.time.ZoneId; import java.time.ZonedDateTime; -import com.google.common.flogger.FluentLogger; - import javax.servlet.http.HttpServletResponse; - import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URLEncodedUtils; import org.jetbrains.annotations.NotNull; @@ -244,15 +264,22 @@ public void handle(@NotNull Context ctx) { addLinkHeader(ctx, fts, contentType); - ctx.result(results).contentType(contentType.toString()); - addDeprecatedContentTypeWarning(ctx, contentType); requestResultSize.update(results.length()); + ctx.contentType(contentType.toString()); + + byte[] bytes = results.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } catch (IllegalArgumentException ex) { CdaError re = new CdaError("Invalid arguments supplied"); logger.atSevere().withCause(ex).log("%s", re); ctx.status(HttpServletResponse.SC_BAD_REQUEST); ctx.json(re); + } catch (IOException ex) { + CdaError re = new CdaError("Failed to process request to retrieve filtered time series"); + logger.atSevere().withCause(ex).log("%s", re); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesGroupController.java b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesGroupController.java index a2cbf7bf2d..2339c3a4c4 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesGroupController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesGroupController.java @@ -70,6 +70,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; @@ -150,11 +151,19 @@ Boolean.class, true, metrics, name(TimeSeriesGroupController.class.getName(), String result = Formats.format(contentType, grps, TimeSeriesGroup.class); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } + } catch (IOException ex) { + CdaError re = new CdaError("Failure to process request to retrieve time series groups"); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve time series groups"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -204,19 +213,24 @@ public void getOne(@NotNull Context ctx, @NotNull String groupId) { if (group != null) { String result = Formats.format(contentType, group); - ctx.result(result); ctx.contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { CdaError re = new CdaError("Unable to find group based on parameters given"); logger.atInfo().log("%s%sfor request %s", re, System.lineSeparator(), ctx.fullUrl()); ctx.status(HttpServletResponse.SC_NOT_FOUND).json(re); } - + } catch (IOException ex) { + CdaError re = new CdaError("Failure to process request to retrieve time series group"); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve time series group"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } - } @OpenApi( diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesIdentifierDescriptorController.java b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesIdentifierDescriptorController.java index fcd567cb61..2aa23b567a 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesIdentifierDescriptorController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesIdentifierDescriptorController.java @@ -25,12 +25,38 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; +import static cwms.cda.api.Controllers.ACTIVE; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.FAIL_IF_EXISTS; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.INCLUDE_ALIASES; +import static cwms.cda.api.Controllers.INTERVAL_OFFSET; +import static cwms.cda.api.Controllers.METHOD; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PAGE; +import static cwms.cda.api.Controllers.PAGE_SIZE; +import static cwms.cda.api.Controllers.RESULTS; +import static cwms.cda.api.Controllers.SIZE; +import static cwms.cda.api.Controllers.SNAP_BACKWARD; +import static cwms.cda.api.Controllers.SNAP_FORWARD; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.STATUS_501; +import static cwms.cda.api.Controllers.TIMESERIES_ID; +import static cwms.cda.api.Controllers.TIMESERIES_ID_REGEX; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.api.Controllers.requiredParamAs; import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.TimeSeriesIdentifierDescriptorDao; import cwms.cda.data.dto.TimeSeriesIdentifierDescriptor; @@ -46,11 +72,11 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; -import com.google.common.flogger.FluentLogger; import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; @@ -140,12 +166,20 @@ public void getAll(Context ctx) { String result = Formats.format(contentType, descriptors); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 timeseries identifiers", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve timeseries identifiers"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } - } @OpenApi( @@ -193,16 +227,25 @@ public void getOne(@NotNull Context ctx, @NotNull String timeseriesId) { if (grp.isPresent()) { String result = Formats.format(contentType, grp.get()); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { CdaError re = new CdaError("Unable to find identifier based on parameters " + "given"); logger.atInfo().log("%s%s for request %s", re, System.lineSeparator(), ctx.fullUrl()); ctx.status(HttpServletResponse.SC_NOT_FOUND).json(re); } + } catch (IOException e) { + CdaError error = ExceptionTraceSupport.buildError(ctx, + "Failed to process request to retrieve time series identifier", e); + logger.atSevere().withCause(e).log("Failed to process request to retrieve time series identifier"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesRecentController.java b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesRecentController.java index de8fd05e4b..39d4895ef9 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesRecentController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesRecentController.java @@ -39,8 +39,10 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.enums.UnitSystem; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.TimeSeriesDao; import cwms.cda.data.dao.TimeSeriesDaoImpl; @@ -55,6 +57,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; @@ -64,7 +67,6 @@ import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Consumer; -import com.google.common.flogger.FluentLogger; import java.util.regex.MatchResult; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -185,10 +187,19 @@ public void handle(@NotNull Context ctx) { String result = Formats.format(contentType, latestValues, RecentValue.class); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 Timeseries Recents", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve Timeseries Recents"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TimeZoneController.java b/cwms-data-api/src/main/java/cwms/cda/api/TimeZoneController.java index 996a09e8f8..f747c32876 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TimeZoneController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TimeZoneController.java @@ -15,6 +15,7 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.TimeZoneDao; import cwms.cda.data.dto.TimeZoneId; @@ -22,16 +23,20 @@ import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; import io.javalin.apibuilder.CrudHandler; +import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; public class TimeZoneController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); + private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -115,7 +120,13 @@ public void getAll(@NotNull Context ctx) { requestResultSize.update(results.length()); ctx.status(HttpServletResponse.SC_OK); - ctx.result(results); + byte[] bytes = results.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException ex) { + CdaError re = new CdaError("Failed to process request to retrieve time zone"); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve time zone"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesGetController.java b/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesGetController.java index 870608d0e1..a4a810861e 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesGetController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesGetController.java @@ -25,13 +25,29 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; +import static cwms.cda.api.Controllers.BEGIN; +import static cwms.cda.api.Controllers.END; +import static cwms.cda.api.Controllers.END_TIME_INCLUSIVE; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PAGE_SIZE; +import static cwms.cda.api.Controllers.RESULTS; +import static cwms.cda.api.Controllers.SIZE; +import static cwms.cda.api.Controllers.START_TIME_INCLUSIVE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.TIMEZONE; +import static cwms.cda.api.Controllers.UNIT_SYSTEM; +import static cwms.cda.api.Controllers.requiredInstant; import static cwms.cda.data.dao.JooqDao.getDslContext; import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.enums.UnitSystem; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.location.kind.TurbineDao; import cwms.cda.data.dto.CwmsId; import cwms.cda.data.dto.location.kind.TurbineChange; @@ -45,6 +61,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.time.Instant; import java.util.List; import javax.servlet.http.HttpServletResponse; @@ -52,6 +69,7 @@ import org.jooq.DSLContext; public final class TurbineChangesGetController implements Handler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private static final int DEFAULT_PAGE_SIZE = 500; private final MetricRegistry metrics; @@ -139,9 +157,17 @@ public void handle(@NotNull Context ctx) throws Exception { ContentType contentType = Formats.parseHeader(formatHeader, TurbineChange.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, turbineChanges, TurbineChange.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 Turbine Changes", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Turbine Changes"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } \ No newline at end of file diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TurbineController.java b/cwms-data-api/src/main/java/cwms/cda/api/TurbineController.java index 5be3f682e8..66dfadc80f 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TurbineController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TurbineController.java @@ -24,9 +24,31 @@ package cwms.cda.api; +import static com.codahale.metrics.MetricRegistry.name; +import static cwms.cda.api.Controllers.CREATE; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.FAIL_IF_EXISTS; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.METHOD; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PROJECT_ID; +import static cwms.cda.api.Controllers.RESULTS; +import static cwms.cda.api.Controllers.SIZE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_201; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.UPDATE; +import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.data.dao.JooqDao.getDslContext; + import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.location.kind.TurbineDao; import cwms.cda.data.dto.StatusResponse; @@ -42,17 +64,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; -import static cwms.cda.data.dao.JooqDao.getDslContext; - public final class TurbineController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); static final String TAG = "Turbines"; private final MetricRegistry metrics; @@ -99,9 +118,17 @@ public void getAll(Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, Turbine.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, turbines, Turbine.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 Turbines", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Turbines"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -135,9 +162,17 @@ public void getOne(@NotNull Context ctx, @NotNull String name) { ContentType contentType = Formats.parseHeader(formatHeader, Turbine.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, turbine); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 Turbine", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Turbine"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/UnitsController.java b/cwms-data-api/src/main/java/cwms/cda/api/UnitsController.java index fab490fa90..3e207b9f89 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/UnitsController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/UnitsController.java @@ -16,22 +16,27 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.UnitsDao; import cwms.cda.data.dto.Unit; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; import io.javalin.apibuilder.CrudHandler; +import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; public class UnitsController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); + private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -111,11 +116,17 @@ public void getAll(@NotNull Context ctx) { } ctx.status(HttpServletResponse.SC_OK); - ctx.result(results); addDeprecatedContentTypeWarning(ctx, contentType); requestResultSize.update(results.length()); - } + byte[] bytes = results.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); + } catch (IOException ex) { + CdaError re = new CdaError("Failed to procees request to retrieve units"); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve units"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); + } } @OpenApi(ignore = true) diff --git a/cwms-data-api/src/main/java/cwms/cda/api/UpstreamLocationsGetController.java b/cwms-data-api/src/main/java/cwms/cda/api/UpstreamLocationsGetController.java index d23fba3e8c..435278cb7c 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/UpstreamLocationsGetController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/UpstreamLocationsGetController.java @@ -25,10 +25,6 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; - -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; import static cwms.cda.api.Controllers.ALL_UPSTREAM; import static cwms.cda.api.Controllers.AREA_UNIT; import static cwms.cda.api.Controllers.GET_ALL; @@ -41,6 +37,13 @@ import static cwms.cda.api.Controllers.STATION_UNIT; import static cwms.cda.api.Controllers.STATUS_200; import static cwms.cda.data.dao.JooqDao.getDslContext; + +import com.codahale.metrics.Histogram; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.StreamLocationDao; import cwms.cda.data.dto.stream.StreamLocation; import cwms.cda.formatters.ContentType; @@ -48,13 +51,18 @@ import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.http.Handler; -import io.javalin.plugin.openapi.annotations.*; +import io.javalin.plugin.openapi.annotations.OpenApi; +import io.javalin.plugin.openapi.annotations.OpenApiContent; +import io.javalin.plugin.openapi.annotations.OpenApiParam; +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; public final class UpstreamLocationsGetController implements Handler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -105,9 +113,17 @@ public void handle(@NotNull Context ctx) throws Exception { ContentType contentType = Formats.parseHeader(formatHeader, StreamLocation.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, upstreamLocations, StreamLocation.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 upstream locations", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve upstream locations"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/VerticalDatumController.java b/cwms-data-api/src/main/java/cwms/cda/api/VerticalDatumController.java index e3479cc1c4..2bdc82aa27 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/VerticalDatumController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/VerticalDatumController.java @@ -21,12 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + package cwms.cda.api; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; -import com.google.common.flogger.FluentLogger; import static com.codahale.metrics.MetricRegistry.name; import static cwms.cda.api.Controllers.CREATE; import static cwms.cda.api.Controllers.DELETE; @@ -38,9 +35,15 @@ import static cwms.cda.api.Controllers.UNIT; import static cwms.cda.api.Controllers.UPDATE; import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.api.LocationController.LOCATIONS_TAG; import static cwms.cda.data.dao.JooqDao.getDslContext; +import com.codahale.metrics.Histogram; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.VerticalDatumDao; import cwms.cda.data.dto.StatusResponse; import cwms.cda.data.dto.VerticalDatumInfo; @@ -55,12 +58,11 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; -import static cwms.cda.api.LocationController.LOCATIONS_TAG; - public final class VerticalDatumController implements CrudHandler { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); @@ -115,9 +117,18 @@ 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.result(serialized); ctx.status(HttpServletResponse.SC_OK); 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); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/auth/users/UserProfileController.java b/cwms-data-api/src/main/java/cwms/cda/api/auth/users/UserProfileController.java index c42efa5e3d..12773d8fe6 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/auth/users/UserProfileController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/auth/users/UserProfileController.java @@ -3,17 +3,10 @@ import static cwms.cda.api.Controllers.STATUS_200; import static cwms.cda.data.dao.JooqDao.getDslContext; -import java.security.Principal; -import java.util.Optional; - -import org.jooq.DSLContext; - import com.codahale.metrics.MetricRegistry; - import cwms.cda.ApiServlet; import cwms.cda.data.dao.AuthDao; import cwms.cda.data.dao.UserDao; -import cwms.cda.data.dto.Clobs; import cwms.cda.data.dto.auth.users.User; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; @@ -25,9 +18,10 @@ import io.javalin.plugin.openapi.annotations.HttpMethod; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; -import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; +import javax.servlet.http.HttpServletResponse; +import org.jooq.DSLContext; public class UserProfileController implements Handler { @@ -66,8 +60,12 @@ public void handle(Context ctx) throws Exception { ContentType contentType = Formats.parseHeader(formatHeader, User.class); String result = Formats.format(contentType, user); - ctx.result(result); ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/auth/users/UsersController.java b/cwms-data-api/src/main/java/cwms/cda/api/auth/users/UsersController.java index 3b9fe43814..41e2d65251 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/auth/users/UsersController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/auth/users/UsersController.java @@ -1,17 +1,24 @@ package cwms.cda.api.auth.users; import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; +import static cwms.cda.api.Controllers.CURSOR; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.GET_ONE; +import static cwms.cda.api.Controllers.INCLUDE_ROLES; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PAGE; +import static cwms.cda.api.Controllers.PAGE_SIZE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.USERNAME_LIKE; +import static cwms.cda.api.Controllers.queryParamAsClass; import static cwms.cda.data.dao.JooqDao.getDslContext; -import javax.servlet.http.HttpServletResponse; -import org.jooq.DSLContext; - import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; - +import com.google.common.flogger.FluentLogger; import cwms.cda.api.Controllers; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.UserDao; import cwms.cda.data.dto.CwmsDTOPaginated; import cwms.cda.data.dto.auth.users.User; @@ -27,8 +34,12 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; +import org.jooq.DSLContext; public class UsersController implements CrudHandler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; private static final int DEFAULT_PAGE_SIZE = 100; public static final String TAG = "User Management"; @@ -59,7 +70,7 @@ public void delete(Context ctx, String username) { queryParams = { @OpenApiParam(allowEmptyValue = true, name = OFFICE, description = "Show only users with active privileges in a given office." - + Controllers.OFFICE_DESCRIPTION ), + + Controllers.OFFICE_DESCRIPTION), @OpenApiParam(name = USERNAME_LIKE, description = "Posix regular expression " + " matching against the username"), @@ -124,8 +135,17 @@ public void getAll(Context ctx) { String result = Formats.format(contentType, users); - ctx.result(result); ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 Users", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve Users"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -148,15 +168,26 @@ public void getAll(Context ctx) { ) @Override public void getOne(Context ctx, String userName) { - DSLContext dsl = getDslContext(ctx); - UserDao dao = new UserDao(dsl); - User user = dao.getByUniqueName(userName, null).orElse(null); - String formatHeader = ctx.header(Header.ACCEPT); - ContentType contentType = Formats.parseHeader(formatHeader, User.class); - String result = Formats.format(contentType, user); - - ctx.result(result); - ctx.contentType(contentType.toString()); + try (final Timer.Context ignored = markAndTime(GET_ONE)) { + DSLContext dsl = getDslContext(ctx); + UserDao dao = new UserDao(dsl); + User user = dao.getByUniqueName(userName, null).orElse(null); + String formatHeader = ctx.header(Header.ACCEPT); + ContentType contentType = Formats.parseHeader(formatHeader, User.class); + String result = Formats.format(contentType, user); + + ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 User", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve User"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); + } } @OpenApi( diff --git a/cwms-data-api/src/main/java/cwms/cda/api/location/kind/GateChangeGetAllController.java b/cwms-data-api/src/main/java/cwms/cda/api/location/kind/GateChangeGetAllController.java index fdc6cfc972..57a58f8146 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/location/kind/GateChangeGetAllController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/location/kind/GateChangeGetAllController.java @@ -20,12 +20,26 @@ package cwms.cda.api.location.kind; -import static cwms.cda.api.Controllers.*; +import static cwms.cda.api.Controllers.BEGIN; +import static cwms.cda.api.Controllers.END; +import static cwms.cda.api.Controllers.END_TIME_INCLUSIVE; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PAGE_SIZE; +import static cwms.cda.api.Controllers.PROJECT_ID; +import static cwms.cda.api.Controllers.START_TIME_INCLUSIVE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.TIMEZONE; +import static cwms.cda.api.Controllers.UNIT_SYSTEM; +import static cwms.cda.api.Controllers.requiredInstant; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.BaseHandler; import cwms.cda.api.enums.UnitSystem; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.location.kind.OutletDao; import cwms.cda.data.dto.CwmsId; @@ -39,6 +53,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.time.Instant; import java.util.List; import javax.servlet.http.HttpServletResponse; @@ -46,6 +61,7 @@ import org.jooq.DSLContext; public class GateChangeGetAllController extends BaseHandler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private static final int DEFAULT_PAGE_SIZE = 500; public GateChangeGetAllController(MetricRegistry metrics) { @@ -116,9 +132,18 @@ public void handle(@NotNull Context context) { String formatHeader = context.header(Header.ACCEPT) != null ? context.header(Header.ACCEPT) : Formats.JSONV1; ContentType contentType = Formats.parseHeader(formatHeader, GateChange.class); String serialized = Formats.format(contentType, changes, GateChange.class); - context.result(serialized); context.status(HttpServletResponse.SC_OK); updateResultSize(serialized.length()); + context.contentType(contentType.toString()); + + byte[] bytes = serialized.getBytes(); + context.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + context.res.getOutputStream().write(bytes); + } catch (IOException ex) { + CdaError error = ExceptionTraceSupport.buildError(context, + "Failed to process request to retrieve Gate Changes", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve Gate Changes"); + context.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/location/kind/LockController.java b/cwms-data-api/src/main/java/cwms/cda/api/location/kind/LockController.java index 5475598789..d72574cf68 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/location/kind/LockController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/location/kind/LockController.java @@ -38,7 +38,6 @@ import static cwms.cda.api.Controllers.SIZE; import static cwms.cda.api.Controllers.STATUS_200; import static cwms.cda.api.Controllers.STATUS_201; -import static cwms.cda.api.Controllers.STATUS_204; import static cwms.cda.api.Controllers.STATUS_404; import static cwms.cda.api.Controllers.UNIT; import static cwms.cda.api.Controllers.UPDATE; @@ -48,8 +47,11 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.Controllers; import cwms.cda.api.enums.UnitSystem; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.location.kind.LockDao; import cwms.cda.data.dto.CwmsId; @@ -66,12 +68,15 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; public final class LockController implements CrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); + private static final String ERROR_MSG = "Failed to process request to retrieve Locks"; static final String TAG = "Locks"; private final MetricRegistry metrics; @@ -118,9 +123,16 @@ public void getAll(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, Lock.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, locks, Lock.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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, ERROR_MSG, ex); + LOGGER.atSevere().withCause(ex).log(ERROR_MSG); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -162,9 +174,17 @@ public void getOne(@NotNull Context ctx, @NotNull String name) { ContentType contentType = Formats.parseHeader(formatHeader, Lock.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, lock); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + ctx.contentType(contentType.toString()); + + 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, ERROR_MSG, ex); + LOGGER.atSevere().withCause(ex).log(ERROR_MSG); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/location/kind/OutletController.java b/cwms-data-api/src/main/java/cwms/cda/api/location/kind/OutletController.java index 6eb33239e3..3609a7ab0c 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/location/kind/OutletController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/location/kind/OutletController.java @@ -38,7 +38,10 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.BaseCrudHandler; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.location.kind.OutletDao; import cwms.cda.data.dto.StatusResponse; @@ -53,6 +56,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; @@ -60,6 +64,7 @@ public class OutletController extends BaseCrudHandler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); static final String TAG = "Outlets"; public OutletController(MetricRegistry metrics) { @@ -129,9 +134,16 @@ public void getAll(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, Outlet.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, outlets, Outlet.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); updateResultSize(serialized); + + 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 outlets", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve outlets"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -165,9 +177,16 @@ public void getOne(@NotNull Context ctx, @NotNull String name) { ContentType contentType = Formats.parseHeader(formatHeader, Outlet.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, outlet); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); updateResultSize(serialized); + + 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 outlet", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve outlet"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/location/kind/VirtualOutletController.java b/cwms-data-api/src/main/java/cwms/cda/api/location/kind/VirtualOutletController.java index 9ba08ed8ad..edc0b28630 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/location/kind/VirtualOutletController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/location/kind/VirtualOutletController.java @@ -20,19 +20,28 @@ package cwms.cda.api.location.kind; -import com.codahale.metrics.Histogram; +import static cwms.cda.api.Controllers.DELETE; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.METHOD; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PROJECT_ID; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.data.dao.JooqDao.getDslContext; + import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.BaseCrudHandler; -import cwms.cda.api.Controllers; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.location.kind.OutletDao; import cwms.cda.data.dto.StatusResponse; import cwms.cda.data.dto.location.kind.VirtualOutlet; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; -import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.HttpMethod; @@ -40,15 +49,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; -import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.*; -import static cwms.cda.data.dao.JooqDao.getDslContext; public class VirtualOutletController extends BaseCrudHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); public VirtualOutletController(MetricRegistry metrics) { super(metrics); @@ -89,9 +97,17 @@ public void getAll(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(formatHeader, VirtualOutlet.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, outlets, VirtualOutlet.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); updateResultSize(serialized); + + 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 Virtual Outlets", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Virtual Outlets"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } @@ -126,9 +142,17 @@ public void getOne(@NotNull Context ctx, @NotNull String name) { ContentType contentType = Formats.parseHeader(formatHeader, VirtualOutlet.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, outlet); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); updateResultSize(serialized); + + 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 Virtual Outlet", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Virtual Outlet"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/project/LockRevokerRightsCatalog.java b/cwms-data-api/src/main/java/cwms/cda/api/project/LockRevokerRightsCatalog.java index a7e725f6ad..68947e7ad6 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/project/LockRevokerRightsCatalog.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/project/LockRevokerRightsCatalog.java @@ -35,7 +35,10 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.Controllers; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.project.ProjectLockDao; import cwms.cda.data.dto.project.LockRevokerRights; @@ -50,12 +53,13 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; - +import java.io.IOException; import java.util.List; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; public class LockRevokerRightsCatalog implements Handler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); public static final String TAGS = "Project Lock Revoker Rights"; public static final String PATH = "/project-lock-rights/"; private final MetricRegistry metrics; @@ -110,9 +114,18 @@ public void handle(@NotNull Context ctx) throws Exception { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(formatHeader, LockRevokerRights.class); String result = Formats.format(contentType, rights, LockRevokerRights.class); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 lock revoker rights", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve lock revoker rights"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectChildLocationHandler.java b/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectChildLocationHandler.java index e8349bf16b..e8510d05a0 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectChildLocationHandler.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectChildLocationHandler.java @@ -35,7 +35,10 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.Controllers; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.project.ProjectChildLocationDao; import cwms.cda.data.dto.project.ProjectChildLocations; @@ -49,12 +52,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; public class ProjectChildLocationHandler implements Handler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); public static final String TAGS = "Projects"; public static final String PATH = "/projects/child-locations/"; private final MetricRegistry metrics; @@ -105,9 +110,18 @@ public void handle(@NotNull Context ctx) throws Exception { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(formatHeader, ProjectChildLocations.class); String result = Formats.format(contentType, childLocations, ProjectChildLocations.class); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 Project Child Locations", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Project Child Locations"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockCatalog.java b/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockCatalog.java index 488d2abc64..6aed96cfcc 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockCatalog.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockCatalog.java @@ -36,6 +36,8 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import cwms.cda.api.Controllers; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.project.ProjectLockDao; import cwms.cda.data.dto.project.ProjectLock; @@ -50,7 +52,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; - +import java.io.IOException; import java.util.List; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; @@ -113,9 +115,17 @@ public void handle(@NotNull Context ctx) throws Exception { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(formatHeader, ProjectLock.class); String result = Formats.format(contentType, locks, ProjectLock.class); - ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 project locks", ex); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockGetOne.java b/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockGetOne.java index c3da7dcd99..cd11b82b85 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockGetOne.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockGetOne.java @@ -36,7 +36,10 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.Controllers; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.project.ProjectLockDao; import cwms.cda.data.dto.project.ProjectLock; @@ -51,11 +54,12 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; - +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; public class ProjectLockGetOne implements Handler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); public static final String TAGS = "Project Locks"; private final MetricRegistry metrics; @@ -105,17 +109,25 @@ public void handle(@NotNull Context ctx) throws Exception { try (final Timer.Context ignored = markAndTime(GET_ONE)) { ProjectLockDao lockDao = new ProjectLockDao(JooqDao.getDslContext(ctx)); ProjectLock lock = lockDao.retrieveLock(office, prjId, appId); - if(lock != null) { + if (lock != null) { String acceptHeader = ctx.header(Header.ACCEPT); ContentType acceptType = Formats.parseHeader(acceptHeader, ProjectLock.class); String result = Formats.format(acceptType, lock); - ctx.result(result); ctx.contentType(acceptType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { ctx.status(HttpServletResponse.SC_NOT_FOUND); } + } catch (IOException ex) { + CdaError error = ExceptionTraceSupport.buildError(ctx, + "Failed to process request to retrieve Project Lock", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Project Lock"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingEffectiveDatesController.java b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingEffectiveDatesController.java index 0f958033cd..2d921604f6 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingEffectiveDatesController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingEffectiveDatesController.java @@ -1,10 +1,6 @@ package cwms.cda.api.rating; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; import static com.codahale.metrics.MetricRegistry.name; -import com.codahale.metrics.Timer; -import cwms.cda.api.Controllers; import static cwms.cda.api.Controllers.BEGIN; import static cwms.cda.api.Controllers.END; import static cwms.cda.api.Controllers.OFFICE_MASK; @@ -15,6 +11,14 @@ import static cwms.cda.api.Controllers.TIMEZONE; import static cwms.cda.api.Controllers.queryParamAsInstant; import static cwms.cda.data.dao.JooqDao.getDslContext; + +import com.codahale.metrics.Histogram; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.Controllers; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.RatingSpecDao; import cwms.cda.data.dto.rating.RatingEffectiveDatesMap; import cwms.cda.formatters.ContentType; @@ -26,12 +30,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.time.Instant; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; public final class RatingEffectiveDatesController implements Handler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -82,9 +88,17 @@ public void handle(@NotNull Context ctx) throws Exception { ContentType contentType = Formats.parseHeader(formatHeader, RatingEffectiveDatesMap.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, effectiveDatesForSpecs); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); + + 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 rating effective dates", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve rating effective dates"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingLatestController.java b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingLatestController.java index aff922c105..70b4827d9b 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingLatestController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingLatestController.java @@ -34,12 +34,16 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.Controllers; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JsonRatingUtils; import cwms.cda.data.dao.RatingDao; import cwms.cda.data.dao.RatingSetDao; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; +import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.http.Handler; import io.javalin.http.HttpCode; @@ -47,11 +51,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; public class RatingLatestController implements Handler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private static final String TAG = "Ratings"; private final MetricRegistry metrics; @@ -101,11 +108,18 @@ public void handle(@NotNull Context ctx) throws Exception { String body = getLatestRatingSet(ctx, officeId, rating, contentType); ctx.contentType(contentType.toString()); if (body != null) { - ctx.result(body); - ctx.status(HttpCode.OK); + ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = body.getBytes(); + ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); + ctx.res.getOutputStream().write(bytes); } else { ctx.status(HttpCode.NOT_FOUND); } + } catch (IOException ex) { + CdaError error = ExceptionTraceSupport.buildError(ctx, "Failed to process request to retrieve Rating", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve Rating"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingMetadataController.java b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingMetadataController.java index bd684d0e91..ae5efd48f3 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingMetadataController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rating/RatingMetadataController.java @@ -25,10 +25,8 @@ package cwms.cda.api.rating; import static com.codahale.metrics.MetricRegistry.name; - import static cwms.cda.api.Controllers.END; import static cwms.cda.api.Controllers.GET_ALL; -import static cwms.cda.api.Controllers.NOT_SUPPORTED_YET; import static cwms.cda.api.Controllers.OFFICE; import static cwms.cda.api.Controllers.PAGE; import static cwms.cda.api.Controllers.PAGE_SIZE; @@ -42,8 +40,10 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.Controllers; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.JooqDao; import cwms.cda.data.dao.RatingMetadataDao; import cwms.cda.data.dto.rating.RatingMetadataList; @@ -57,8 +57,8 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.time.ZonedDateTime; -import com.google.common.flogger.FluentLogger; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -152,7 +152,7 @@ public void getAll(Context ctx) { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(formatHeader, RatingMetadataList.class); - try (final Timer.Context timeContext = markAndTime(GET_ALL)){ + try (final Timer.Context timeContext = markAndTime(GET_ALL)) { DSLContext dsl = getDslContext(ctx); RatingMetadataDao dao = getDao(dsl); @@ -161,12 +161,19 @@ public void getAll(Context ctx) { ratingIdMask, beginZdt, endZdt); String result = Formats.format(contentType, metadataList); - ctx.result(result); - ctx.contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 rating metadata", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve rating metadata"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rating/ReverseRateTimeSeriesController.java b/cwms-data-api/src/main/java/cwms/cda/api/rating/ReverseRateTimeSeriesController.java index 4ef734c18c..5548678145 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rating/ReverseRateTimeSeriesController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rating/ReverseRateTimeSeriesController.java @@ -36,7 +36,10 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.BaseHandler; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.RateDao; import cwms.cda.data.dto.rating.RateInputTimeSeries; import cwms.cda.data.dto.rating.RatedOutput; @@ -52,11 +55,13 @@ import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; public final class ReverseRateTimeSeriesController extends BaseHandler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private static final String REVERSE_RATE = "ReverseRate"; @@ -110,7 +115,17 @@ public void handle(@NotNull Context ctx) throws Exception { String acceptFormatHeader = ctx.header(Header.ACCEPT); ContentType acceptContentType = Formats.parseHeader(acceptFormatHeader, RatedOutputTimeSeries.class); String result = Formats.format(acceptContentType, output); - ctx.status(HttpServletResponse.SC_OK).result(result); + ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 reverse rate input values", ex); + logger.atSevere().withCause(ex).log("Failed to process request to reverse rate input values"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rating/ReverseRateValuesController.java b/cwms-data-api/src/main/java/cwms/cda/api/rating/ReverseRateValuesController.java index 58b9f6dda5..afbb601f4c 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rating/ReverseRateValuesController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rating/ReverseRateValuesController.java @@ -36,7 +36,10 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.BaseHandler; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.RateDao; import cwms.cda.data.dto.rating.RateInputValues; import cwms.cda.data.dto.rating.RatedOutput; @@ -52,11 +55,13 @@ import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; public final class ReverseRateValuesController extends BaseHandler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private static final String REVERSE_RATE = "ReverseRate"; @@ -110,7 +115,16 @@ public void handle(@NotNull Context ctx) throws Exception { String acceptFormatHeader = ctx.header(Header.ACCEPT); ContentType acceptContentType = Formats.parseHeader(acceptFormatHeader, RatedOutputValues.class); String result = Formats.format(acceptContentType, output); - ctx.status(HttpServletResponse.SC_OK).result(result); + ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 reverse rate input values", ex); + logger.atSevere().withCause(ex).log("Failed to process request to reverse rate input values"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rss/RssHandler.java b/cwms-data-api/src/main/java/cwms/cda/api/rss/RssHandler.java index c264599251..efaa6b7c54 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rss/RssHandler.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rss/RssHandler.java @@ -24,14 +24,27 @@ package cwms.cda.api.rss; -import static cwms.cda.api.Controllers.*; +import static cwms.cda.api.Controllers.CURSOR; +import static cwms.cda.api.Controllers.GET_ALL; +import static cwms.cda.api.Controllers.NAME; +import static cwms.cda.api.Controllers.OFFICE; +import static cwms.cda.api.Controllers.PAGE; +import static cwms.cda.api.Controllers.PAGE_SIZE; +import static cwms.cda.api.Controllers.SINCE; +import static cwms.cda.api.Controllers.STATUS_200; +import static cwms.cda.api.Controllers.STATUS_404; +import static cwms.cda.api.Controllers.TIMEZONE; +import static cwms.cda.api.Controllers.queryParamAsClass; +import static cwms.cda.api.Controllers.queryParamAsInstant; import static cwms.cda.data.dao.JooqDao.getDslContext; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.BaseHandler; import cwms.cda.api.enums.MessageQueue; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.rss.MessageDao; import cwms.cda.data.dto.CwmsDTOPaginated; import cwms.cda.data.dto.rss.RssFeed; @@ -45,17 +58,20 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.net.URISyntaxException; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.function.UnaryOperator; +import javax.servlet.http.HttpServletResponse; import org.apache.http.client.utils.URIBuilder; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; public final class RssHandler extends BaseHandler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private static final int DEFAULT_PAGE_SIZE = 500; private static final String TAG = "RSS"; @@ -120,8 +136,17 @@ public void handle(@NotNull Context ctx) throws Exception { MessageDao dao = new MessageDao(dsl); RssFeed feed = dao.retrieveFeed(cursor, pageSize, office, name, since, newLinkTemplate(ctx)); String result = Formats.format(contentType, feed); - ctx.result(result); ctx.contentType(contentType.toString()); + ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 data as RSS feed", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve data as RSS feed"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileBase.java b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileBase.java index d2a01e6ec6..f839bdb6e3 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileBase.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileBase.java @@ -28,11 +28,13 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.Controllers; import cwms.cda.data.dao.timeseriesprofile.TimeSeriesProfileDao; import org.jooq.DSLContext; public abstract class TimeSeriesProfileBase { + static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); static final String TAG = "TimeSeries"; private MetricRegistry metrics; diff --git a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileCatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileCatalogController.java index fefe55d8bd..ab903d2f69 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileCatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileCatalogController.java @@ -38,6 +38,8 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.timeseriesprofile.TimeSeriesProfileDao; import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileList; import cwms.cda.formatters.ContentType; @@ -50,12 +52,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; public final class TimeSeriesProfileCatalogController extends TimeSeriesProfileBase implements Handler { + public static final String TAG = "Time Series Profiles"; public static final String PARAMETER_ID_MASK = "parameter-id-mask"; public TimeSeriesProfileCatalogController(MetricRegistry metrics) { @@ -103,7 +107,16 @@ public void handle(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(acceptHeader, TimeSeriesProfileList.class); String results = Formats.format(contentType, retrievedProfiles); ctx.status(HttpServletResponse.SC_OK); - ctx.result(results); + ctx.contentType(contentType.toString()); + + byte[] bytes = results.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 time series profiles", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve time series profiles"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileController.java b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileController.java index 6e535b9ebb..854a2362df 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileController.java @@ -36,6 +36,8 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.timeseriesprofile.TimeSeriesProfileDao; import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfile; import cwms.cda.formatters.ContentType; @@ -48,6 +50,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -95,7 +98,16 @@ public void handle(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(acceptHeader, TimeSeriesProfile.class); String result = Formats.format(contentType, returned); ctx.status(HttpServletResponse.SC_OK); - ctx.result(result); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 Time Series Profile", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Time Series Profile"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceCatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceCatalogController.java index bd6691f3d7..903ac6a1f8 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceCatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceCatalogController.java @@ -36,6 +36,9 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.timeseriesprofile.TimeSeriesProfileInstanceDao; import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileInstance; import cwms.cda.formatters.ContentType; @@ -48,6 +51,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; @@ -55,6 +59,7 @@ public final class TimeSeriesProfileInstanceCatalogController extends TimeSeriesProfileInstanceBase implements Handler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); public TimeSeriesProfileInstanceCatalogController(MetricRegistry metrics) { tspMetrics(metrics); } @@ -99,8 +104,17 @@ public void handle(@NotNull Context ctx) { String acceptHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(acceptHeader, TimeSeriesProfileInstance.class); String result = Formats.format(contentType, retrievedInstances, TimeSeriesProfileInstance.class); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 time series profile instances", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve time series profile instances"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceController.java b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceController.java index f8cb337955..b52b2f3ca7 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceController.java @@ -51,6 +51,9 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.timeseriesprofile.TimeSeriesProfileInstanceDao; import cwms.cda.data.dto.CwmsId; import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileInstance; @@ -64,6 +67,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.time.Instant; import java.util.Arrays; import java.util.List; @@ -73,6 +77,7 @@ public final class TimeSeriesProfileInstanceController extends TimeSeriesProfileInstanceBase implements Handler { + private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); public TimeSeriesProfileInstanceController(MetricRegistry metrics) { tspMetrics(metrics); @@ -165,8 +170,17 @@ public void handle(@NotNull Context ctx) { String acceptHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(acceptHeader, TimeSeriesProfileInstance.class); String result = Formats.format(contentType, returnedInstance); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 time series profile instance", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve time series profile instance"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserBase.java b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserBase.java index 277f82e2d9..bc5fca5101 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserBase.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserBase.java @@ -28,11 +28,13 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.Controllers; import cwms.cda.data.dao.timeseriesprofile.TimeSeriesProfileParserDao; import org.jooq.DSLContext; public abstract class TimeSeriesProfileParserBase { + static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); static final String TAG = "TimeSeries"; public static final String COLUMNAR_TYPE = "columnar-timeseries-profile-parser"; public static final String INDEXED_TYPE = "indexed-timeseries-profile-parser"; diff --git a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserCatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserCatalogController.java index e46c02959e..757521274d 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserCatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserCatalogController.java @@ -36,6 +36,8 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.timeseriesprofile.TimeSeriesProfileParserDao; import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileParser; import cwms.cda.formatters.ContentType; @@ -48,6 +50,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; @@ -101,7 +104,16 @@ public void handle(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(acceptHeader, TimeSeriesProfileParser.class); String result = Formats.format(contentType, tspParsers, TimeSeriesProfileParser.class); ctx.status(HttpServletResponse.SC_OK); - ctx.result(result); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 time series profile parsers", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve time series profile parsers"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserController.java b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserController.java index 406a25f71b..53bc6165be 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileParserController.java @@ -38,6 +38,8 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.timeseriesprofile.TimeSeriesProfileParserDao; import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileParser; import cwms.cda.formatters.ContentType; @@ -50,6 +52,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -103,7 +106,16 @@ public void handle(@NotNull Context ctx) { ContentType contentType = Formats.parseHeader(acceptHeader, TimeSeriesProfileParser.class); String result = Formats.format(contentType, tspParser); ctx.status(HttpServletResponse.SC_OK); - ctx.result(result); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 time series profile parser", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve time series profile parser"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/AccountingCatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/AccountingCatalogController.java index 3393d3d92c..ce899b2260 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/AccountingCatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/AccountingCatalogController.java @@ -43,7 +43,6 @@ import static cwms.cda.api.Controllers.TIME_FORMAT_DESC; import static cwms.cda.api.Controllers.UNIT; import static cwms.cda.api.Controllers.WATER_USER; -import static cwms.cda.api.Controllers.queryParamAsClass; import static cwms.cda.api.Controllers.requiredInstant; import static cwms.cda.data.dao.JooqDao.getDslContext; @@ -52,6 +51,7 @@ import com.google.common.flogger.FluentLogger; import cwms.cda.api.Controllers; import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.watersupply.WaterContractDao; import cwms.cda.data.dao.watersupply.WaterSupplyAccountingDao; import cwms.cda.data.dto.CwmsId; @@ -69,6 +69,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.io.IOException; import java.time.Instant; import java.util.List; import javax.servlet.http.HttpServletResponse; @@ -213,8 +214,17 @@ public void handle(Context ctx) { ascending, rowLimit); String result = Formats.format(contentType, accounting, WaterSupplyAccounting.class); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); + ctx.contentType(contentType.toString()); + + byte[] bytes = result.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 pump accounting", ex); + LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve pump accounting"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractCatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractCatalogController.java index 26a1d0e68c..91b27203c2 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractCatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractCatalogController.java @@ -35,6 +35,8 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.watersupply.WaterContractDao; import cwms.cda.data.dto.CwmsId; import cwms.cda.data.dto.watersupply.WaterUserContract; @@ -42,12 +44,12 @@ import cwms.cda.formatters.Formats; import io.javalin.core.util.Header; import io.javalin.http.Context; -import io.javalin.http.Handler; import io.javalin.plugin.openapi.annotations.HttpMethod; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; 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; @@ -98,8 +100,16 @@ public void handle(@NotNull Context ctx) { String waterUserEntity = ctx.pathParam(WATER_USER); List contracts = contractDao.getAllWaterContracts(projectLocation, waterUserEntity); String result = Formats.format(contentType, contracts, WaterUserContract.class); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 water contracts", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve water contracts"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractController.java index 43263274a1..187c552724 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractController.java @@ -36,6 +36,8 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.watersupply.WaterContractDao; import cwms.cda.data.dto.CwmsId; import cwms.cda.data.dto.watersupply.WaterUserContract; @@ -43,14 +45,13 @@ import cwms.cda.formatters.Formats; import io.javalin.core.util.Header; import io.javalin.http.Context; -import io.javalin.http.Handler; import io.javalin.plugin.openapi.annotations.HttpMethod; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; - +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -106,8 +107,16 @@ public void handle(@NotNull Context ctx) { WaterContractDao contractDao = getContractDao(dsl); WaterUserContract contract = contractDao.getWaterContract(contractName, projectLocation, waterUser); String result = Formats.format(contentType, contract); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 water contract", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve water contract"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeCatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeCatalogController.java index ec92d906c8..496018ff39 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeCatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeCatalogController.java @@ -32,20 +32,21 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.watersupply.WaterContractDao; import cwms.cda.data.dto.LookupType; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; import io.javalin.core.util.Header; import io.javalin.http.Context; -import io.javalin.http.Handler; import io.javalin.plugin.openapi.annotations.HttpMethod; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; - +import java.io.IOException; import java.util.List; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; @@ -93,8 +94,16 @@ public void handle(@NotNull Context ctx) { WaterContractDao dao = getContractDao(dsl); List typeList = dao.getAllWaterContractTypes(officeId); result = Formats.format(contentType, typeList, LookupType.class); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 water contract types", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve water contract types"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterSupplyControllerBase.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterSupplyControllerBase.java index 1e521d4a41..2369672e28 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterSupplyControllerBase.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterSupplyControllerBase.java @@ -27,13 +27,13 @@ package cwms.cda.api.watersupply; import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; +import com.google.common.flogger.FluentLogger; import cwms.cda.api.BaseHandler; -import cwms.cda.api.Controllers; import cwms.cda.data.dao.watersupply.WaterContractDao; import org.jooq.DSLContext; public abstract class WaterSupplyControllerBase extends BaseHandler { + static final FluentLogger logger = FluentLogger.forEnclosingClass(); static final String TAG = "Water Contracts"; public WaterSupplyControllerBase(MetricRegistry metrics) { diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCatalogController.java index 253564b118..c35a316a6f 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCatalogController.java @@ -34,6 +34,8 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.watersupply.WaterContractDao; import cwms.cda.data.dto.CwmsId; import cwms.cda.data.dto.watersupply.WaterUser; @@ -42,14 +44,13 @@ import cwms.cda.formatters.Formats; import io.javalin.core.util.Header; import io.javalin.http.Context; -import io.javalin.http.Handler; import io.javalin.plugin.openapi.annotations.HttpMethod; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; - +import java.io.IOException; import java.util.List; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; @@ -99,6 +100,15 @@ public void handle(@NotNull Context ctx) { String result = Formats.format(contentType, users, WaterUserContract.class); ctx.result(result); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 water users", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve water users"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserController.java index d0de71695f..5b23b822e9 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserController.java @@ -35,6 +35,8 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import cwms.cda.api.errors.CdaError; +import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.watersupply.WaterContractDao; import cwms.cda.data.dto.CwmsId; import cwms.cda.data.dto.watersupply.WaterUser; @@ -43,14 +45,13 @@ import cwms.cda.formatters.Formats; import io.javalin.core.util.Header; import io.javalin.http.Context; -import io.javalin.http.Handler; import io.javalin.plugin.openapi.annotations.HttpMethod; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import io.javalin.plugin.openapi.annotations.OpenApiSecurity; - +import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -102,6 +103,15 @@ public void handle(@NotNull Context ctx) { String result = Formats.format(contentType, user); ctx.result(result); ctx.status(HttpServletResponse.SC_OK); + + byte[] bytes = result.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 water user", ex); + logger.atSevere().withCause(ex).log("Failed to process request to retrieve water user"); + ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } } From 298897ca080fe0d7029d70c1c5dab1cd8059fbda Mon Sep 17 00:00:00 2001 From: zack-rma Date: Tue, 16 Jun 2026 13:28:07 -0700 Subject: [PATCH 4/6] Cleaned up imports, reverted tag addition, removed lingering result context calls. --- .../api/DownstreamLocationsGetController.java | 1 - .../cwms/cda/api/LocationGroupController.java | 1 - .../java/cwms/cda/api/PoolController.java | 1 - .../cwms/cda/api/TimeSeriesController.java | 40 +------------------ .../cda/api/TimeSeriesFilteredController.java | 25 +----------- ...eSeriesIdentifierDescriptorController.java | 28 +------------ .../TimeSeriesProfileCatalogController.java | 1 - .../WaterUserCatalogController.java | 1 - .../api/watersupply/WaterUserController.java | 1 - 9 files changed, 4 insertions(+), 95 deletions(-) diff --git a/cwms-data-api/src/main/java/cwms/cda/api/DownstreamLocationsGetController.java b/cwms-data-api/src/main/java/cwms/cda/api/DownstreamLocationsGetController.java index 9cae344bdb..1fce4d6a76 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/DownstreamLocationsGetController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/DownstreamLocationsGetController.java @@ -112,7 +112,6 @@ public void handle(@NotNull Context ctx) throws Exception { ContentType contentType = Formats.parseHeader(formatHeader, StreamLocation.class); ctx.contentType(contentType.toString()); String serialized = Formats.format(contentType, downstreamLocations, StreamLocation.class); - ctx.result(serialized); ctx.status(HttpServletResponse.SC_OK); requestResultSize.update(serialized.length()); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LocationGroupController.java b/cwms-data-api/src/main/java/cwms/cda/api/LocationGroupController.java index 41b2b7dee9..70bde18bb1 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LocationGroupController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LocationGroupController.java @@ -147,7 +147,6 @@ Boolean.class, false, metrics, name(LocationGroupController.class.getName(), String result = Formats.format(contentType, grps, LocationGroup.class); - ctx.result(result); ctx.contentType(contentType.toString()); requestResultSize.update(result.length()); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/PoolController.java b/cwms-data-api/src/main/java/cwms/cda/api/PoolController.java index 76108fcb57..c806b6b68c 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/PoolController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/PoolController.java @@ -230,7 +230,6 @@ public void getOne(@NotNull Context ctx, @NotNull String poolId) { String result = Formats.format(contentType, pool); - ctx.result(result); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesController.java b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesController.java index 22edd37921..5a977d9616 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesController.java @@ -1,45 +1,7 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.BEGIN; -import static cwms.cda.api.Controllers.CREATE; -import static cwms.cda.api.Controllers.CREATE_AS_LRTS; -import static cwms.cda.api.Controllers.CURSOR; -import static cwms.cda.api.Controllers.DATUM; -import static cwms.cda.api.Controllers.DELETE; -import static cwms.cda.api.Controllers.END; -import static cwms.cda.api.Controllers.END_TIME_INCLUSIVE; -import static cwms.cda.api.Controllers.FORMAT; -import static cwms.cda.api.Controllers.GET_ALL; -import static cwms.cda.api.Controllers.GET_ONE; -import static cwms.cda.api.Controllers.INCLUDE_ENTRY_DATE; -import static cwms.cda.api.Controllers.MAX_VERSION; -import static cwms.cda.api.Controllers.NAME; -import static cwms.cda.api.Controllers.OFFICE; -import static cwms.cda.api.Controllers.OVERRIDE_PROTECTION; -import static cwms.cda.api.Controllers.PAGE; -import static cwms.cda.api.Controllers.PAGE_SIZE; -import static cwms.cda.api.Controllers.RESULTS; -import static cwms.cda.api.Controllers.SIZE; -import static cwms.cda.api.Controllers.START_TIME_INCLUSIVE; -import static cwms.cda.api.Controllers.STATUS_200; -import static cwms.cda.api.Controllers.STATUS_400; -import static cwms.cda.api.Controllers.STATUS_404; -import static cwms.cda.api.Controllers.STATUS_501; -import static cwms.cda.api.Controllers.STORE_RULE; -import static cwms.cda.api.Controllers.TIMESERIES; -import static cwms.cda.api.Controllers.TIMEZONE; -import static cwms.cda.api.Controllers.TIME_FORMAT_DESC; -import static cwms.cda.api.Controllers.UNIT; -import static cwms.cda.api.Controllers.UNITS; -import static cwms.cda.api.Controllers.UPDATE; -import static cwms.cda.api.Controllers.VERSION; -import static cwms.cda.api.Controllers.VERSION_DATE; -import static cwms.cda.api.Controllers.addDeprecatedContentTypeWarning; -import static cwms.cda.api.Controllers.queryParamAsClass; -import static cwms.cda.api.Controllers.queryParamAsZdt; -import static cwms.cda.api.Controllers.requiredParam; -import static cwms.cda.api.Controllers.requiredZdt; +import static cwms.cda.api.Controllers.*; import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesFilteredController.java b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesFilteredController.java index 6a1806216a..ea144fe66a 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesFilteredController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesFilteredController.java @@ -1,30 +1,7 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.BEGIN; -import static cwms.cda.api.Controllers.CURSOR; -import static cwms.cda.api.Controllers.END; -import static cwms.cda.api.Controllers.GET_ALL; -import static cwms.cda.api.Controllers.INCLUDE_ENTRY_DATE; -import static cwms.cda.api.Controllers.NAME; -import static cwms.cda.api.Controllers.OFFICE; -import static cwms.cda.api.Controllers.PAGE; -import static cwms.cda.api.Controllers.PAGE_SIZE; -import static cwms.cda.api.Controllers.QUERY; -import static cwms.cda.api.Controllers.RESULTS; -import static cwms.cda.api.Controllers.SIZE; -import static cwms.cda.api.Controllers.STATUS_200; -import static cwms.cda.api.Controllers.STATUS_400; -import static cwms.cda.api.Controllers.STATUS_404; -import static cwms.cda.api.Controllers.STATUS_501; -import static cwms.cda.api.Controllers.TIMEZONE; -import static cwms.cda.api.Controllers.TIME_FORMAT_DESC; -import static cwms.cda.api.Controllers.UNIT; -import static cwms.cda.api.Controllers.VERSION_DATE; -import static cwms.cda.api.Controllers.addDeprecatedContentTypeWarning; -import static cwms.cda.api.Controllers.queryParamAsClass; -import static cwms.cda.api.Controllers.queryParamAsZdt; -import static cwms.cda.api.Controllers.requiredParam; +import static cwms.cda.api.Controllers.*; import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesIdentifierDescriptorController.java b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesIdentifierDescriptorController.java index 2aa23b567a..5d90559481 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesIdentifierDescriptorController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesIdentifierDescriptorController.java @@ -25,31 +25,7 @@ package cwms.cda.api; import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.ACTIVE; -import static cwms.cda.api.Controllers.CREATE; -import static cwms.cda.api.Controllers.DELETE; -import static cwms.cda.api.Controllers.FAIL_IF_EXISTS; -import static cwms.cda.api.Controllers.GET_ALL; -import static cwms.cda.api.Controllers.GET_ONE; -import static cwms.cda.api.Controllers.INCLUDE_ALIASES; -import static cwms.cda.api.Controllers.INTERVAL_OFFSET; -import static cwms.cda.api.Controllers.METHOD; -import static cwms.cda.api.Controllers.NAME; -import static cwms.cda.api.Controllers.OFFICE; -import static cwms.cda.api.Controllers.PAGE; -import static cwms.cda.api.Controllers.PAGE_SIZE; -import static cwms.cda.api.Controllers.RESULTS; -import static cwms.cda.api.Controllers.SIZE; -import static cwms.cda.api.Controllers.SNAP_BACKWARD; -import static cwms.cda.api.Controllers.SNAP_FORWARD; -import static cwms.cda.api.Controllers.STATUS_200; -import static cwms.cda.api.Controllers.STATUS_404; -import static cwms.cda.api.Controllers.STATUS_501; -import static cwms.cda.api.Controllers.TIMESERIES_ID; -import static cwms.cda.api.Controllers.TIMESERIES_ID_REGEX; -import static cwms.cda.api.Controllers.UPDATE; -import static cwms.cda.api.Controllers.requiredParam; -import static cwms.cda.api.Controllers.requiredParamAs; +import static cwms.cda.api.Controllers.*; import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; @@ -371,7 +347,7 @@ public void update(@NotNull Context ctx, @NotNull String name) { @Override public void delete(@NotNull Context ctx, @NotNull String timeseriesId) { - JooqDao.DeleteMethod method =requiredParamAs(ctx, METHOD, JooqDao.DeleteMethod.class); + JooqDao.DeleteMethod method = requiredParamAs(ctx, METHOD, JooqDao.DeleteMethod.class); String office = requiredParam(ctx, OFFICE); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileCatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileCatalogController.java index ab903d2f69..caae208f65 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileCatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileCatalogController.java @@ -59,7 +59,6 @@ public final class TimeSeriesProfileCatalogController extends TimeSeriesProfileBase implements Handler { - public static final String TAG = "Time Series Profiles"; public static final String PARAMETER_ID_MASK = "parameter-id-mask"; public TimeSeriesProfileCatalogController(MetricRegistry metrics) { diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCatalogController.java index c35a316a6f..353b43c6bb 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCatalogController.java @@ -98,7 +98,6 @@ public void handle(@NotNull Context ctx) { WaterContractDao contractDao = getContractDao(dsl); List users = contractDao.getAllWaterUsers(projectLocation); String result = Formats.format(contentType, users, WaterUserContract.class); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); byte[] bytes = result.getBytes(); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserController.java index 5b23b822e9..3c9bfbc4d7 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserController.java @@ -101,7 +101,6 @@ public void handle(@NotNull Context ctx) { WaterContractDao contractDao = getContractDao(dsl); WaterUser user = contractDao.getWaterUser(projectLocation, entityName); String result = Formats.format(contentType, user); - ctx.result(result); ctx.status(HttpServletResponse.SC_OK); byte[] bytes = result.getBytes(); From ad0189a4ad549427a5eb1a893e0615bf9158e660 Mon Sep 17 00:00:00 2001 From: zack-rma Date: Tue, 16 Jun 2026 13:44:27 -0700 Subject: [PATCH 5/6] Reverted change for office and state controller due to failing tests --- .../java/cwms/cda/api/OfficeController.java | 28 ++++--------------- .../java/cwms/cda/api/StateController.java | 15 +--------- 2 files changed, 6 insertions(+), 37 deletions(-) diff --git a/cwms-data-api/src/main/java/cwms/cda/api/OfficeController.java b/cwms-data-api/src/main/java/cwms/cda/api/OfficeController.java index 438e1b8ceb..7d02e7bebc 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/OfficeController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/OfficeController.java @@ -14,7 +14,6 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; -import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.OfficeDao; import cwms.cda.data.dto.Office; @@ -28,7 +27,6 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; -import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.List; @@ -43,7 +41,6 @@ * @see OfficeController */ public class OfficeController implements CrudHandler { - private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; @@ -110,19 +107,13 @@ public void getAll(Context ctx) { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseQueryOrHeaderParam(formatHeader, formatParm, Office.class); - Controllers.addDeprecatedContentTypeWarning(ctx, contentType); String result = Formats.format(contentType, offices, Office.class); - ctx.contentType(contentType.toString()); - ctx.status(HttpServletResponse.SC_OK); + + Controllers.addDeprecatedContentTypeWarning(ctx, contentType); + + ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); - byte[] bytes = result.getBytes(); - ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); - ctx.res.getOutputStream().write(bytes); - } catch (IOException ex) { - CdaError re = new CdaError("Error writing response"); - LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Basins"); - ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } @@ -164,24 +155,15 @@ public void getOne(Context ctx, String officeId) { ContentType contentType = Formats.parseHeaderAndQueryParm(formatHeader, formatParm, Office.class); String result = Formats.format(contentType, office.get()); Controllers.addDeprecatedContentTypeWarning(ctx, contentType); - ctx.contentType(contentType.toString()); - ctx.status(HttpServletResponse.SC_OK); + ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); - - byte[] bytes = result.getBytes(); - ctx.header(Header.CONTENT_LENGTH, String.valueOf(bytes.length)); - ctx.res.getOutputStream().write(bytes); } else { Map map = new HashMap<>(); map.put(OFFICE, "An office with that name does not exist"); CdaError re = new CdaError("Not Found", map); ctx.status(HttpServletResponse.SC_NOT_FOUND).json(re); } - } catch (IOException ex) { - CdaError re = new CdaError("Error writing response"); - LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve Basins"); - ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re); } } diff --git a/cwms-data-api/src/main/java/cwms/cda/api/StateController.java b/cwms-data-api/src/main/java/cwms/cda/api/StateController.java index 68e29e2d25..0a05423f4f 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/StateController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/StateController.java @@ -33,21 +33,17 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; -import com.google.common.flogger.FluentLogger; import cwms.cda.api.errors.CdaError; -import cwms.cda.api.errors.ExceptionTraceSupport; import cwms.cda.data.dao.StateDao; import cwms.cda.data.dto.State; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; -import cwms.cda.formatters.FormattingException; import io.javalin.apibuilder.CrudHandler; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; 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; @@ -60,7 +56,6 @@ * @see StateController */ public class StateController implements CrudHandler { - private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass(); private final MetricRegistry metrics; private final Histogram requestResultSize; @@ -100,17 +95,9 @@ public void getAll(@NotNull Context ctx) { String formatHeader = ctx.header(Header.ACCEPT); ContentType contentType = Formats.parseHeader(formatHeader, State.class); String result = Formats.format(contentType, states, State.class); + ctx.result(result).contentType(contentType.toString()); requestResultSize.update(result.length()); ctx.status(HttpServletResponse.SC_OK); - ctx.contentType(contentType.toString()); - - byte[] bytes = result.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 States", ex); - LOGGER.atSevere().withCause(ex).log("Failed to process request to retrieve States"); - ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(error); } } From 1e4d57d37ee9747530d4b4238bba8b055f31caa4 Mon Sep 17 00:00:00 2001 From: zack-rma Date: Wed, 24 Jun 2026 13:29:20 -0700 Subject: [PATCH 6/6] import cleanup --- cwms-data-api/src/main/java/cwms/cda/api/rss/RssHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/cwms-data-api/src/main/java/cwms/cda/api/rss/RssHandler.java b/cwms-data-api/src/main/java/cwms/cda/api/rss/RssHandler.java index abad904ae0..08671089a6 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/rss/RssHandler.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/rss/RssHandler.java @@ -50,7 +50,6 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import java.io.IOException; -import java.io.IOException; import java.net.URISyntaxException; import java.net.URLDecoder; import java.net.URLEncoder;