Skip to content

Added filtered time series retrieval API. #1169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cwms-data-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ dependencies {
exclude group: "jakarta.xml.bind", module: "*"
}

implementation 'cz.jirutka.rsql:rsql-parser:2.1.0'

compileOnly(libs.javaee.web.api)
compileOnly(libs.cwms.tomcat.auth)

Expand Down
23 changes: 14 additions & 9 deletions cwms-data-api/src/main/java/cwms/cda/ApiServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
import cwms.cda.api.TimeSeriesGroupController;
import cwms.cda.api.TimeSeriesIdentifierDescriptorController;
import cwms.cda.api.TimeSeriesRecentController;
import cwms.cda.api.TimeSeriesFilteredController;
import cwms.cda.api.TimeZoneController;
import cwms.cda.api.TurbineChangesDeleteController;
import cwms.cda.api.TurbineChangesGetController;
Expand Down Expand Up @@ -321,7 +322,7 @@ public void init(ServletConfig config) throws ServletException {
metrics = (MetricRegistry)config.getServletContext()
.getAttribute(MetricsServlet.METRICS_REGISTRY);
totalRequests = metrics.meter("cwms.dataapi.total_requests");

super.init(config);
}

Expand Down Expand Up @@ -552,6 +553,10 @@ protected void configureRoutes() {
get(recentPath, new TimeSeriesRecentController(metrics));
addCacheControl(recentPath, 5, TimeUnit.MINUTES);

String filteredPath = "/timeseries/filtered";
get(filteredPath, new TimeSeriesFilteredController(metrics));
addCacheControl(filteredPath, 5, TimeUnit.MINUTES);

cdaCrudCache(format("/standard-text-id/{%s}", Controllers.STANDARD_TEXT_ID),
new StandardTextController(metrics), requiredRoles,1, TimeUnit.DAYS);

Expand All @@ -568,30 +573,30 @@ protected void configureRoutes() {
addCacheControl(textBinaryValuePath, 1, TimeUnit.DAYS);

String timeSeriesProfilePath = "/timeseries/profile/";
get(format(timeSeriesProfilePath + "{%s}/{%s}", Controllers.LOCATION_ID, Controllers.PARAMETER_ID),
get(format( "%s{%s}/{%s}", timeSeriesProfilePath, Controllers.LOCATION_ID, Controllers.PARAMETER_ID),
new TimeSeriesProfileController(metrics));
delete(format(timeSeriesProfilePath + "/{%s}/{%s}", Controllers.LOCATION_ID,
delete(format( "%s/{%s}/{%s}", timeSeriesProfilePath, Controllers.LOCATION_ID,
Controllers.PARAMETER_ID), new TimeSeriesProfileDeleteController(metrics),
requiredRoles);
get(format(timeSeriesProfilePath, Controllers.LOCATION_ID, Controllers.PARAMETER_ID),
new TimeSeriesProfileCatalogController(metrics));
post(timeSeriesProfilePath, new TimeSeriesProfileCreateController(metrics), requiredRoles);

String timeSeriesProfileParserPath = "/timeseries/profile-parser/";
get(format(timeSeriesProfileParserPath + "{%s}/{%s}/", Controllers.LOCATION_ID,
get(format( "%s{%s}/{%s}/", timeSeriesProfileParserPath, Controllers.LOCATION_ID,
Controllers.PARAMETER_ID), new TimeSeriesProfileParserController(metrics));
post(timeSeriesProfileParserPath, new TimeSeriesProfileParserCreateController(metrics), requiredRoles);
delete(format(timeSeriesProfileParserPath + "{%s}/{%s}/", Controllers.LOCATION_ID,
delete(format( "%s{%s}/{%s}/", timeSeriesProfileParserPath, Controllers.LOCATION_ID,
Controllers.PARAMETER_ID), new TimeSeriesProfileParserDeleteController(metrics),
requiredRoles);
get(timeSeriesProfileParserPath, new TimeSeriesProfileParserCatalogController(metrics));

String timeSeriesProfileInstancePath = "/timeseries/profile-instance/";
get(format(timeSeriesProfileInstancePath + "{%s}/{%s}/{%s}/", Controllers.LOCATION_ID,
get(format("%s{%s}/{%s}/{%s}/", timeSeriesProfileInstancePath, Controllers.LOCATION_ID,
Controllers.PARAMETER_ID, Controllers.VERSION),
new TimeSeriesProfileInstanceController(metrics));
post(timeSeriesProfileInstancePath, new TimeSeriesProfileInstanceCreateController(metrics), requiredRoles);
delete(format(timeSeriesProfileInstancePath + "{%s}/{%s}/{%s}/", Controllers.LOCATION_ID,
delete(format("%s{%s}/{%s}/{%s}/", timeSeriesProfileInstancePath, Controllers.LOCATION_ID,
Controllers.PARAMETER_ID, Controllers.VERSION),
new TimeSeriesProfileInstanceDeleteController(metrics), requiredRoles);
get(timeSeriesProfileInstancePath, new TimeSeriesProfileInstanceCatalogController(metrics));
Expand Down Expand Up @@ -629,7 +634,7 @@ protected void configureRoutes() {
String measTimeExtents = measurements + "time-extents";
get(measTimeExtents,new MeasurementTimeExtentsGetController(metrics));
addCacheControl(measTimeExtents, 5, TimeUnit.MINUTES);
cdaCrudCache(format(measurements + "{%s}", LOCATION_ID),
cdaCrudCache(format( "%s{%s}", measurements, LOCATION_ID),
new cwms.cda.api.MeasurementController(metrics), requiredRoles,5, TimeUnit.MINUTES);
cdaCrudCache("/blobs/{blob-id}",
new BlobController(metrics), requiredRoles,5, TimeUnit.MINUTES);
Expand Down Expand Up @@ -939,7 +944,7 @@ private void getOpenApiOptions(JavalinConfig config) {

String provider = CdaAccessManager.class.getSimpleName();


Components components = new Components();
final ArrayList<SecurityRequirement> secReqs = new ArrayList<>();
authenticator.getActiveProviders().forEach(identityProvider -> {
Expand Down
10 changes: 9 additions & 1 deletion cwms-data-api/src/main/java/cwms/cda/api/Controllers.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ public final class Controllers {
public static final String INTERVAL = "interval";
public static final String CATEGORY_ID = "category-id";
public static final String CATEGORY_ID_MASK = "category-id-mask";
public static final String EXAMPLE_DATE = "2021-06-10T13:00:00-07:00";
public static final String VERSION_DATE = "version-date";

public static final String CREATE_AS_LRTS = "create-as-lrts";
Expand Down Expand Up @@ -160,7 +159,12 @@ public final class Controllers {
public static final String REPLACE_ASSIGNED_LOCS = "replace-assigned-locs";
public static final String REPLACE_ASSIGNED_TS = "replace-assigned-ts";
public static final String TS_IDS = "ts-ids";

public static final String EXAMPLE_DATE = "2021-06-10T13:00:00-07:00";
public static final String DATE_FORMAT = "YYYY-MM-dd'T'hh:mm:ss[Z'['VV']']";
public static final String TIME_FORMAT_DESC = "The <a href=\"times.html\">format for this field</a> is ISO 8601 extended" +
", with optional offset and timezone, i.e., '" + DATE_FORMAT + "', e.g., '" + EXAMPLE_DATE + "'." ;

public static final String INCLUDE_ASSIGNED = "include-assigned";
public static final String ANY_MASK = "*";
public static final String OFFICE_MASK = "office-mask";
Expand Down Expand Up @@ -226,6 +230,10 @@ public final class Controllers {
private static final String DEPRECATED_HEADER = "CWMS-DATA-Format-Deprecated";
private static final String DEPRECATED_TAB = "2024-11-01 TAB is not used often.";
private static final String DEPRECATED_CSV = "2024-11-01 CSV is not used often.";
public static final String MIN_VALUE = "min-value";
public static final String MAX_VALUE = "max-value";
public static final String FILTER_NULLS = "filter-nulls";
public static final String QUERY = "query";


static {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
import java.time.ZoneId;
import java.time.ZonedDateTime;

import static com.codahale.metrics.MetricRegistry.name;
import static cwms.cda.api.Controllers.*;
import static cwms.cda.data.dao.JooqDao.getDslContext;

Expand Down Expand Up @@ -77,16 +76,13 @@ private Timer.Context markAndTime(String subject) {
@OpenApiParam(name = BEGIN, description = "Specifies the "
+ "start of the time window for data to be included in the response. "
+ "If this field is not specified, any required time window begins 24"
+ " hours prior to the specified or default end time. The format for "
+ "this field is ISO 8601 extended, with optional offset and "
+ "timezone, i.e., '"
+ DATE_FORMAT + "', e.g., '" + EXAMPLE_DATE + "'."),
+ " hours prior to the specified or default end time. " +
TIME_FORMAT_DESC),
@OpenApiParam(name = END, description = "Specifies the "
+ "end of the time window for data to be included in the response. If"
+ " this field is not specified, any required time window ends at the"
+ " current time. The format for this field is ISO 8601 extended, "
+ "with optional timezone, i.e., '"
+ DATE_FORMAT + "', e.g., '" + EXAMPLE_DATE + "'."),
+ " current time. " +
TIME_FORMAT_DESC),
@OpenApiParam(name = TIMEZONE, description = "Specifies "
+ "the time zone of the values of the begin and end fields (unless "
+ "otherwise specified), as well as the time zone of any times in the"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@
import static cwms.cda.api.Controllers.AGENCY;
import static cwms.cda.api.Controllers.BEGIN;
import static cwms.cda.api.Controllers.CREATE;
import static cwms.cda.api.Controllers.DATE_FORMAT;
import static cwms.cda.api.Controllers.DELETE;
import static cwms.cda.api.Controllers.EXAMPLE_DATE;
import static cwms.cda.api.Controllers.FAIL_IF_EXISTS;
import static cwms.cda.api.Controllers.GET_ALL;
import static cwms.cda.api.Controllers.GET_ONE;
Expand All @@ -50,6 +48,7 @@
import static cwms.cda.api.Controllers.OFFICE_MASK;
import static cwms.cda.api.Controllers.QUALITY;
import static cwms.cda.api.Controllers.TIMEZONE;
import static cwms.cda.api.Controllers.TIME_FORMAT_DESC;
import static cwms.cda.api.Controllers.UNIT_SYSTEM;
import static cwms.cda.api.Controllers.queryParamAsDouble;
import static cwms.cda.api.Controllers.queryParamAsInstant;
Expand Down Expand Up @@ -100,14 +99,10 @@ private Timer.Context markAndTime(String subject) {
@OpenApiParam(name = ID_MASK, description = "Location id mask for filtering measurements. Use null to retrieve measurements for all locations."),
@OpenApiParam(name = MIN_NUMBER, description = "Minimum measurement number-id for filtering measurements."),
@OpenApiParam(name = MAX_NUMBER, description = "Maximum measurement number-id for filtering measurements."),
@OpenApiParam(name = BEGIN, description = "The start of the time "
+ "window to delete. The format for this field is ISO 8601 extended, with "
+ "optional offset and timezone, i.e., '" + DATE_FORMAT + "', e.g., '"
+ EXAMPLE_DATE + "'. A null value is treated as an unbounded start."),
@OpenApiParam(name = END, description = "The end of the time "
+ "window to delete.The format for this field is ISO 8601 extended, with "
+ "optional offset and timezone, i.e., '" + DATE_FORMAT + "', e.g., '"
+ EXAMPLE_DATE + "'.A null value is treated as an unbounded end."),
@OpenApiParam(name = BEGIN, description = "The start of the time window to delete. " +
TIME_FORMAT_DESC + " A null value is treated as an unbounded start."),
@OpenApiParam(name = END, description = "The end of the time window to delete." +
TIME_FORMAT_DESC + " A null value is treated as an unbounded end."),
@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. "
Expand Down Expand Up @@ -226,14 +221,10 @@ public void update(@NotNull Context ctx, @NotNull String locationId) {
},
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the office of the measurements to delete"),
@OpenApiParam(name = BEGIN, required = true, description = "The start of the time "
+ "window to delete. The format for this field is ISO 8601 extended, with "
+ "optional offset and timezone, i.e., '" + DATE_FORMAT + "', e.g., '"
+ EXAMPLE_DATE + "'."),
@OpenApiParam(name = END, required = true, description = "The end of the time "
+ "window to delete.The format for this field is ISO 8601 extended, with "
+ "optional offset and timezone, i.e., '" + DATE_FORMAT + "', e.g., '"
+ EXAMPLE_DATE + "'."),
@OpenApiParam(name = BEGIN, required = true, description = "The start of the time window to delete. " +
TIME_FORMAT_DESC),
@OpenApiParam(name = END, required = true, description = "The end of the time window to delete." +
TIME_FORMAT_DESC),
@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. "
Expand Down
Loading
Loading