diff --git a/cwms-data-api/src/main/java/cwms/cda/api/BaseCrudHandler.java b/cwms-data-api/src/main/java/cwms/cda/api/BaseCrudHandler.java
index 96d813cf3..d6b2e7f75 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/BaseCrudHandler.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/BaseCrudHandler.java
@@ -23,12 +23,15 @@
import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
+import com.google.common.flogger.FluentLogger;
import io.javalin.apibuilder.CrudHandler;
+import io.javalin.http.Context;
import static com.codahale.metrics.MetricRegistry.name;
import static cwms.cda.api.Controllers.RESULTS;
import static cwms.cda.api.Controllers.SIZE;
public abstract class BaseCrudHandler implements CrudHandler {
+ private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass();
private final MetricRegistry metrics;
private final Histogram requestResultSize;
@@ -46,4 +49,21 @@ protected final Timer.Context markAndTime(String subject) {
protected final void updateResultSize(String responseString) {
requestResultSize.update(responseString.length());
}
+
+ protected final void updateResultSize(int responseLength) {
+ requestResultSize.update(responseLength);
+ }
+
+ protected final void updateResultSize(long responseLength) {
+ requestResultSize.update(responseLength);
+ }
+
+ public MetricRegistry getMetrics() {
+ return metrics;
+ }
+
+ protected final void logUnusedPathParameter(Context ctx, String pathParam, String reason) {
+ String param = ctx.pathParam(pathParam);
+ LOGGER.atFinest().log("Path parameter '%s' is documented but not used in handler '%s'\nValue: '%s'\nReason: '%s'", pathParam, this.getClass().getSimpleName(), param, reason);
+ }
}
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/BaseHandler.java b/cwms-data-api/src/main/java/cwms/cda/api/BaseHandler.java
index 0a4ce454d..db9dc01db 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/BaseHandler.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/BaseHandler.java
@@ -23,6 +23,8 @@
import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
+import com.google.common.flogger.FluentLogger;
+import io.javalin.http.Context;
import io.javalin.http.Handler;
import static com.codahale.metrics.MetricRegistry.name;
import static cwms.cda.api.Controllers.RESULTS;
@@ -30,6 +32,7 @@
public abstract class BaseHandler implements Handler {
+ private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass();
private final MetricRegistry metrics;
private final Histogram requestResultSize;
@@ -47,4 +50,13 @@ protected final Timer.Context markAndTime(String subject) {
protected final void updateResultSize(int value) {
requestResultSize.update(value);
}
+
+ protected final void updateResultSize(long value) {
+ requestResultSize.update(value);
+ }
+
+ protected final void logUnusedPathParameter(Context ctx, String pathParam, String reason) {
+ String param = ctx.pathParam(pathParam);
+ LOGGER.atFinest().log("Path parameter '%s' is documented but not used in handler '%s'\nValue: '%s'\nReason: '%s'", pathParam, this.getClass().getSimpleName(), param, reason);
+ }
}
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 767f1ed36..8f6f1d0e1 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
@@ -70,19 +70,18 @@
import org.jooq.DSLContext;
-public class BinaryTimeSeriesController implements CrudHandler {
+public class BinaryTimeSeriesController extends BaseCrudHandler {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
static final String TAG = "Binary-TimeSeries";
public static final String REPLACE_ALL = "replace-all";
private static final String DEFAULT_BIN_TYPE_MASK = "*";
public static final String BINARY_TYPE_MASK = "binary-type-mask";
- private final MetricRegistry metrics;
public BinaryTimeSeriesController(MetricRegistry metrics) {
- this.metrics = metrics;
+ super(metrics);
}
@NotNull
@@ -91,11 +90,6 @@ protected TimeSeriesBinaryDao getDao(DSLContext dsl) {
}
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
- }
-
-
@OpenApi(
summary = "Retrieve binary time series values for a provided time window and date version."
+ "If individual values exceed 64 kilobytes, a URL to a separate download is "
@@ -179,7 +173,7 @@ public void getAll(@NotNull Context ctx) {
@OpenApi(ignore = true)
@Override
public void getOne(@NotNull Context ctx, @NotNull String templateId) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
@@ -232,8 +226,8 @@ public void create(@NotNull Context ctx) {
tags = {TAG}
)
@Override
- public void update(@NotNull Context ctx, @NotNull String oldBinaryTimeSeriesId) {
-
+ public void update(@NotNull Context ctx, @NotNull String name) {
+ logUnusedPathParameter(ctx, NAME, "Body contains information");
try (Timer.Context ignored = markAndTime(UPDATE)) {
boolean maxVersion = true;
boolean replaceAll = ctx.queryParamAsClass(REPLACE_ALL, Boolean.class).getOrDefault(false);
@@ -276,7 +270,7 @@ public void update(@NotNull Context ctx, @NotNull String oldBinaryTimeSeriesId)
tags = {TAG}
)
@Override
- public void delete(@NotNull Context ctx, @NotNull String binaryTimeSeriesId) {
+ public void delete(@NotNull Context ctx, @NotNull String name) {
try (Timer.Context ignored = markAndTime(DELETE)) {
DSLContext dsl = getDslContext(ctx);
String office = requiredParam(ctx, OFFICE);
@@ -289,7 +283,7 @@ public void delete(@NotNull Context ctx, @NotNull String binaryTimeSeriesId) {
TimeSeriesBinaryDao dao = getDao(dsl);
- dao.delete(office, binaryTimeSeriesId, mask, begin, end, version);
+ dao.delete(office, name, mask, begin, end, version);
ctx.status(HttpServletResponse.SC_NO_CONTENT);
}
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/BinaryTimeSeriesValueController.java b/cwms-data-api/src/main/java/cwms/cda/api/BinaryTimeSeriesValueController.java
index fb66e766c..cffac4407 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/BinaryTimeSeriesValueController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/BinaryTimeSeriesValueController.java
@@ -27,6 +27,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.BlobDao;
import cwms.cda.data.dao.StreamConsumer;
@@ -47,18 +48,11 @@
import static cwms.cda.data.dao.JooqDao.getDslContext;
-public class BinaryTimeSeriesValueController implements Handler {
- private final MetricRegistry metrics;
- private final Histogram requestResultSize;
-
+public class BinaryTimeSeriesValueController extends BaseHandler {
+ private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass();
public BinaryTimeSeriesValueController(MetricRegistry metrics) {
- this.metrics = metrics;
- requestResultSize = this.metrics.histogram((name(BinaryTimeSeriesValueController.class, RESULTS, SIZE)));
- }
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ super(metrics);
}
@OpenApi(
@@ -69,12 +63,6 @@ private Timer.Context markAndTime(String subject) {
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office of "
+ "the Binary TimeSeries whose data is to be included in the response."),
- @OpenApiParam(name = TIMEZONE, description = "Specifies "
- + "the time zone of the values of the begin and end fields (unless "
- + "otherwise specified). If this field is not specified, "
- + "the default time zone of UTC shall be used."),
- @OpenApiParam(name = DATE, required = true, description = "The date of the binary value to retrieve"),
- @OpenApiParam(name = VERSION_DATE, description = "The version date for the value to retrieve."),
@OpenApiParam(name = BLOB_ID, description = "Will be removed in a schema update. " +
"This is a placeholder for integration testing with schema 23.3.16", deprecated = true)
},
@@ -89,6 +77,8 @@ private Timer.Context markAndTime(String subject) {
public void handle(@NotNull Context ctx) {
//Implementation will change with new CWMS schema
//https://www.hec.usace.army.mil/confluence/display/CWMS/2024-02-29+Task2A+Text-ts+and+Binary-ts+Design
+ logUnusedPathParameter(ctx, NAME, "Handled as " + BLOB_ID + " in query parameter. May change with schema.");
+
try (Timer.Context ignored = markAndTime(GET_ALL)) {
String binaryId = requiredParam(ctx, BLOB_ID);
String officeId = requiredParam(ctx, OFFICE);
@@ -113,7 +103,7 @@ public void handle(@NotNull Context ctx) {
ctx.status(HttpServletResponse.SC_NOT_FOUND).json(new CdaError("Unable to find "
+ "blob based on given parameters"));
} else {
- requestResultSize.update(totalLength);
+ updateResultSize(totalLength);
RangeRequestUtil.seekableStream(ctx, is, isPosition, mediaType, totalLength);
}
};
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 5470c1d97..65e3aaa0f 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
@@ -40,24 +40,12 @@
/**
*
*/
-public class BlobController implements CrudHandler {
+public class BlobController extends BaseCrudHandler {
private static final int DEFAULT_PAGE_SIZE = 20;
public static final String TAG = "Blob";
- private final MetricRegistry metrics;
-
-
- private final Histogram requestResultSize;
-
public BlobController(MetricRegistry metrics) {
- this.metrics = metrics;
- String className = BlobController.class.getName();
-
- requestResultSize = this.metrics.histogram((name(className, RESULTS, SIZE)));
- }
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ super(metrics);
}
protected DSLContext getDslContext(Context ctx) {
@@ -91,6 +79,11 @@ private BlobAccess chooseBlobAccess(DSLContext dsl) {
+ "identifies where in the request you are. This is an opaque"
+ " value, and can be obtained from the 'next-page' value in "
+ "the response."),
+ @OpenApiParam(name = CURSOR, deprecated = true,
+ description = "This end point can return a lot of data, this "
+ + "identifies where in the request you are. This is an opaque"
+ + " value, and can be obtained from the 'next-page' value in "
+ + "the response. Deprecated, use " + PAGE + " instead."),
@OpenApiParam(name = PAGE_SIZE,
type = Integer.class,
description = "How many entries per page returned. Default "
@@ -116,7 +109,7 @@ public void getAll(@NotNull Context ctx) {
String office = ctx.queryParam(OFFICE);
String cursor = queryParamAsClass(ctx, new String[]{PAGE, CURSOR},
- String.class, "", metrics, name(BlobController.class.getName(), GET_ALL));
+ String.class, "", getMetrics(), name(BlobController.class.getName(), GET_ALL));
if (!CwmsDTOPaginated.CURSOR_CHECK.invoke(cursor)) {
ctx.json(new CdaError("cursor or page passed in but failed validation"))
@@ -125,7 +118,7 @@ public void getAll(@NotNull Context ctx) {
}
int pageSize = queryParamAsClass(ctx, new String[]{PAGE_SIZE},
- Integer.class, DEFAULT_PAGE_SIZE, metrics,
+ Integer.class, DEFAULT_PAGE_SIZE, getMetrics(),
name(BlobController.class.getName(), GET_ALL));
String like = ctx.queryParamAsClass(LIKE, String.class).getOrDefault(".*");
@@ -140,13 +133,21 @@ public void getAll(@NotNull Context ctx) {
ctx.result(result);
ctx.contentType(contentType.toString());
- requestResultSize.update(result.length());
+ updateResultSize(result.length());
}
}
@OpenApi(
description = "Returns the binary value of the requested blob as a seekable stream with the "
+ "appropriate media type.",
+ pathParams = {
+ @OpenApiParam(name = BLOB_ID, description = "If the _query_ parameter is provided this _path_ parameter "
+ + "is ignored and the value of the query parameter is used. "
+ + "Note: the _query_ parameter is necessary for id's that contain '/' or other special "
+ + "characters. This is due to limitations in path pattern matching. "
+ + "We will likely add support for encoding the ID in the path in the future. For now use the id field for those IDs. "
+ + "Client libraries should detect slashes and choose the appropriate field. \"ignored\" is suggested for the path endpoint."),
+ },
queryParams = {
@OpenApiParam(name = OFFICE, description = "Specifies the owning office."),
@OpenApiParam(name = BLOB_ID, description = "If this _query_ parameter is provided the id _path_ parameter "
@@ -198,7 +199,7 @@ public void getOne(@NotNull Context ctx, @NotNull String blobId) {
ctx.status(HttpServletResponse.SC_NOT_FOUND).json(new CdaError("Unable to find "
+ "blob based on given parameters"));
} else {
- requestResultSize.update(totalLength);
+ updateResultSize(totalLength);
// is OracleBlobInputStream or something from MinIO
RangeRequestUtil.seekableStream(ctx, is, isPosition, mediaType, totalLength);
}
@@ -265,6 +266,8 @@ public void create(@NotNull Context ctx) {
)
@Override
public void update(@NotNull Context ctx, @NotNull String blobId) {
+ logUnusedPathParameter(ctx, BLOB_ID, "Body contains information");
+
try (final Timer.Context ignored = markAndTime(UPDATE)) {
String idQueryParam = ctx.queryParam(BLOB_ID);
if (idQueryParam != null) {
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 f21784f0b..a4d04a7e4 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
@@ -31,6 +31,7 @@
import java.util.Map;
import java.util.Set;
import com.google.common.flogger.FluentLogger;
+import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
import org.owasp.html.PolicyFactory;
@@ -63,19 +64,19 @@ private Timer.Context markAndTime(String subject) {
@OpenApi(tags = {TAG}, ignore = true)
@Override
public void create(Context ctx) {
- ctx.status(HttpCode.NOT_IMPLEMENTED).result("cannot perform this action");
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(tags = {"Catalog"}, ignore = true)
@Override
public void delete(Context ctx, @NotNull String entry) {
- ctx.status(HttpCode.NOT_IMPLEMENTED).result("cannot perform this action");
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(tags = {"Catalog"}, ignore = true)
@Override
public void getAll(Context ctx) {
- ctx.status(HttpCode.NOT_IMPLEMENTED).result("cannot perform this action");
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
@@ -84,7 +85,11 @@ public void getAll(Context ctx) {
description = "This end point can return a lot of data, this "
+ "identifies where in the request you are."
),
-
+ @OpenApiParam(name = CURSOR, deprecated = true,
+ description = "This end point can return a lot of data, this "
+ + "identifies where in the request you are. This is an opaque"
+ + " value, and can be obtained from the 'next-page' value in "
+ + "the response. Deprecated, use " + PAGE + " instead."),
@OpenApiParam(name = PAGE_SIZE,
type = Integer.class,
description = "How many entries per page returned. Default 500."
@@ -311,7 +316,7 @@ private static void warnAboutNotSupported(@NotNull Context ctx, String[] warnAbo
@OpenApi(tags = {"Catalog"}, ignore = true)
@Override
public void update(Context ctx, @NotNull String entry) {
- ctx.status(HttpCode.NOT_IMPLEMENTED).json(CdaError.notImplemented());
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
}
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 89d858abe..f14a128ac 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
@@ -86,6 +86,11 @@ protected DSLContext getDslContext(Context ctx) {
+ "identifies where in the request you are. This is an opaque"
+ " value, and can be obtained from the 'next-page' value in "
+ "the response."),
+ @OpenApiParam(name = CURSOR, deprecated = true,
+ description = "This end point can return a lot of data, this "
+ + "identifies where in the request you are. This is an opaque"
+ + " value, and can be obtained from the 'next-page' value in "
+ + "the response. Deprecated, use " + PAGE + " instead."),
@OpenApiParam(name = PAGE_SIZE,
type = Integer.class,
description = "How many entries per page returned. Default "
@@ -152,6 +157,14 @@ public void getAll(@NotNull Context ctx) {
+ "When the accept header is set to " + Formats.JSONV2 + " the clob will be returned as a serialized Clob "
+ "object with fields for office-id, id, description and value. "
+ "For more information about accept header usage, see this page.",
+ pathParams = {
+ @OpenApiParam(name = CLOB_ID, description = "If the _query_ parameter is provided this _path_ parameter "
+ + "is ignored and the value of the query parameter is used. "
+ + "Note: the query parameter is necessary for id's that contain '/' or other special "
+ + "characters. This is due to limitations in path pattern matching. "
+ + "We will likely add support for encoding the ID in the path in the future. For now use the id field for those IDs. "
+ + "Client libraries should detect slashes and choose the appropriate field. \"ignored\" is suggested for the path endpoint."),
+ },
queryParams = {
@OpenApiParam(name = OFFICE, description = "Specifies the owning office."),
@OpenApiParam(name = CLOB_ID, description = "If this _query_ parameter is provided the id _path_ parameter "
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/Controllers.java b/cwms-data-api/src/main/java/cwms/cda/api/Controllers.java
index 3528a22e7..bd06fab4f 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/Controllers.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/Controllers.java
@@ -241,6 +241,7 @@ public final class Controllers {
private static final String DEPRECATED_CSV = "2024-11-01 CSV is not used often.";
public static final String QUERY = "query";
+ public static final String INCLUDE_ROLES = "include-roles";
static {
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/ForecastFileController.java b/cwms-data-api/src/main/java/cwms/cda/api/ForecastFileController.java
index d41274d87..607d59492 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/ForecastFileController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/ForecastFileController.java
@@ -95,7 +95,7 @@ private Timer.Context markAndTime(String subject) {
tags = {ForecastSpecController.TAG}
)
public void handle(@NotNull Context ctx) {
- String specId = requiredParam(ctx, NAME);
+ String specId = ctx.pathParam(NAME);
String office = requiredParam(ctx, OFFICE);
String designator = ctx.queryParamAsClass(DESIGNATOR, String.class).allowNullable().get();
String forecastDate = requiredParam(ctx, FORECAST_DATE);
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 0899db67d..e7ed5292e 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
@@ -33,22 +33,13 @@
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
-public final class ForecastInstanceController implements CrudHandler {
+public final class ForecastInstanceController extends BaseCrudHandler {
public static final String TAG = "Forecast";
- private final MetricRegistry metrics;
-
- private final Histogram requestResultSize;
private static final int KILO_BYTE_LIMIT = Integer.parseInt(System.getProperty("cda.api.forecast.file.max.length.kB", "64"));
public ForecastInstanceController(MetricRegistry metrics) {
- this.metrics = metrics;
- String className = this.getClass().getName();
- requestResultSize = this.metrics.histogram((name(className, RESULTS, SIZE)));
- }
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ super(metrics);
}
protected DSLContext getDslContext(Context ctx) {
@@ -172,7 +163,7 @@ public void getAll(@NotNull Context ctx) {
String result = Formats.format(contentType, instances, ForecastInstance.class);
ctx.result(result).contentType(contentType.toString());
- requestResultSize.update(result.length());
+ updateResultSize(result.length());
ctx.status(HttpServletResponse.SC_OK);
} catch (URISyntaxException e) {
@@ -242,7 +233,7 @@ public void getOne(@NotNull Context ctx, @NotNull String name) {
String result = Formats.format(contentType, instance);
ctx.result(result).contentType(contentType.toString());
- requestResultSize.update(result.length());
+ updateResultSize(result.length());
ctx.status(HttpServletResponse.SC_OK);
} catch (URISyntaxException e) {
@@ -271,6 +262,7 @@ public void getOne(@NotNull Context ctx, @NotNull String name) {
)
@Override
public void update(@NotNull Context ctx, @NotNull String name) {
+ logUnusedPathParameter(ctx, NAME, "Body contains information");
try (final Timer.Context ignored = markAndTime(UPDATE)) {
ForecastInstance forecastInstance = deserializeForecastInstance(ctx);
ForecastInstanceDao dao = new ForecastInstanceDao(getDslContext(ctx));
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 d991dab7b..a856bfa63 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,9 +1,5 @@
package cwms.cda.api;
-import static com.codahale.metrics.MetricRegistry.name;
-import static cwms.cda.api.Controllers.*;
-
-import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import cwms.cda.data.dao.DeleteRule;
@@ -12,7 +8,6 @@
import cwms.cda.data.dto.forecast.ForecastSpec;
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;
@@ -21,27 +16,18 @@
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 implements CrudHandler {
+public final class ForecastSpecController extends BaseCrudHandler {
public static final String TAG = "Forecast";
- private final MetricRegistry metrics;
-
- private final Histogram requestResultSize;
public ForecastSpecController(MetricRegistry metrics) {
- this.metrics = metrics;
- String className = this.getClass().getName();
- requestResultSize = this.metrics.histogram((name(className, RESULTS, SIZE)));
- }
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ super(metrics);
}
protected DSLContext getDslContext(Context ctx) {
@@ -173,7 +159,7 @@ public void getAll(@NotNull Context ctx) {
String result = Formats.format(contentType, specs, ForecastSpec.class);
ctx.result(result).contentType(contentType.toString());
- requestResultSize.update(result.length());
+ updateResultSize(result.length());
ctx.status(HttpServletResponse.SC_OK);
}
@@ -222,7 +208,7 @@ public void getOne(@NotNull Context ctx, @NotNull String name) {
String result = Formats.format(contentType, spec);
ctx.result(result).contentType(contentType.toString());
- requestResultSize.update(result.length());
+ updateResultSize(result.length());
ctx.status(HttpServletResponse.SC_OK);
}
@@ -247,6 +233,7 @@ public void getOne(@NotNull Context ctx, @NotNull String name) {
)
@Override
public void update(@NotNull Context ctx, @NotNull String name) {
+ logUnusedPathParameter(ctx, NAME, "Body contains information");
try (final Timer.Context ignored = markAndTime(UPDATE)) {
ForecastSpec forecastSpec = deserializeForecastSpec(ctx);
DSLContext dsl = getDslContext(ctx);
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/ForecastTimeseriesController.java b/cwms-data-api/src/main/java/cwms/cda/api/ForecastTimeseriesController.java
index ce604c26c..4aed7436b 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/ForecastTimeseriesController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/ForecastTimeseriesController.java
@@ -3,6 +3,7 @@
import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
+import cwms.cda.api.errors.CdaError;
import cwms.cda.data.dao.JooqDao;
import cwms.cda.data.dto.TimeSeries;
import cwms.cda.formatters.Formats;
@@ -13,6 +14,7 @@
import io.javalin.plugin.openapi.annotations.OpenApiContent;
import io.javalin.plugin.openapi.annotations.OpenApiParam;
import io.javalin.plugin.openapi.annotations.OpenApiRequestBody;
+import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
@@ -45,40 +47,10 @@ private Timer.Context markAndTime(String subject) {
return Controllers.markAndTime(metrics, getClass().getName(), subject);
}
- @OpenApi(
- description = "Used to create and save a forecast timeseries",
- requestBody = @OpenApiRequestBody(
- content = {
- @OpenApiContent(from = TimeSeries.class, type = Formats.JSONV2)
- },
- required = true
- ),
- queryParams = {
- @OpenApiParam(name = FORECAST_DATE, required = true, description = "Specifies the " +
- "forecast date time of the forecast instance to be associated with the created" +
- "forecast timeseries."),
- @OpenApiParam(name = ISSUE_DATE, required = true, description = "Specifies the " +
- "issue date time of the forecast instance to be associated with the created " +
- "forecast timeseries."),
- @OpenApiParam(name = OFFICE, required = true, description = "Specifies the " +
- "owning office of the forecast spec whose forecast instance will be " +
- "associated with the created forecast timeseries."),
- @OpenApiParam(name = NAME, required = true, description = "Specifies the " +
- "spec id of the forecast spec whose forecast instance will be " +
- "associated with the created forecast timeseries."),
- @OpenApiParam(name = LOCATION_ID, required = true, description = "Specifies the " +
- "location of the forecast spec whose forecast instance will be" +
- "associated with the created forecast timeseries."),
- @OpenApiParam(name = TIMESERIES_ID, required = true, description = "Id of timeseries " +
- "that will be created.")
- },
- method = HttpMethod.POST,
- path = "/forecast-timeseries",
- tags = TAG
- )
+ @OpenApi(ignore = true)
@Override
public void create(@NotNull Context ctx) {
-
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
protected DSLContext getDslContext(Context ctx) {
@@ -88,34 +60,25 @@ protected DSLContext getDslContext(Context ctx) {
@OpenApi(ignore = true)
@Override
public void delete(@NotNull Context ctx, @NotNull String forecastSpecId) {
- try (final Timer.Context ignored = markAndTime(GET_ONE)) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
- }
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void getAll(@NotNull Context ctx) {
- try (final Timer.Context ignored = markAndTime(GET_ONE)) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
- }
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void getOne(@NotNull Context ctx, @NotNull String id) {
- try (final Timer.Context ignored = markAndTime(GET_ONE)) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
- }
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void update(@NotNull Context ctx, @NotNull String id) {
- try (final Timer.Context ignored = markAndTime(GET_ONE)) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
- }
-
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
}
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 9927c069c..3b2537ae9 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
@@ -50,15 +50,10 @@
import static cwms.cda.api.Controllers.*;
import static cwms.cda.data.dao.JooqDao.getDslContext;
-public class LevelsAsTimeSeriesController implements Handler {
- private final MetricRegistry metrics;
+public class LevelsAsTimeSeriesController extends BaseHandler {
public LevelsAsTimeSeriesController(MetricRegistry metrics) {
- this.metrics = metrics;
- }
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ super(metrics);
}
@OpenApi(
@@ -113,7 +108,7 @@ private Timer.Context markAndTime(String subject) {
tags = LevelsController.TAG
)
public void handle(Context ctx) {
-
+ logUnusedPathParameter(ctx, LEVEL_ID, "Body contains required information");
try (final Timer.Context timeContext = markAndTime("getLevelAsTimeSeries")) {
DSLContext dsl = getDslContext(ctx);
Validator pathParam = ctx.pathParamAsClass(LEVEL_ID, String.class);
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 c1dfa0de3..5ca14bfa4 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
@@ -161,6 +161,9 @@ private LocationLevel deserializeLocationLevel(Context ctx) throws IOException {
@OpenApiParam(name = EFFECTIVE_DATE, description = "Specifies the "
+ "effective date of the level to be deleted. If not provided will "
+ "delete all data and reference to the location level."),
+ @OpenApiParam(name = DATE, deprecated = true, description = "Specifies "
+ + "the effective date of Location Level that will be deleted."
+ + " Deprecated, use " + EFFECTIVE_DATE + " instead"),
@OpenApiParam(name = TIMEZONE, description = "Specifies the time zone of "
+ "the value of the effective date field (unless otherwise "
+ "specified).If this field is not specified, the default time zone of UTC "
@@ -196,6 +199,9 @@ public void delete(@NotNull Context ctx, @NotNull String levelId) {
@OpenApiParam(name = LEVEL_ID_MASK, description = "Specifies the name(s) of "
+ "the location level(s) whose data is to be included in the response. "
+ "Uses * for all."),
+ @OpenApiParam(name = NAME, deprecated = true, description = "Specifies the name(s) of "
+ + "the location level(s) whose data is to be included in the response. "
+ + "Uses * for all. Deprecated, use " + LEVEL_ID_MASK + " instead"),
@OpenApiParam(name = OFFICE, description = "Specifies the owning "
+ "office of the location level(s) whose data is to be included in the"
+ " response. If this field is not specified, matching location level "
@@ -338,6 +344,9 @@ public void getAll(@NotNull Context ctx) {
@OpenApiParam(name = EFFECTIVE_DATE, required = true, description = "Specifies "
+ "the effective date of Location Level to be returned."
+ "Expected formats are `YYYY-MM-DDTHH:MM` or `YYYY-MM-DDTHH:MM:SS`"),
+ @OpenApiParam(name = DATE, deprecated = true, description = "Specifies "
+ + "the effective date of Location Level that will be returned."
+ + " Deprecated, use " + EFFECTIVE_DATE + " instead"),
@OpenApiParam(name = EFFECTIVE_DATE_EXACT, description = "If true"
+ " only a level with the exact provided date will be returned. If false"
+ " The most recent level on or before this time will be returned."
@@ -401,7 +410,10 @@ String.class, null, metrics, name(LevelsController.class.getName(),
},
queryParams = {
@OpenApiParam(name = EFFECTIVE_DATE, description = "Specifies "
- + "the effective date of Location Level that will be updated")
+ + "the effective date of Location Level that will be updated"),
+ @OpenApiParam(name = DATE, deprecated = true, description = "Specifies "
+ + "the effective date of Location Level that will be updated."
+ + " Deprecated, use " + EFFECTIVE_DATE + " instead")
},
requestBody = @OpenApiRequestBody(
content = {
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 791379f34..9bce96e1d 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
@@ -205,6 +205,9 @@ public void getAll(@NotNull Context ctx) {
}
@OpenApi(
+ pathParams = {
+ @OpenApiParam(name = LOCATION_ID, description = "The ID of the location to get")
+ },
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the "
+ "owning office of the location level(s) whose data is to be "
@@ -232,7 +235,7 @@ public void getAll(@NotNull Context ctx) {
tags = {"Locations"}
)
@Override
- public void getOne(@NotNull Context ctx, @NotNull String name) {
+ public void getOne(@NotNull Context ctx, @NotNull String locationId) {
try (final Timer.Context ignored = markAndTime(GET_ONE)) {
DSLContext dsl = getDslContext(ctx);
@@ -246,12 +249,12 @@ public void getOne(@NotNull Context ctx, @NotNull String name) {
ContentType contentType = Formats.parseHeader(formatHeader, Location.class);
ctx.contentType(contentType.toString());
LocationsDao locationDao = getLocationsDao(dsl);
- Location location = locationDao.getLocation(name, units, office, includeAliases);
+ Location location = locationDao.getLocation(locationId, units, office, includeAliases);
String serializedLocation = Formats.format(contentType, location);
ctx.result(serializedLocation);
addDeprecatedContentTypeWarning(ctx, contentType);
} catch (IOException ex) {
- String errorMsg = "Error retrieving " + name;
+ String errorMsg = "Error retrieving " + locationId;
CdaError re = new CdaError(errorMsg);
ctx.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).json(re);
logger.atSevere().withCause(ex).log("%s", errorMsg);
@@ -301,6 +304,9 @@ public void create(@NotNull Context ctx) {
}
@OpenApi(
+ pathParams = {
+ @OpenApiParam(name = LOCATION_ID, description = "The ID of the location to update")
+ },
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = Location.class, type = Formats.XML),
@@ -354,15 +360,16 @@ public void update(@NotNull Context ctx, @NotNull String locationId) {
}
@OpenApi(
+ pathParams = {
+ @OpenApiParam(name = LOCATION_ID, description = "The ID of the location to delete")
+ },
queryParams = {
@OpenApiParam(name = OFFICE, description = "Specifies the owning office of "
+ "the location whose data is to be deleted. If this field is not "
+ "specified, matching location information will be deleted from all "
+ "offices."),
- //Keeping hidden from the API docs for now as this call is particularly destructive
- //@OpenApiParam(name = CASCADE_DELETE, type = Boolean.class,
- //description = "Specifies whether to specifies whether to delete associated data " +
- //"for this location before deleting the location itself. Default: false")
+ @OpenApiParam(name = CASCADE_DELETE, type = Boolean.class, description = "Specifies whether to delete"
+ + " associated data for this location before deleting the location itself. Default: false")
},
description = "Delete CWMS Location",
method = HttpMethod.DELETE,
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 48c858a3f..31f2d5815 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
@@ -263,6 +263,10 @@ public void create(@NotNull Context ctx) {
@OpenApiContent(from = LocationGroup.class, type = Formats.JSON)
},
required = true),
+ pathParams = {
+ @OpenApiParam(name = GROUP_ID, required = true, description = "Specifies "
+ + "the location_group to be renamed.")
+ },
queryParams = {
@OpenApiParam(name = REPLACE_ASSIGNED_LOCS, type = Boolean.class, description = "Specifies whether to "
+ "unassign all existing locations before assigning new locations specified in the content body "
@@ -276,7 +280,7 @@ public void create(@NotNull Context ctx) {
tags = {TAG}
)
@Override
- public void update(@NotNull Context ctx, @NotNull String oldGroupId) {
+ public void update(@NotNull Context ctx, @NotNull String groupId) {
try (Timer.Context ignored = markAndTime(CREATE)) {
DSLContext dsl = getDslContext(ctx);
@@ -288,8 +292,8 @@ public void update(@NotNull Context ctx, @NotNull String oldGroupId) {
boolean replaceAssignedLocs = ctx.queryParamAsClass(REPLACE_ASSIGNED_LOCS,
Boolean.class).getOrDefault(false);
LocationGroupDao locationGroupDao = new LocationGroupDao(dsl);
- if (!office.equalsIgnoreCase(CWMS_OFFICE) && !oldGroupId.equals(deserialize.getId())) {
- locationGroupDao.renameLocationGroup(oldGroupId, deserialize);
+ if (!office.equalsIgnoreCase(CWMS_OFFICE) && !groupId.equals(deserialize.getId())) {
+ locationGroupDao.renameLocationGroup(groupId, deserialize);
}
if (replaceAssignedLocs) {
locationGroupDao.unassignAllLocs(deserialize, office);
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 f61bf96f3..2b5bc56a4 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
@@ -103,9 +103,8 @@ public void handle(@NotNull Context ctx) {
String kindRegexMask = ctx.queryParam(LOCATION_KIND_LIKE);
String office = ctx.queryParam(OFFICE);
- String formatParm = ctx.queryParamAsClass(Formats.JSONV1, String.class).getOrDefault("");
String formatHeader = ctx.header(Header.ACCEPT);
- ContentType contentType = Formats.parseHeaderAndQueryParm(formatHeader, formatParm, CwmsIdLocationKind.class);
+ ContentType contentType = Formats.parseHeader(formatHeader, CwmsIdLocationKind.class);
String results;
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 139039862..f6a5cc4f5 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
@@ -27,6 +27,7 @@
import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
+import cwms.cda.api.errors.CdaError;
import cwms.cda.data.dao.LookupTypeDao;
import cwms.cda.data.dto.LookupType;
import cwms.cda.data.dto.StatusResponse;
@@ -51,23 +52,12 @@
import static cwms.cda.api.Controllers.*;
import static cwms.cda.data.dao.JooqDao.getDslContext;
-public final class LookupTypeController implements CrudHandler {
+public final class LookupTypeController extends BaseCrudHandler {
static final String TAG = "LookupTypes";
- private final MetricRegistry metrics;
-
- private final Histogram requestResultSize;
-
public LookupTypeController(MetricRegistry metrics) {
- this.metrics = metrics;
- String className = this.getClass().getName();
-
- requestResultSize = this.metrics.histogram((name(className, RESULTS, SIZE)));
- }
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ super(metrics);
}
@OpenApi(
@@ -99,16 +89,14 @@ public void getAll(Context ctx) {
String serialized = Formats.format(contentType, lookupTypes, LookupType.class);
ctx.result(serialized);
ctx.status(HttpServletResponse.SC_OK);
- requestResultSize.update(serialized.length());
+ updateResultSize(serialized.length());
}
}
@OpenApi(ignore = true)
@Override
public void getOne(@NotNull Context context, @NotNull String s) {
- try (final Timer.Context ignored = markAndTime(GET_ONE)) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
- }
+ context.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
@@ -146,6 +134,9 @@ public void create(Context ctx) {
}
@OpenApi(
+ pathParams = {
+ @OpenApiParam(name = NAME, required = true, description = "Specifies the location type to update.")
+ },
queryParams = {
@OpenApiParam(name = CATEGORY, required = true, description = "Specifies the category id of the lookup type to be updated."),
@OpenApiParam(name = PREFIX, required = true, description = "Specifies the prefix of the lookup type to be updated."),
@@ -164,6 +155,7 @@ public void create(Context ctx) {
)
@Override
public void update(Context ctx, String name) {
+ logUnusedPathParameter(ctx, NAME, "Body has required information");
String category = requiredParam(ctx, CATEGORY);
String prefix = requiredParam(ctx, PREFIX);
try (Timer.Context ignored = markAndTime(UPDATE)) {
@@ -180,6 +172,9 @@ public void update(Context ctx, String name) {
}
@OpenApi(
+ pathParams = {
+ @OpenApiParam(name = NAME, required = true, description = "Specifies the location type to delete.")
+ },
queryParams = {
@OpenApiParam(name = CATEGORY, required = true, description = "Specifies the category id of the lookup type to be deleted."),
@OpenApiParam(name = PREFIX, required = true, description = "Specifies the prefix of the lookup type to be deleted."),
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 9c3cc445f..be7ea5b71 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
@@ -56,6 +56,7 @@
import static cwms.cda.api.Controllers.queryParamAsInstant;
import static cwms.cda.api.Controllers.requiredParam;
import cwms.cda.api.enums.UnitSystem;
+import cwms.cda.api.errors.CdaError;
import cwms.cda.data.dao.MeasurementDao;
import cwms.cda.data.dto.StatusResponse;
import cwms.cda.data.dto.measurement.Measurement;
@@ -165,10 +166,7 @@ public void getAll(@NotNull Context ctx) {
@OpenApi(ignore = true)
@Override
public void getOne(@NotNull Context ctx, @NotNull String locationId) {
- try (final Timer.Context ignored = markAndTime(GET_ONE)) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
- }
-
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
@@ -208,9 +206,7 @@ public void create(Context ctx) {
@OpenApi(ignore = true)
@Override
public void update(@NotNull Context ctx, @NotNull String locationId) {
- try (final Timer.Context ignored = markAndTime(GET_ONE)) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
- }
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
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 dcd9f0918..d2791de33 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
@@ -52,13 +52,13 @@ private Timer.Context markAndTime(String subject) {
@OpenApi(ignore = true)
@Override
public void create(Context ctx) {
- ctx.status(HttpServletResponse.SC_NOT_FOUND);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void delete(Context ctx, String id) {
- ctx.status(HttpServletResponse.SC_NOT_FOUND);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@@ -131,16 +131,13 @@ public void getAll(Context ctx) {
@OpenApi(ignore = true)
@Override
public void getOne(Context ctx, String id) {
- try (final Timer.Context timeContext = markAndTime(GET_ONE)) {
- ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
- }
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void update(Context ctx, String id) {
ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
-
}
}
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 5d7616031..2841cdc2b 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
@@ -83,6 +83,11 @@ private Timer.Context markAndTime(String subject) {
+ " in the request you are. This is an opaque value, and can be"
+ " obtained from the 'next-page' value in the response."
),
+ @OpenApiParam(name = CURSOR, deprecated = true,
+ description = "This end point can return a lot of data, this "
+ + "identifies where in the request you are. This is an opaque"
+ + " value, and can be obtained from the 'next-page' value in "
+ + "the response. Deprecated, use " + PAGE + " instead."),
@OpenApiParam(name = PAGE_SIZE,
type = Integer.class,
description =
@@ -226,18 +231,18 @@ public void getOne(@NotNull Context ctx, @NotNull String poolId) {
@OpenApi(ignore = true)
@Override
public void create(@NotNull Context ctx) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void update(@NotNull Context ctx, @NotNull String locationCode) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void delete(@NotNull Context ctx, @NotNull String locationCode) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
}
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 7a2459a1e..78707d30a 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
@@ -52,31 +52,18 @@
import static cwms.cda.api.Controllers.*;
import static cwms.cda.data.dao.JooqDao.getDslContext;
-public final class PropertyController implements CrudHandler {
+public final class PropertyController extends BaseCrudHandler {
static final String TAG = "Properties";
- private final MetricRegistry metrics;
-
- private final Histogram requestResultSize;
-
public PropertyController(MetricRegistry metrics) {
- this.metrics = metrics;
- String className = this.getClass().getName();
-
- requestResultSize = this.metrics.histogram((name(className, RESULTS, SIZE)));
- }
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ super(metrics);
}
@OpenApi(
- pathParams = {
- },
queryParams = {
@OpenApiParam(name = OFFICE_MASK, description = "Filters properties to the specified office mask"),
- @OpenApiParam(name = CATEGORY_ID, description = "Filters properties to the specified category mask"),
+ @OpenApiParam(name = CATEGORY_ID_MASK, description = "Filters properties to the specified category mask"),
@OpenApiParam(name = NAME_MASK, description = "Filters properties to the specified name mask"),
},
responses = {
@@ -105,7 +92,7 @@ public void getAll(Context ctx) {
String serialized = Formats.format(contentType, properties, Property.class);
ctx.result(serialized);
ctx.status(HttpServletResponse.SC_OK);
- requestResultSize.update(serialized.length());
+ updateResultSize(serialized.length());
}
}
@@ -149,7 +136,7 @@ public void getOne(Context ctx, String name) {
String serialized = Formats.format(contentType, property);
ctx.result(serialized);
ctx.status(HttpServletResponse.SC_OK);
- requestResultSize.update(serialized.length());
+ updateResultSize(serialized.length());
}
}
@@ -184,6 +171,10 @@ public void create(Context ctx) {
}
@OpenApi(
+ pathParams = {
+ @OpenApiParam(name = NAME, required = true, description = "Specifies the name of the property to be " +
+ "updated."),
+ },
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = Property.class, type = Formats.JSON)
@@ -198,6 +189,7 @@ public void create(Context ctx) {
)
@Override
public void update(Context ctx, String name) {
+ logUnusedPathParameter(ctx, NAME, "Body contains required information");
try (Timer.Context ignored = markAndTime(UPDATE)) {
String formatHeader = ctx.req.getContentType();
ContentType contentType = Formats.parseHeader(formatHeader, Property.class);
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 1686f6e63..550c9efda 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
@@ -122,8 +122,7 @@ public void getAll(Context ctx) {
@OpenApi(ignore = true)
@Override
public void getOne(Context ctx, String templateId) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET); //To change body of
- // generated methods, choose Tools | Specs.
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
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 79e06dadf..0038a39f7 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
@@ -26,6 +26,7 @@
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
+import cwms.cda.api.errors.CdaError;
import cwms.cda.data.dao.DeleteRule;
import cwms.cda.data.dao.JooqDao;
import cwms.cda.data.dao.texttimeseries.StandardTextDao;
@@ -76,7 +77,9 @@ private Timer.Context markAndTime(String subject) {
@OpenApiParam(name = OFFICE_MASK, description = "Specifies the office filter of the"
+ "standard text."),
@OpenApiParam(name = STANDARD_TEXT_ID_MASK, description = "Specifies the text id filter of the "
- + "standard text")
+ + "standard text"),
+ @OpenApiParam(name = NAME_MASK, deprecated = true, description = "Specifies the text id filter of the "
+ + "standard text. Deprecated, use " + STANDARD_TEXT_ID_MASK)
},
responses = {
@OpenApiResponse(status = STATUS_200,
@@ -94,10 +97,7 @@ public void getAll(Context ctx) {
if (officeMask == null) {
officeMask = "*";
}
- String idMask = ctx.queryParam(NAME_MASK);
- if (idMask == null) {
- idMask = "*";
- }
+ String idMask = queryParamAsClass(ctx, new String[]{STANDARD_TEXT_ID_MASK, NAME_MASK}, String.class, "*");
String formatHeader = ctx.header(Header.ACCEPT);
ContentType contentType = Formats.parseHeader(formatHeader, StandardTextCatalog.class);
DSLContext dsl = getDslContext(ctx);
@@ -182,7 +182,7 @@ public void create(@NotNull Context ctx) {
@OpenApi(ignore = true)
@Override
public void update(@NotNull Context ctx, @NotNull String oldTextTimeSeriesId) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
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 3e3f4813c..8c3f84ad9 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
@@ -71,21 +71,12 @@
import static cwms.cda.data.dao.JooqDao.getDslContext;
-public final class StreamLocationController implements CrudHandler {
+public final class StreamLocationController extends BaseCrudHandler {
static final String TAG = "StreamLocations";
- private final MetricRegistry metrics;
- private final Histogram requestResultSize;
-
public StreamLocationController(MetricRegistry metrics) {
- this.metrics = metrics;
- String className = this.getClass().getName();
- requestResultSize = this.metrics.histogram((name(className, RESULTS, SIZE)));
- }
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ super(metrics);
}
@OpenApi(
@@ -128,7 +119,7 @@ public void getAll(Context ctx) {
String serialized = Formats.format(contentType, streamLocations, StreamLocation.class);
ctx.result(serialized);
ctx.status(HttpServletResponse.SC_OK);
- requestResultSize.update(serialized.length());
+ updateResultSize(serialized.length());
}
}
@@ -174,7 +165,7 @@ public void getOne(@NotNull Context ctx, @NotNull String locationId) {
String serialized = Formats.format(contentType, streamLocation);
ctx.result(serialized);
ctx.status(HttpServletResponse.SC_OK);
- requestResultSize.update(serialized.length());
+ updateResultSize(serialized.length());
}
}
@@ -212,6 +203,10 @@ public void create(Context ctx) {
}
@OpenApi(
+ pathParams = {
+ @OpenApiParam(name = NAME, required = true, description = "Specifies the location-id of "
+ + "the stream location to be renamed."),
+ },
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = StreamLocation.class, type = Formats.JSONV1)
@@ -225,7 +220,8 @@ public void create(Context ctx) {
}
)
@Override
- public void update(Context ctx, @NotNull String locationId) {
+ public void update(Context ctx, @NotNull String name) {
+ logUnusedPathParameter(ctx, NAME, "Body contains required information");
try (Timer.Context ignored = markAndTime(METHOD + "update")) {
String formatHeader = ctx.req.getContentType();
ContentType contentType = Formats.parseHeader(formatHeader, StreamLocation.class);
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 4e557631e..43893dd3a 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
@@ -56,7 +56,7 @@
-public class TextTimeSeriesController implements CrudHandler {
+public class TextTimeSeriesController extends BaseCrudHandler {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
static final String TAG = "Text-TimeSeries";
@@ -65,10 +65,8 @@ public class TextTimeSeriesController implements CrudHandler {
public static final boolean DEFAULT_CREATE_REPLACE_ALL = false;
public static final boolean DEFAULT_UPDATE_REPLACE_ALL = true;
- private final MetricRegistry metrics;
-
public TextTimeSeriesController(MetricRegistry metrics) {
- this.metrics = metrics;
+ super(metrics);
}
@NotNull
@@ -76,12 +74,6 @@ protected TimeSeriesTextDao getDao(DSLContext dsl) {
return new TimeSeriesTextDao(dsl);
}
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
- }
-
-
@OpenApi(
summary = "Retrieve text time series values for a provided time window and date version."
+ "If individual values exceed 64 kilobytes, a URL to a separate download is provided "
@@ -95,6 +87,8 @@ private Timer.Context markAndTime(String subject) {
+ "the time zone of the values of the begin and end fields (unless "
+ "otherwise specified). If this field is not specified, "
+ "the default time zone of UTC shall be used."),
+ @OpenApiParam(name = VERSION_DATE, description = "Specifies the version date of the "
+ + "text timeseries. If not specified, the latest version will be used."),
@OpenApiParam(name = BEGIN, required = true, description = "The start of the time window"),
@OpenApiParam(name = END, required = true, description = "The end of the time window.")
},
@@ -162,7 +156,7 @@ public void getAll(@NotNull Context ctx) {
@OpenApi(ignore = true)
@Override
public void getOne(@NotNull Context ctx, @NotNull String templateId) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
@@ -217,7 +211,7 @@ public void create(@NotNull Context ctx) {
)
@Override
public void update(@NotNull Context ctx, @NotNull String oldTextTimeSeriesId) {
-
+ logUnusedPathParameter(ctx, NAME, "Body contains required information");
try (Timer.Context ignored = markAndTime(UPDATE)) {
boolean replaceAll = ctx.queryParamAsClass(REPLACE_ALL, Boolean.class)
.getOrDefault(DEFAULT_UPDATE_REPLACE_ALL);
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TextTimeSeriesValueController.java b/cwms-data-api/src/main/java/cwms/cda/api/TextTimeSeriesValueController.java
index 7702b4006..5203b105b 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/TextTimeSeriesValueController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/TextTimeSeriesValueController.java
@@ -43,18 +43,11 @@
import static cwms.cda.data.dao.JooqDao.getDslContext;
-public class TextTimeSeriesValueController implements Handler {
+public class TextTimeSeriesValueController extends BaseHandler {
public static final String TEXT_PLAIN = "text/plain";
- private final MetricRegistry metrics;
- private final Histogram requestResultSize;
public TextTimeSeriesValueController(MetricRegistry metrics) {
- this.metrics = metrics;
- requestResultSize = this.metrics.histogram((name(TextTimeSeriesValueController.class, RESULTS, SIZE)));
- }
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ super(metrics);
}
@OpenApi(
@@ -65,12 +58,6 @@ private Timer.Context markAndTime(String subject) {
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office of "
+ "the Text TimeSeries whose data is to be included in the response."),
- @OpenApiParam(name = TIMEZONE, description = "Specifies "
- + "the time zone of the values of the begin and end fields (unless "
- + "otherwise specified). If this field is not specified, "
- + "the default time zone of UTC shall be used."),
- @OpenApiParam(name = DATE, required = true, description = "The date of the text value to retrieve"),
- @OpenApiParam(name = VERSION_DATE, description = "The version date for the value to retrieve."),
@OpenApiParam(name = CLOB_ID, description = "Will be removed in a schema update. " +
"This is a placeholder for integration testing with schema 23.3.16", deprecated = true)
},
@@ -84,7 +71,8 @@ private Timer.Context markAndTime(String subject) {
)
public void handle(Context ctx) {
//Implementation will change with new CWMS schema
- //https://www.hec.usace.army.mil/confluence/display/CWMS/2024-02-29+Task2A+Text-ts+and+Binary-ts+Design
+ //https://www.hec.usace.army.mil/confluence/spaces/CWMS/pages/183110112/2024-02-29+Developer+Meeting+Task2A+Text-ts+and+Binary-ts+Design
+ logUnusedPathParameter(ctx, NAME, "Handled as " + CLOB_ID + " in query parameter. May change with schema.");
String textId = requiredParam(ctx, CLOB_ID);
String officeId = requiredParam(ctx, OFFICE);
try (Timer.Context ignored = markAndTime(GET_ALL)) {
@@ -92,7 +80,7 @@ public void handle(Context ctx) {
ClobDao clobDao = new ClobDao(dsl);
StreamConsumer consumer = (is, isPosition, mediaType, totalLength) -> {
- requestResultSize.update(totalLength);
+ updateResultSize(totalLength);
ctx.header(Header.ACCEPT_RANGES, "bytes");
RangeRequestUtil.seekableStream(ctx, is, isPosition, mediaType, totalLength);
};
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 e7f455ae7..4d73ac51b 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
@@ -193,7 +193,7 @@ public void create(Context ctx) {
@OpenApi(ignore = true)
@Override
public void update(@NotNull Context ctx, @NotNull String locationCode) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
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 45e463879..6a7841ff2 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
@@ -178,11 +178,6 @@ private Timer.Context markAndTime(String subject) {
required = true
),
queryParams = {
- @OpenApiParam(name = TIMEZONE, description = "Specifies "
- + "the time zone of the version-date field (unless "
- + "otherwise specified). If this field is not specified, the default time zone "
- + "of UTC shall be used.\r\nIgnored if version-date was specified with "
- + "offset and timezone."),
@OpenApiParam(name = CREATE_AS_LRTS, type = Boolean.class, description = "Flag indicating if "
+ "timeseries should be created as Local Regular Time Series. "
+ "'True' or 'False', default is 'False'"),
@@ -417,6 +412,11 @@ public void delete(@NotNull Context ctx, @NotNull String timeseries) {
+ "of data as a series of pages. This parameter is used to describes the "
+ "current location in the response stream. This is an opaque "
+ "value, and can be obtained from the 'next-page' value in the response."),
+ @OpenApiParam(name = CURSOR, deprecated = true,
+ description = "This end point can return a lot of data, this "
+ + "identifies where in the request you are. This is an opaque"
+ + " value, and can be obtained from the 'next-page' value in "
+ + "the response. Deprecated, use " + PAGE + " instead."),
@OpenApiParam(name = PAGE_SIZE,
type = Integer.class,
description = "How many entries per page returned. "
@@ -580,7 +580,7 @@ private void addLinkHeader(@NotNull Context ctx, TimeSeries ts, ContentType cont
public void getOne(@NotNull Context ctx, @NotNull String id) {
try (final Timer.Context ignored = markAndTime(GET_ONE)) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
}
@@ -597,11 +597,6 @@ public void getOne(@NotNull Context ctx, @NotNull String id) {
},
required = true),
queryParams = {
- @OpenApiParam(name = TIMEZONE, description = "Specifies "
- + "the time zone of the version-date field (unless "
- + "otherwise specified). If this field is not specified, the default time zone "
- + "of UTC shall be used.\r\nIgnored if version-date was specified with "
- + "offset and timezone."),
@OpenApiParam(name = CREATE_AS_LRTS, type = Boolean.class, description = ""),
@OpenApiParam(name = STORE_RULE, type = StoreRule.class, description = STORE_RULE_DESC),
@OpenApiParam(name = OVERRIDE_PROTECTION, type = Boolean.class, description =
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 48d339ca8..da8f26eef 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
@@ -141,6 +141,11 @@ private TimeSeriesDao getTimeSeriesDao(DSLContext dsl) {
+ "of data as a series of pages. This parameter is used to describes the "
+ "current location in the response stream. This is an opaque "
+ "value, and can be obtained from the 'next-page' value in the response."),
+ @OpenApiParam(name = CURSOR, deprecated = true,
+ description = "This end point can return a lot of data, this "
+ + "identifies where in the request you are. This is an opaque"
+ + " value, and can be obtained from the 'next-page' value in "
+ + "the response. Deprecated, use " + PAGE + " instead."),
@OpenApiParam(name = PAGE_SIZE,
type = Integer.class,
description = "How many entries per page returned. "
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 9152953f6..708629088 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
@@ -97,6 +97,8 @@ private Timer.Context markAndTime(String subject) {
@OpenApiParam(name = OFFICE, description = "Specifies the owning office of the "
+ "timeseries assigned to the group(s) whose data is to be included in the response. If this "
+ "field is not specified, group information for all assigned TS offices shall be returned."),
+ @OpenApiParam(name = GROUP_OFFICE_ID, description = "Specifies the owning office of the "
+ + "timeseries group", required = true),
@OpenApiParam(name = INCLUDE_ASSIGNED, type = Boolean.class, description = "Include"
+ " the assigned timeseries in the returned timeseries groups. (default: true)"),
@OpenApiParam(name = TIMESERIES_CATEGORY_LIKE, description = "Posix regular expression "
@@ -276,6 +278,10 @@ public void create(@NotNull Context ctx) {
@OpenApiContent(from = TimeSeriesGroup.class, type = Formats.JSON)
},
required = true),
+ pathParams = {
+ @OpenApiParam(name = GROUP_ID, required = true, description = "Specifies "
+ + "the original timeseries group to rename.")
+ },
queryParams = {
@OpenApiParam(name = REPLACE_ASSIGNED_TS, type = Boolean.class, description = "Specifies whether to "
+ "unassign all existing time series before assigning new time series specified in the content body "
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 bdbdecc42..44cf6d9ff 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
@@ -17,6 +17,7 @@
import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
+import cwms.cda.api.errors.CdaError;
import cwms.cda.data.dao.TimeZoneDao;
import cwms.cda.data.dto.TimeZoneId;
import cwms.cda.data.dto.TimeZoneIds;
@@ -54,13 +55,13 @@ private Timer.Context markAndTime(String subject) {
@OpenApi(ignore = true)
@Override
public void create(Context ctx) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void delete(Context ctx, String id) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
@@ -130,15 +131,13 @@ public void getAll(Context ctx) {
@OpenApi(ignore = true)
@Override
public void getOne(Context ctx, String id) {
- try (Timer.Context timeContext = markAndTime(GET_ONE)) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
- }
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void update(Context ctx, String id) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
}
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesDeleteController.java b/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesDeleteController.java
index 6fd640da3..597a0ad4f 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesDeleteController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesDeleteController.java
@@ -25,25 +25,8 @@
package cwms.cda.api;
import static com.codahale.metrics.MetricRegistry.name;
-import static cwms.cda.api.Controllers.BEGIN;
-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.GET_ALL;
-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_SIZE;
-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.START_TIME_INCLUSIVE;
-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.UNIT_SYSTEM;
-import static cwms.cda.api.Controllers.requiredInstant;
-import static cwms.cda.api.Controllers.requiredParam;
+import static cwms.cda.api.Controllers.*;
+import static cwms.cda.api.Controllers.SINCE;
import static cwms.cda.data.dao.JooqDao.getDslContext;
import com.codahale.metrics.Histogram;
@@ -96,6 +79,11 @@ private Timer.Context markAndTime(String subject) {
"turbine changes to be deleted."),
},
queryParams = {
+ @OpenApiParam(name = TIMEZONE, description = "Specifies "
+ + "the time zone of the values of " + BEGIN + ", " + END + " fields (unless "
+ + "otherwise specified). If this field is not specified, the default time zone "
+ + "of UTC shall be used.\r\nIgnored if " + BEGIN + " was specified with "
+ + "offset and timezone."),
@OpenApiParam(name = BEGIN, required = true, description = "The start of the time window"),
@OpenApiParam(name = END, required = true, description = "The end of the time window."),
@OpenApiParam(name = OVERRIDE_PROTECTION, type = Boolean.class, description = "A flag "
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 d9d5a9837..e8d3b936d 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,26 +25,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.DELETE;
-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.OVERRIDE_PROTECTION;
-import static cwms.cda.api.Controllers.PAGE_SIZE;
-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.START_TIME_INCLUSIVE;
-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.UNIT_SYSTEM;
-import static cwms.cda.api.Controllers.requiredInstant;
-import static cwms.cda.api.Controllers.requiredParam;
+import static cwms.cda.api.Controllers.*;
import static cwms.cda.data.dao.JooqDao.getDslContext;
import com.codahale.metrics.Histogram;
@@ -100,6 +81,11 @@ private Timer.Context markAndTime(String subject) {
"Turbine changes whose data is to be included in the response."),
},
queryParams = {
+ @OpenApiParam(name = TIMEZONE, description = "Specifies "
+ + "the time zone of the values of " + BEGIN + ", " + END + " fields (unless "
+ + "otherwise specified). If this field is not specified, the default time zone "
+ + "of UTC shall be used.\r\nIgnored if " + BEGIN + " was specified with "
+ + "offset and timezone."),
@OpenApiParam(name = BEGIN, required = true, description = "The start of the time window"),
@OpenApiParam(name = END, required = true, description = "The end of the time window."),
@OpenApiParam(name = START_TIME_INCLUSIVE, type = Boolean.class, description = "A flag "
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesPostController.java b/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesPostController.java
index dda5a6dd0..533f93044 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesPostController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/TurbineChangesPostController.java
@@ -75,16 +75,11 @@
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
-public final class TurbineChangesPostController implements Handler {
- private final MetricRegistry metrics;
+public final class TurbineChangesPostController extends BaseHandler {
public TurbineChangesPostController(MetricRegistry metrics) {
- this.metrics = metrics;
- }
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ super(metrics);
}
@OpenApi(
@@ -115,6 +110,9 @@ private Timer.Context markAndTime(String subject) {
)
@Override
public void handle(@NotNull Context ctx) throws Exception {
+ logUnusedPathParameter(ctx, NAME, "Body contains required information.");
+ logUnusedPathParameter(ctx, OFFICE, "Body contains required information.");
+
try (Timer.Context ignored = markAndTime(CREATE)) {
String formatHeader = ctx.req.getContentType();
ContentType contentType = Formats.parseHeader(formatHeader, TurbineChange.class);
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/auth/ApiKeyController.java b/cwms-data-api/src/main/java/cwms/cda/api/auth/ApiKeyController.java
index 279c0843a..59329d573 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/auth/ApiKeyController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/auth/ApiKeyController.java
@@ -46,6 +46,7 @@
import io.javalin.plugin.openapi.annotations.OpenApiSecurity;
import java.util.List;
+import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
@@ -97,6 +98,10 @@ public void create(Context ctx) {
}
@OpenApi(
+ pathParams = {
+ @OpenApiParam(name = "key-name", required = true,
+ description = "Name of the specific key to get more information for. NOTE: Case-sensitive.")
+ },
responses = @OpenApiResponse(
content = {
@OpenApiContent(from = ApiKey.class, type = Formats.JSON)
@@ -180,7 +185,7 @@ public void getOne(Context ctx, @NotNull String keyName) {
)
@Override
public void update(@NotNull Context ctx, @NotNull String arg1) {
- throw new UnsupportedOperationException("Update is not implemented. Delete and create a new key.");
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
}
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 e23602162..aa08a202e 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,21 +1,12 @@
package cwms.cda.api.auth.users;
import static com.codahale.metrics.MetricRegistry.name;
-import static cwms.cda.api.Controllers.CURSOR;
-import static cwms.cda.api.Controllers.GET_ALL;
-import static cwms.cda.api.Controllers.INCLUDE_VALUES;
-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.STATUS_201;
-import static cwms.cda.api.Controllers.STATUS_204;
-import static cwms.cda.api.Controllers.markAndTime;
-import static cwms.cda.api.Controllers.queryParamAsClass;
+import static cwms.cda.api.Controllers.*;
import static cwms.cda.data.dao.JooqDao.getDslContext;
import java.util.List;
+import javax.servlet.http.HttpServletResponse;
import org.jooq.DSLContext;
import com.codahale.metrics.MetricRegistry;
@@ -63,14 +54,13 @@ private Timer.Context markAndTime(String subject) {
@OpenApi(ignore = true)
@Override
public void create(Context ctx) {
- throw new UnsupportedOperationException("Unimplemented method 'create'");
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void delete(Context ctx, String username) {
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Unimplemented method 'delete'");
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@@ -84,10 +74,19 @@ public void delete(Context ctx, String username) {
+ "identifies where in the request you are. This is an opaque"
+ " value, and can be obtained from the 'next-page' value in "
+ "the response."),
+ @OpenApiParam(name = CURSOR, deprecated = true,
+ description = "This end point can return a lot of data, this "
+ + "identifies where in the request you are. This is an opaque"
+ + " value, and can be obtained from the 'next-page' value in "
+ + "the response. Deprecated, use " + PAGE + " instead."),
@OpenApiParam(name = PAGE_SIZE,
type = Integer.class,
description = "How many entries per page returned. Default "
- + DEFAULT_PAGE_SIZE + ".")
+ + DEFAULT_PAGE_SIZE + "."),
+ @OpenApiParam(name = INCLUDE_ROLES,
+ type = Boolean.class,
+ allowEmptyValue = true,
+ description = "Include roles in the response. Default false.")
},
responses = @OpenApiResponse(
content = {
@@ -122,7 +121,7 @@ public void getAll(Context ctx) {
int pageSize = queryParamAsClass(ctx, new String[]{PAGE_SIZE}, Integer.class, DEFAULT_PAGE_SIZE, metrics,
name(UsersController.class.getName(), GET_ALL));
- boolean includeRoles = queryParamAsClass(ctx, new String[]{"include-roles"},
+ boolean includeRoles = queryParamAsClass(ctx, new String[]{INCLUDE_ROLES},
Boolean.class, false, metrics,
name(UsersController.class.getName(), GET_ALL));
UserDao dao = new UserDao(dsl);
@@ -170,9 +169,6 @@ public void getOne(Context ctx, String userName) {
)
@Override
public void update(Context ctx, String arg1) {
- throw new UnsupportedOperationException("Unimplemented method 'update'");
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
-
-
-
}
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/location/kind/GateChangeDeleteController.java b/cwms-data-api/src/main/java/cwms/cda/api/location/kind/GateChangeDeleteController.java
index 0d27aee91..9fbf1bf82 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/location/kind/GateChangeDeleteController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/location/kind/GateChangeDeleteController.java
@@ -53,6 +53,10 @@ public GateChangeDeleteController(MetricRegistry metrics) {
"Gate Changes whose data is to be included in the response."),
},
queryParams = {
+ @OpenApiParam(name = TIMEZONE, description = "This field specifies a default "
+ + "timezone to be used if the format of the "
+ + BEGIN + " and " + END + " parameters do not include "
+ + "offset or time zone information. Defaults to UTC."),
@OpenApiParam(name = BEGIN, required = true, description = "The start of the time window"),
@OpenApiParam(name = END, required = true, description = "The end of the time window."),
@OpenApiParam(name = OVERRIDE_PROTECTION, type = Boolean.class, description = "A flag "
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 c8226be94..e3761f8f6 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
@@ -59,6 +59,10 @@ public GateChangeGetAllController(MetricRegistry metrics) {
"Gate Changes whose data is to be included in the response."),
},
queryParams = {
+ @OpenApiParam(name = TIMEZONE, description = "This field specifies a default "
+ + "timezone to be used if the format of the "
+ + BEGIN + " and " + END + " parameters do not include "
+ + "offset or time zone information. Defaults to UTC."),
@OpenApiParam(name = BEGIN, required = true, description = "The start of the time window"),
@OpenApiParam(name = END, required = true, description = "The end of the time window."),
@OpenApiParam(name = START_TIME_INCLUSIVE, type = Boolean.class, description = "A flag "
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockRevoke.java b/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockRevoke.java
index 43f6eeb16..ef13e4548 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockRevoke.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectLockRevoke.java
@@ -66,6 +66,7 @@ public ProjectLockRevoke(MetricRegistry metrics) {
queryParams = {
@OpenApiParam(name = OFFICE, required = true,
description = "Specifies the office of the lock."),
+ @OpenApiParam(name = APPLICATION_ID, required = true, description = "Specifies the application id."),
@OpenApiParam(name = REVOKE_TIMEOUT, type = Integer.class,
description = "time in seconds to wait for existing lock to be revoked. Default: 10")
},
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectPublishStatusUpdate.java b/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectPublishStatusUpdate.java
index 77ebc7eed..1f94272a7 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectPublishStatusUpdate.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/project/ProjectPublishStatusUpdate.java
@@ -24,23 +24,13 @@
package cwms.cda.api.project;
-import static cwms.cda.api.Controllers.APPLICATION_ID;
-import static cwms.cda.api.Controllers.BEGIN;
-import static cwms.cda.api.Controllers.END;
-import static cwms.cda.api.Controllers.NAME;
-import static cwms.cda.api.Controllers.OFFICE;
-import static cwms.cda.api.Controllers.SOURCE_ID;
-import static cwms.cda.api.Controllers.STATUS_200;
-import static cwms.cda.api.Controllers.TIMESERIES_ID;
-import static cwms.cda.api.Controllers.queryParamAsInstant;
-import static cwms.cda.api.Controllers.requiredParam;
-
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import cwms.cda.api.Controllers;
import cwms.cda.api.ProjectController;
import cwms.cda.data.dao.JooqDao;
import cwms.cda.data.dao.project.ProjectDao;
+import cwms.cda.formatters.Formats;
import io.javalin.http.Context;
import io.javalin.http.Handler;
import io.javalin.plugin.openapi.annotations.HttpMethod;
@@ -50,6 +40,7 @@
import java.time.Instant;
import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
+import static cwms.cda.api.Controllers.*;
public class ProjectPublishStatusUpdate implements Handler {
@@ -80,6 +71,13 @@ public ProjectPublishStatusUpdate(MetricRegistry metrics) {
@OpenApiParam(name = TIMESERIES_ID, description = "A time series identifier of "
+ "the time series associated with the update. If NULL or not "
+ "specified, the generated message will not include this item."),
+ @OpenApiParam(name = TIMEZONE, description = "Specifies "
+ + "the time zone of the values of the begin and end fields (unless "
+ + "otherwise specified). For other formats this parameter "
+ + "affects the time zone of times in the "
+ + "response. If this field is not specified, the default time zone "
+ + "of UTC shall be used.\r\nIgnored if begin was specified with "
+ + "offset and timezone."),
@OpenApiParam(name = BEGIN, description = "The start time of the updates to "
+ "the time series. If NULL or not specified, the generated message "
+ "will not include this item."),
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 24dd660c5..78d8ed7dd 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
@@ -57,6 +57,7 @@
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 cwms.cda.api.errors.CdaError;
@@ -101,23 +102,17 @@
-public class RatingController implements CrudHandler {
+public class RatingController extends BaseCrudHandler {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
static final String TAG = "Ratings";
- private final MetricRegistry metrics;
-
- private final Histogram requestResultSize;
-
static {
JavalinValidation.register(RatingSet.DatabaseLoadMethod.class,
RatingController::getDatabaseLoadMethod);
}
public RatingController(MetricRegistry metrics) {
- this.metrics = metrics;
- String className = this.getClass().getName();
- requestResultSize = this.metrics.histogram((name(className, RESULTS, SIZE)));
+ super(metrics);
}
private static RatingSet.DatabaseLoadMethod getDatabaseLoadMethod(String input) {
@@ -185,10 +180,6 @@ public void create(@NotNull Context ctx) {
}
}
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
- }
-
private String deserializeRatingSet(Context ctx, boolean storeTemplate) throws IOException, RatingException {
String formatHeader = ctx.req.getContentType();
//Using placeholder CwmsDTOBase.class since we do not have a RatingSet DTO
@@ -360,7 +351,7 @@ public void getAll(@NotNull Context ctx) {
ctx.status(HttpServletResponse.SC_OK);
ctx.result(results);
addDeprecatedContentTypeWarning(ctx, contentType);
- requestResultSize.update(results.length());
+ updateResultSize(results.length());
}
}
@@ -566,7 +557,7 @@ private RatingSet getRatingSet(Context ctx, RatingSet.DatabaseLoadMethod method,
},
method = HttpMethod.PATCH, path = "/ratings", tags = {TAG})
public void update(@NotNull Context ctx, @NotNull String ratingId) {
-
+ logUnusedPathParameter(ctx, RATING_ID, "Body contains required information");
try (final Timer.Context ignored = markAndTime(UPDATE)) {
DSLContext dsl = getDslContext(ctx);
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 eba0d857a..ce95a2f17 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
@@ -179,8 +179,7 @@ public void getAll(Context ctx) {
@OpenApi(ignore = true)
@Override
public void getOne(Context ctx, String ratingId) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET); //To change body of
- // generated methods, choose Tools | Specs.
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@NotNull
@@ -192,22 +191,19 @@ protected RatingMetadataDao getDao(DSLContext dsl) {
@OpenApi(ignore = true)
@Override
public void create(Context ctx) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET); //To change body of
- // generated methods, choose Tools | Specs.
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void update(Context ctx, String locationCode) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET); //To change body of
- // generated methods, choose Tools | Specs.
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(ignore = true)
@Override
public void delete(Context ctx, String locationCode) {
- throw new UnsupportedOperationException(NOT_SUPPORTED_YET); //To change body of
- // generated methods, choose Tools | Specs.
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
}
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 4b5477a6f..c963ad079 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
@@ -257,8 +257,7 @@ private static String translateJsonToXml(String body) {
@OpenApi(ignore = true)
@Override
public void update(Context ctx, String locationCode) {
- throw new UnsupportedOperationException("Not supported yet."); //To change body of
- // generated methods, choose Tools | Specs.
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
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 d0cf75b7e..5b5a1e49a 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
@@ -258,8 +258,7 @@ private static String translateJsonToXml(String body) {
@OpenApi(ignore = true)
@Override
public void update(Context ctx, String locationCode) {
- throw new UnsupportedOperationException("Not supported yet."); //To change body of
- // generated methods, choose Tools | Templates.
+ ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
}
@OpenApi(
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 43d5b8f65..e33e4e052 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,18 +24,7 @@
package cwms.cda.api.rss;
-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_400;
-import static cwms.cda.api.Controllers.STATUS_404;
-import static cwms.cda.api.Controllers.queryParamAsClass;
-import static cwms.cda.api.Controllers.queryParamAsInstant;
+import static cwms.cda.api.Controllers.*;
import static cwms.cda.data.dao.JooqDao.getDslContext;
import com.codahale.metrics.MetricRegistry;
@@ -81,13 +70,23 @@ public RssHandler(MetricRegistry metrics) {
"eg TS_STORED, STATUS, REALTIME_OPS")
},
queryParams = {
+ @OpenApiParam(name = TIMEZONE, description = "Specifies "
+ + "the time zone of the values of " + SINCE + " fields (unless "
+ + "otherwise specified). If this field is not specified, the default time zone "
+ + "of UTC shall be used.\r\nIgnored if " + SINCE + " was specified with "
+ + "offset and timezone."),
@OpenApiParam(name = SINCE, description = "The start the feed time window. " +
"The endpoint will not retrieve more than the last week of messages."),
@OpenApiParam(name = PAGE_SIZE, type = Integer.class, description = "The number of feed items to include."),
@OpenApiParam(name = PAGE, description = "This end point can return a lot of data, this "
+ "identifies where in the request you are. This is an opaque"
+ " value, and can be obtained from the 'next-page' value in "
- + "the response.")
+ + "the response."),
+ @OpenApiParam(name = CURSOR, deprecated = true,
+ description = "This end point can return a lot of data, this "
+ + "identifies where in the request you are. This is an opaque"
+ + " value, and can be obtained from the 'next-page' value in "
+ + "the response. Deprecated, use " + PAGE + " instead."),
},
responses = {
@OpenApiResponse(status = STATUS_200, content = {
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceCreateController.java b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceCreateController.java
index b85da41c0..ccdeb5528 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceCreateController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/timeseriesprofile/TimeSeriesProfileInstanceCreateController.java
@@ -26,14 +26,7 @@
package cwms.cda.api.timeseriesprofile;
-import static cwms.cda.api.Controllers.CREATE;
-import static cwms.cda.api.Controllers.METHOD;
-import static cwms.cda.api.Controllers.OVERRIDE_PROTECTION;
-import static cwms.cda.api.Controllers.PROFILE_DATA;
-import static cwms.cda.api.Controllers.VERSION;
-import static cwms.cda.api.Controllers.VERSION_DATE;
-import static cwms.cda.api.Controllers.requiredInstant;
-import static cwms.cda.api.Controllers.requiredParam;
+import static cwms.cda.api.Controllers.*;
import static cwms.cda.data.dao.JooqDao.getDslContext;
import com.codahale.metrics.MetricRegistry;
@@ -67,6 +60,11 @@ public TimeSeriesProfileInstanceCreateController(MetricRegistry metrics) {
+ " time series profile instance. Default is REPLACE_ALL"),
@OpenApiParam(name = OVERRIDE_PROTECTION, type = Boolean.class, description = "Override protection"
+ " for the time series profile instance. Default is false"),
+ @OpenApiParam(name = TIMEZONE, description = "Specifies "
+ + "the time zone of the values of " + VERSION_DATE + " fields (unless "
+ + "otherwise specified). If this field is not specified, the default time zone "
+ + "of UTC shall be used.\r\nIgnored if " + VERSION_DATE + " was specified with "
+ + "offset and timezone."),
@OpenApiParam(name = VERSION_DATE, type = Instant.class, description = "The version date of the"
+ " time series profile instance. Accepts ISO8601 format.", required = true),
@OpenApiParam(name = PROFILE_DATA, required = true, description = "The profile data of the"
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/AccountingCreateController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/AccountingCreateController.java
index 1fd980b8e..6f929a2d9 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/AccountingCreateController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/AccountingCreateController.java
@@ -36,6 +36,7 @@
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
+import cwms.cda.api.BaseHandler;
import cwms.cda.api.Controllers;
import cwms.cda.data.dao.LookupTypeDao;
import cwms.cda.data.dao.watersupply.WaterSupplyAccountingDao;
@@ -64,16 +65,11 @@
import org.jooq.DSLContext;
-public class AccountingCreateController implements Handler {
+public class AccountingCreateController extends BaseHandler {
private static final String TAG = "Pump Accounting";
- private final MetricRegistry metrics;
-
- private Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
- }
public AccountingCreateController(MetricRegistry metrics) {
- this.metrics = metrics;
+ super(metrics);
}
@NotNull
@@ -107,6 +103,8 @@ protected WaterSupplyAccountingDao getWaterSupplyAccountingDao(DSLContext dsl) {
@Override
public void handle(@NotNull Context ctx) {
+ logUnusedPathParameter(ctx, WATER_USER, "Body contains required information.");
+
try (Timer.Context ignored = markAndTime(CREATE)) {
final String contractId = ctx.pathParam(CONTRACT_NAME);
final String office = ctx.pathParam(OFFICE);
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 8e31f1dbf..26a1d0e68 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
@@ -54,10 +54,10 @@
import org.jooq.DSLContext;
-public final class WaterContractCatalogController extends WaterSupplyControllerBase implements Handler {
+public final class WaterContractCatalogController extends WaterSupplyControllerBase {
public WaterContractCatalogController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
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 9b208dc28..43263274a 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
@@ -56,10 +56,10 @@
import org.jooq.DSLContext;
-public final class WaterContractController extends WaterSupplyControllerBase implements Handler {
+public final class WaterContractController extends WaterSupplyControllerBase {
public WaterContractController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractCreateController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractCreateController.java
index 1748d2ed6..304511f30 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractCreateController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractCreateController.java
@@ -56,10 +56,10 @@
import org.jooq.DSLContext;
-public final class WaterContractCreateController extends WaterSupplyControllerBase implements Handler {
+public final class WaterContractCreateController extends WaterSupplyControllerBase {
public WaterContractCreateController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
@@ -94,6 +94,8 @@ public WaterContractCreateController(MetricRegistry metrics) {
@Override
public void handle(@NotNull Context ctx) {
+ logUnusedPathParameter(ctx, PROJECT_ID, "Body contains required information.");
+ logUnusedPathParameter(ctx, OFFICE, "Body contains required information.");
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/watersupply/WaterContractDeleteController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractDeleteController.java
index 409a39aa0..0b0b8304c 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractDeleteController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractDeleteController.java
@@ -52,9 +52,9 @@
import org.jooq.DSLContext;
-public final class WaterContractDeleteController extends WaterSupplyControllerBase implements Handler {
+public final class WaterContractDeleteController extends WaterSupplyControllerBase {
public WaterContractDeleteController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
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 7a2ffa4e1..ec92d906c 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
@@ -52,10 +52,10 @@
import org.jooq.DSLContext;
-public final class WaterContractTypeCatalogController extends WaterSupplyControllerBase implements Handler {
+public final class WaterContractTypeCatalogController extends WaterSupplyControllerBase {
public WaterContractTypeCatalogController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeCreateController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeCreateController.java
index 3e8bc44df..003375014 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeCreateController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeCreateController.java
@@ -50,10 +50,10 @@
import org.jooq.DSLContext;
-public final class WaterContractTypeCreateController extends WaterSupplyControllerBase implements Handler {
+public final class WaterContractTypeCreateController extends WaterSupplyControllerBase {
public WaterContractTypeCreateController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeDeleteController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeDeleteController.java
index 7a7849655..1ccf26aa4 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeDeleteController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractTypeDeleteController.java
@@ -47,12 +47,12 @@
import org.jooq.DSLContext;
-public final class WaterContractTypeDeleteController extends WaterSupplyControllerBase implements Handler {
+public final class WaterContractTypeDeleteController extends WaterSupplyControllerBase {
private static final String DISPLAY_VALUE = "display-value";
public WaterContractTypeDeleteController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractUpdateController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractUpdateController.java
index ca6e6140d..d7faded49 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractUpdateController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterContractUpdateController.java
@@ -56,10 +56,10 @@
import org.jooq.DSLContext;
-public final class WaterContractUpdateController extends WaterSupplyControllerBase implements Handler {
+public final class WaterContractUpdateController extends WaterSupplyControllerBase {
public WaterContractUpdateController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
@@ -96,6 +96,10 @@ public WaterContractUpdateController(MetricRegistry metrics) {
@Override
public void handle(@NotNull Context ctx) {
+ logUnusedPathParameter(ctx, PROJECT_ID, "Body contains required information.");
+ logUnusedPathParameter(ctx, OFFICE, "Body contains required information.");
+ logUnusedPathParameter(ctx, WATER_USER, "Body contains required information.");
+
try (Timer.Context ignored = markAndTime(UPDATE)) {
DSLContext dsl = getDslContext(ctx);
String contractName = ctx.pathParam(CONTRACT_NAME);
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterPumpDisassociateController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterPumpDisassociateController.java
index 5c3de2922..1c1dffc2f 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterPumpDisassociateController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterPumpDisassociateController.java
@@ -52,12 +52,12 @@
import org.jooq.DSLContext;
-public final class WaterPumpDisassociateController extends WaterSupplyControllerBase implements Handler {
+public final class WaterPumpDisassociateController extends WaterSupplyControllerBase {
private static final String PUMP_TYPE = "pump-type";
private static final String DELETE_ACCOUNTING = "delete-accounting";
public WaterPumpDisassociateController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
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 7ff2d8aad..1e521d4a4 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
@@ -28,23 +28,19 @@
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
+import cwms.cda.api.BaseHandler;
import cwms.cda.api.Controllers;
import cwms.cda.data.dao.watersupply.WaterContractDao;
import org.jooq.DSLContext;
-public class WaterSupplyControllerBase {
+public abstract class WaterSupplyControllerBase extends BaseHandler {
static final String TAG = "Water Contracts";
- private MetricRegistry metrics;
- WaterContractDao getContractDao(DSLContext dsl) {
- return new WaterContractDao(dsl);
- }
-
- Timer.Context markAndTime(String subject) {
- return Controllers.markAndTime(metrics, getClass().getName(), subject);
+ public WaterSupplyControllerBase(MetricRegistry metrics) {
+ super(metrics);
}
- void waterMetrics(MetricRegistry metrics) {
- this.metrics = metrics;
+ WaterContractDao getContractDao(DSLContext dsl) {
+ return new WaterContractDao(dsl);
}
}
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 758ca2f00..253564b11 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
@@ -56,10 +56,10 @@
import org.jooq.DSLContext;
-public final class WaterUserCatalogController extends WaterSupplyControllerBase implements Handler {
+public final class WaterUserCatalogController extends WaterSupplyControllerBase {
public WaterUserCatalogController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
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 90886a3ca..d0de71695 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
@@ -56,10 +56,10 @@
import org.jooq.DSLContext;
-public final class WaterUserController extends WaterSupplyControllerBase implements Handler {
+public final class WaterUserController extends WaterSupplyControllerBase {
public WaterUserController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCreateController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCreateController.java
index 4516a7ada..ff6e36fde 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCreateController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserCreateController.java
@@ -49,10 +49,10 @@
import org.jooq.DSLContext;
-public final class WaterUserCreateController extends WaterSupplyControllerBase implements Handler {
+public final class WaterUserCreateController extends WaterSupplyControllerBase {
public WaterUserCreateController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserDeleteController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserDeleteController.java
index 2fece833e..aaacb4633 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserDeleteController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserDeleteController.java
@@ -50,11 +50,11 @@
import org.jooq.DSLContext;
-public final class WaterUserDeleteController extends WaterSupplyControllerBase implements Handler {
+public final class WaterUserDeleteController extends WaterSupplyControllerBase {
public WaterUserDeleteController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
diff --git a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserUpdateController.java b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserUpdateController.java
index 32bdc4a9e..1f69eff36 100644
--- a/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserUpdateController.java
+++ b/cwms-data-api/src/main/java/cwms/cda/api/watersupply/WaterUserUpdateController.java
@@ -58,10 +58,10 @@
import org.jooq.DSLContext;
-public final class WaterUserUpdateController extends WaterSupplyControllerBase implements Handler {
+public final class WaterUserUpdateController extends WaterSupplyControllerBase {
public WaterUserUpdateController(MetricRegistry metrics) {
- waterMetrics(metrics);
+ super(metrics);
}
@OpenApi(
diff --git a/cwms-data-api/src/test/java/cwms/cda/api/OpenApiDocTest.java b/cwms-data-api/src/test/java/cwms/cda/api/OpenApiDocTest.java
index 2d365d4c0..48322cde5 100644
--- a/cwms-data-api/src/test/java/cwms/cda/api/OpenApiDocTest.java
+++ b/cwms-data-api/src/test/java/cwms/cda/api/OpenApiDocTest.java
@@ -22,8 +22,10 @@
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
+import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;
+import com.github.javaparser.ast.expr.ArrayInitializerExpr;
import com.github.javaparser.ast.expr.ClassExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.FieldAccessExpr;
@@ -31,6 +33,7 @@
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.resolution.Resolvable;
import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration;
+import com.github.javaparser.resolution.types.ResolvedType;
import com.google.common.flogger.FluentLogger;
import helpers.OpenApiDocInfo;
import helpers.OpenApiDocTestInfo;
@@ -39,6 +42,7 @@
import helpers.OpenApiParamUsageInfo;
import helpers.OpenApiTestHelper;
import io.javalin.apibuilder.CrudHandler;
+import io.javalin.http.Context;
import io.javalin.http.Handler;
import java.io.IOException;
import java.lang.reflect.Field;
@@ -46,6 +50,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
@@ -53,7 +58,6 @@
import java.util.stream.Stream;
import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.params.ParameterizedTest;
@@ -79,9 +83,9 @@ void test_crud_handler_documentation(OpenApiDocTestInfo testInfo) throws IOExcep
assertAll(buildTestAssertions(compilationUnit, testInfo));
}
- @Test
+// @Test
void test_time_series_controller() throws IOException {
- OpenApiDocTestInfo testInfo = OpenApiTestHelper.readOpenApiDocs(CrudHandler.class, StateController.class);
+ OpenApiDocTestInfo testInfo = OpenApiTestHelper.readOpenApiDocs(Handler.class, TimeSeriesFilteredController.class);
CompilationUnit compilationUnit = OpenApiTestHelper.readCompilationUnit(testInfo.getClazz());
assertAll(buildTestAssertions(compilationUnit, testInfo));
}
@@ -98,7 +102,7 @@ private Executable validateOpenApiDoc(CompilationUnit unit, OpenApiDocInfo testI
output = testIgnoredMethod(unit, testInfo, clazz);
} else {
OpenApiParamUsage parsedParamInfo = parseParamInfo(unit, clazz, testInfo.getMethod());
- output = testMethod(testInfo, parsedParamInfo);
+ output = testMethod(unit, testInfo, parsedParamInfo, clazz);
}
return output;
}
@@ -119,6 +123,7 @@ private Executable testIgnoredMethod(CompilationUnit unit, OpenApiDocInfo testIn
.filter(exp -> exp.getNameAsString().equals("json"))
.findFirst();
+ String methodRef = buildMethodRef(method, clazz);
try {
boolean usesStatus = statusCall.isPresent();
boolean isCorrectCode = statusCall.stream()
@@ -131,25 +136,33 @@ private Executable testIgnoredMethod(CompilationUnit unit, OpenApiDocInfo testIn
.map("CdaError.notImplemented()"::equals)
.orElse(false);
return () -> assertAll(
- "Testing ignored method " + method.getNameAsString() + ": Incorrect response for ignored endpoint. Expecting `ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented())`",
+ "Testing ignored method " + method.getNameAsString() + " " + methodRef + ": Incorrect response for ignored endpoint. Expecting `ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented())`",
() -> assertTrue(usesStatus && isCorrectCode,
"Incorrect status code used, context should provide HttpServletResponse.SC_NOT_IMPLEMENTED."),
() -> assertTrue(usesJson && isCorrectJson,
"Incorrect JSON returned, context should respond with CdaError.notImplemented()"));
} catch (Exception ex) {
- return () -> fail("Testing ignored method " + method.getNameAsString() + ": Error analyzing method. Expected `ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());`.", ex);
+ return () -> fail("Testing ignored method " + method.getNameAsString() + " " + methodRef + ": Error analyzing method. Expected `ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());`.", ex);
}
}
- private Executable testMethod(OpenApiDocInfo testInfo,
- OpenApiParamUsage parsedParamInfo) {
+ private String buildMethodRef(MethodDeclaration method, Class> clazz) {
+ //Creates a link in IntelliJ logs so we can easily jump to the file and declaration.
+ return "(" + clazz.getSimpleName() + ".java:" + method.getName().getBegin().map(p -> p.line).orElse(-1) + ")";
+ }
+
+ private Executable testMethod(CompilationUnit unit, OpenApiDocInfo testInfo,
+ OpenApiParamUsage parsedParamInfo, Class> clazz) {
List expectedQueryParameters = testInfo.getQueryParameters();
List expectedPathParameters = testInfo.getPathParameters();
Set receivedQueryParameters = parsedParamInfo.getQueryParams();
Set receivedPathParameters = parsedParamInfo.getPathParams();
OpenApiParamUsageInfo receivedResourceId = parsedParamInfo.getResourceId();
- return () -> assertAll("Testing " + testInfo.getMethod().getName(),
+ MethodDeclaration method = getMethodDeclaration(unit, testInfo.getMethod());
+ String methodRef = buildMethodRef(method, clazz);
+
+ return () -> assertAll("Testing " + testInfo.getMethod().getName() + " " + methodRef,
() -> testQueryParameters(expectedQueryParameters, receivedQueryParameters),
() -> testPathParameters(expectedPathParameters, receivedPathParameters, receivedResourceId));
}
@@ -194,9 +207,11 @@ private void testPathParameters(List expectedPathParameters, S
String missingInfo = missingItems.stream()
.map(OpenApiParamInfo::getName)
.collect(Collectors.joining(", "));
- assertAll(() -> assertTrue(receivedItems.isEmpty(), "Found used undocumented path parameter: " + extraInfo),
+ assertAll(
+ () -> assertTrue(receivedItems.isEmpty(), "Found used undocumented path parameter: " + extraInfo),
() -> assertTrue(missingItems.isEmpty(), "Found documented path parameter that is not used: " + missingInfo),
- () -> assertAll(expectedParams.stream().map(expectedParam -> testParamInfo(expectedParam, verifiedUsages))));
+ () -> assertAll(expectedParams.stream().map(expectedParam -> testParamInfo(expectedParam, verifiedUsages)))
+ );
}
private void testQueryParameters(List expectedQueryParameters,
@@ -256,8 +271,10 @@ private OpenApiParamUsage parseParamInfo(CompilationUnit unit, Class> clazz, M
String context = methodDeclaration.getParameter(0).getNameAsString();
List methodCalls = methodDeclaration.findAll(MethodCallExpr.class);
- Set optionalTypedQueryParams = readParamUsagesFromCall(methodCalls, call -> readQueryParamAsClassFromCall(unit, context, clazz, call), "queryParamAsClass");
+ Set optionalTypedQueryParams = readParamUsagesSetFromCall(methodCalls, call -> readQueryParamAsClassFromCall(unit, context, clazz, call), "queryParamAsClass");
Set optionalDoubleQueryParams = readParamUsagesFromCall(methodCalls, call -> readUsageFromCall(unit, clazz, call, false), "queryParamAsDouble");
+ Set filteredTsParam = readParamUsagesFromCall(methodCalls, this::findTsParamsFromUsage, "from");
+ Set ignoredPathParams = readParamUsagesFromCall(methodCalls, this::readIgnoredPathParameter, "logUnusedPathParameter");
Set optionalStringQueryParams = methodCalls.stream()
.filter(call -> call.getNameAsString().equals("queryParam"))
@@ -290,12 +307,14 @@ private OpenApiParamUsage parseParamInfo(CompilationUnit unit, Class> clazz, M
queryParams.addAll(optionalTimeQueryParams);
queryParams.addAll(requiredTimeQueryParams);
queryParams.addAll(optionalDoubleQueryParams);
+ queryParams.addAll(filteredTsParam);
Set pathParams = methodCalls.stream()
.filter(call -> call.getNameAsString().equals("pathParam"))
.map(call -> readUsageFromCall(unit, clazz, call, true))
.collect(Collectors.toSet());
+ pathParams.addAll(ignoredPathParams);
OpenApiParamUsageInfo resourceId = null;
@@ -312,11 +331,31 @@ private OpenApiParamUsage parseParamInfo(CompilationUnit unit, Class> clazz, M
return new OpenApiParamUsage(pathParams, queryParams, resourceId);
}
- private OpenApiParamUsageInfo readQueryParamAsClassFromCall(CompilationUnit unit, String context, Class> clazz, MethodCallExpr call) {
+ private OpenApiParamUsageInfo findTsParamsFromUsage(MethodCallExpr call) {
+ boolean isRightFunc = call.getScope()
+ .filter(Expression::isFieldAccessExpr)
+ .map(Expression::asFieldAccessExpr)
+ .map(s -> s.toString().equals("FilteredTimeSeriesParameters.Builder"))
+ .orElse(false);
+ OpenApiParamUsageInfo output = null;
+ if (isRightFunc) {
+ Expression arg0 = call.getArgument(0);
+ ResolvedType type = arg0.calculateResolvedType();
+ if (type.isReferenceType()) {
+ String qualifiedName = type.asReferenceType().getQualifiedName();
+ if (qualifiedName.equalsIgnoreCase(Context.class.getName())) {
+ output = new OpenApiParamUsageInfo(new OpenApiParamInfo(Controllers.QUERY, false, String.class), true, true);
+ }
+ }
+ }
+ return output;
+ }
+
+ private Set readQueryParamAsClassFromCall(CompilationUnit unit, String context, Class> clazz, MethodCallExpr call) {
return call.getScope()
.map(scope -> {
if (scope.isNameExpr()) {
- return readQueryParamAsClassFromContextCall(unit, clazz, call);
+ return Set.of(readQueryParamAsClassFromContextCall(unit, clazz, call));
} else {
return readQueryParamAsClassFromControllersCall(unit, clazz, call);
}
@@ -338,24 +377,43 @@ private OpenApiParamUsageInfo readQueryParamAsClassFromContextCall(CompilationUn
return new OpenApiParamUsageInfo(new OpenApiParamInfo(paramName, false, paramClass), used, nullHandled);
}
- private OpenApiParamUsageInfo readQueryParamAsClassFromControllersCall(CompilationUnit unit, Class> clazz, MethodCallExpr call) {
+ private Set readQueryParamAsClassFromControllersCall(CompilationUnit unit, Class> clazz, MethodCallExpr call) {
Expression arg1 = call.getArgument(1);
- Class> type;
- String name;
+ Set output = new HashSet<>();
if (arg1.isArrayCreationExpr()) {
//Context, String[], Class, T, {metrics}, {className}
- type = identifyClassFromExpression(unit, clazz, call.getArgument(2).asClassExpr());
- name = parseParameterName(arg1.asArrayCreationExpr().getInitializer().orElse(null).getValues().get(0));
+ NodeList values = arg1.asArrayCreationExpr()
+ .getInitializer()
+ .map(ArrayInitializerExpr::getValues)
+ .orElse(new NodeList<>());
+ Class> type = identifyClassFromExpression(unit, clazz, call.getArgument(2).asClassExpr());
+ values.forEach(value -> {
+ String name = parseParameterName(value);
+ output.add(new OpenApiParamUsageInfo(new OpenApiParamInfo(name, false, type), true, true));
+ });
} else if (arg1.isClassExpr()) {
//Context, Class, T, Name, [Aliases]
- type = identifyClassFromExpression(unit, clazz, arg1.asClassExpr());
- name = parseParameterName(call.getArgument(3));
+ Class> type = identifyClassFromExpression(unit, clazz, arg1.asClassExpr());
+ String name = parseParameterName(call.getArgument(3));
+ output.add(new OpenApiParamUsageInfo(new OpenApiParamInfo(name, false, type), true, true));
} else {
//Unknown case for queryParamAsClass (new method to handle?
throw new UnsupportedOperationException("Unsupported argument[1] type for queryParamAsClass: " + arg1.getClass());
}
- return new OpenApiParamUsageInfo(new OpenApiParamInfo(name, false, type), true, true);
+ return output;
+ }
+
+ private Set readParamUsagesSetFromCall(List methodCalls,
+ Function> paramReader,
+ String... functions) {
+ List realFunctions = Arrays.asList(functions);
+ return methodCalls.stream()
+ .filter(call -> realFunctions.contains(call.getNameAsString()))
+ .map(paramReader)
+ .filter(s -> !s.isEmpty())
+ .flatMap(Set::stream)
+ .collect(Collectors.toSet());
}
private Set readParamUsagesFromCall(List methodCalls,
@@ -365,6 +423,7 @@ private Set readParamUsagesFromCall(List
return methodCalls.stream()
.filter(call -> realFunctions.contains(call.getNameAsString()))
.map(paramReader)
+ .filter(Objects::nonNull)
.collect(Collectors.toSet());
}
@@ -378,6 +437,12 @@ private Set readJavaTimeFromCall(MethodCallExpr call, boo
new OpenApiParamUsageInfo(new OpenApiParamInfo(Controllers.TIMEZONE, required, type), used, nullHandled));
}
+ private OpenApiParamUsageInfo readIgnoredPathParameter(MethodCallExpr call) {
+ //Should never have scope, formatted as logUnusedPathParameter(Context ctx, String pathParam, String reason)
+ String param = parseParameterName(call.getArgument(1));
+ return new OpenApiParamUsageInfo(new OpenApiParamInfo(param, true, String.class), true, true);
+ }
+
private OpenApiParamUsageInfo readUsageFromCall(CompilationUnit unit, Class> clazz, MethodCallExpr call, boolean required) {
//We have a scope, so it's called from something like context.
return call.getScope().map(exp -> {