Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feature/cto 134 reservoir project #689

Merged
15 changes: 10 additions & 5 deletions cwms-data-api/src/main/java/cwms/cda/ApiServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import cwms.cda.api.OfficeController;
import cwms.cda.api.ParametersController;
import cwms.cda.api.PoolController;
import cwms.cda.api.ProjectController;
import cwms.cda.api.PropertyController;
import cwms.cda.api.RatingController;
import cwms.cda.api.RatingMetadataController;
Expand Down Expand Up @@ -167,6 +168,7 @@
"/forecast-spec/*",
"/forecast-instance/*",
"/standard-text-id/*",
"/projects/*",
"/properties/*",
"/lookup-types/*",
"/embankments/*"
Expand Down Expand Up @@ -404,9 +406,9 @@ protected void configureRoutes() {
new ParametersController(metrics), requiredRoles, 60, TimeUnit.MINUTES);
cdaCrudCache("/timezones/{zone}",
new TimeZoneController(metrics), requiredRoles,60, TimeUnit.MINUTES);
cdaCrudCache("/levels/{" + Controllers.LEVEL_ID + "}",
cdaCrudCache(format("/levels/{%s}", Controllers.LEVEL_ID),
new LevelsController(metrics), requiredRoles,5, TimeUnit.MINUTES);
String levelTsPath = "/levels/{" + Controllers.LEVEL_ID + "}/timeseries";
String levelTsPath = format("/levels/{%s}/timeseries", Controllers.LEVEL_ID);
get(levelTsPath, new LevelsAsTimeSeriesController(metrics));
addCacheControl(levelTsPath, 5, TimeUnit.MINUTES);
TimeSeriesController tsController = new TimeSeriesController(metrics);
Expand Down Expand Up @@ -456,13 +458,16 @@ protected void configureRoutes() {
new PoolController(metrics), requiredRoles,5, TimeUnit.MINUTES);
cdaCrudCache("/specified-levels/{specified-level-id}",
new SpecifiedLevelController(metrics), requiredRoles,5, TimeUnit.MINUTES);
cdaCrudCache("/forecast-instance/{" + Controllers.NAME + "}",
cdaCrudCache(format("/forecast-instance/{%s}", Controllers.NAME),
new ForecastInstanceController(metrics), requiredRoles,5, TimeUnit.MINUTES);
cdaCrudCache("/forecast-spec/{" + Controllers.NAME + "}",
cdaCrudCache(format("/forecast-spec/{%s}", Controllers.NAME),
new ForecastSpecController(metrics), requiredRoles,5, TimeUnit.MINUTES);
String forecastFilePath = "/forecast-instance/{" + NAME + "}/file-data";
String forecastFilePath = format("/forecast-instance/{%s}/file-data", NAME);
get(forecastFilePath, new ForecastFileController(metrics));
addCacheControl(forecastFilePath, 1, TimeUnit.DAYS);

cdaCrudCache(format("/projects/{%s}", Controllers.NAME),
new ProjectController(metrics), requiredRoles,5, TimeUnit.MINUTES);
cdaCrudCache(format("/properties/{%s}", Controllers.NAME),
new PropertyController(metrics), requiredRoles,1, TimeUnit.DAYS);
cdaCrudCache(format("/lookup-types/{%s}", Controllers.NAME),
Expand Down
189 changes: 109 additions & 80 deletions cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import static cwms.cda.api.Controllers.LOCATIONS;
import static cwms.cda.api.Controllers.LOCATION_CATEGORY_LIKE;
import static cwms.cda.api.Controllers.LOCATION_GROUP_LIKE;
import static cwms.cda.api.Controllers.LOCATION_KIND_LIKE;
import static cwms.cda.api.Controllers.LOCATION_TYPE_LIKE;
import static cwms.cda.api.Controllers.OFFICE;
import static cwms.cda.api.Controllers.PAGE;
import static cwms.cda.api.Controllers.PAGE_SIZE;
Expand Down Expand Up @@ -45,6 +47,7 @@
import io.javalin.plugin.openapi.annotations.OpenApiContent;
import io.javalin.plugin.openapi.annotations.OpenApiParam;
import io.javalin.plugin.openapi.annotations.OpenApiResponse;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -97,74 +100,88 @@ public void getAll(Context ctx) {
}

@OpenApi(
queryParams = {
@OpenApiParam(name = PAGE,
description = "This end point can return a lot of data, this "
+ "identifies where in the request you are."
queryParams = {
@OpenApiParam(name = PAGE,
description = "This end point can return a lot of data, this "
+ "identifies where in the request you are."
),

@OpenApiParam(name = PAGE_SIZE,
type = Integer.class,
description = "How many entries per page returned. Default 500."
),
@OpenApiParam(name = UNIT_SYSTEM,
type = UnitSystem.class,
description = UnitSystem.DESCRIPTION
),
@OpenApiParam(name = OFFICE,
description = "3-4 letter office name representing the district you "
+ "want to isolate data to."
),
@OpenApiParam(name = LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> "
+ "matching against the id"
),
@OpenApiParam(name = TIMESERIES_CATEGORY_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> "
+ "matching against the timeseries category id"
),
@OpenApiParam(name = TIMESERIES_GROUP_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> "
+ "matching against the timeseries group id"
),
@OpenApiParam(name = LOCATION_CATEGORY_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> "
+ "matching against the location category id"
),
@OpenApiParam(name = LOCATION_GROUP_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> "
+ "matching against the location group id"
),
@OpenApiParam(name = BOUNDING_OFFICE_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> "
+ "matching against the location bounding office. When this field is used "
+ "items with no bounding office set will not be present in results."),
@OpenApiParam(name = INCLUDE_EXTENTS, type = Boolean.class,
description = "Whether the returned catalog entries should include timeseries "
+ "extents. Only valid for TIMESERIES. "
+ "Default is " + INCLUDE_EXTENTS_DEFAULT + "."),
@OpenApiParam(name = EXCLUDE_EMPTY, type = Boolean.class,
description = "Specifies "
+ "whether Timeseries that have empty extents "
+ "should be excluded from the results. For purposes of this parameter "
+ "'empty' is defined as VERSION_TIME, EARLIEST_TIME, LATEST_TIME "
+ "and LAST_UPDATE all being null. This parameter does not control "
+ "whether the extents are returned to the user, only whether matching "
+ "timeseries are excluded. Only valid for TIMESERIES. "
+ "Default is " + EXCLUDE_EMPTY_DEFAULT + "."),
@OpenApiParam(name = LOCATION_KIND_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> matching "
+ "against the location kind. The location-kind is typically unset "
+ "or one of the following: {\"SITE\", \"EMBANKMENT\", \"OVERFLOW\", "
+ "\"TURBINE\", \"STREAM\", \"PROJECT\", \"STREAMGAGE\", \"BASIN\", "
+ "\"OUTLET\", \"LOCK\", \"GATE\"}. Multiple kinds can be matched "
+ "by using Regular Expression OR clauses. For example: "
+ "\"(SITE|STREAM)\""
),

@OpenApiParam(name = PAGE_SIZE,
type = Integer.class,
description = "How many entries per page returned. Default 500."
),
@OpenApiParam(name = UNIT_SYSTEM,
type = UnitSystem.class,
description = UnitSystem.DESCRIPTION
),
@OpenApiParam(name = OFFICE,
description = "3-4 letter office name representing the district you "
+ "want to isolate data to."
),
@OpenApiParam(name = LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> matching against the id"
),
@OpenApiParam(name = TIMESERIES_CATEGORY_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> matching against the "
+ "timeseries category id"
@OpenApiParam(name = LOCATION_TYPE_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> matching "
+ "against the location type."
),
@OpenApiParam(name = TIMESERIES_GROUP_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> matching against the "
+ "timeseries group id"
),
@OpenApiParam(name = LOCATION_CATEGORY_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> matching against the location"
+ " category id"
),
@OpenApiParam(name = LOCATION_GROUP_LIKE,
description = "Posix <a href=\"regexp.html\">regular expression</a> matching against the location"
+ " group id"
),
@OpenApiParam(name = BOUNDING_OFFICE_LIKE, description = "Posix <a href=\"regexp.html\">regular expression</a> "
+ "matching against the location bounding office. "
+ "When this field is used items with no bounding office set will not be present in results."),
@OpenApiParam(name = Controllers.INCLUDE_EXTENTS, type = Boolean.class,
description = "Whether the returned catalog entries should include timeseries "
+ "extents. Only valid for TIMESERIES. "
+ "Default is " + INCLUDE_EXTENTS_DEFAULT + "."),
@OpenApiParam(name = Controllers.EXCLUDE_EMPTY, type = Boolean.class,
description = "Specifies "
+ "whether Timeseries that have empty extents "
+ "should be excluded from the results. For purposes of this parameter "
+ "'empty' is defined as VERSION_TIME, EARLIEST_TIME, LATEST_TIME "
+ "and LAST_UPDATE all being null. This parameter does not control "
+ "whether the extents are returned to the user, only whether matching "
+ "timeseries are excluded. Only valid for TIMESERIES. "
+ "Default is " + EXCLUDE_EMPTY_DEFAULT + "."),
},
pathParams = {
@OpenApiParam(name = "dataset",
type = CatalogableEndpoint.class,
description = "A list of what data? E.g. Timeseries, Locations, Ratings, etc")
},
responses = {@OpenApiResponse(status = STATUS_200,
description = "A list of elements the data set you've selected.",
content = {
@OpenApiContent(from = Catalog.class, type = Formats.JSONV2),
@OpenApiContent(from = Catalog.class, type = Formats.XML)
}
)
},
tags = {TAG}
},
pathParams = {
@OpenApiParam(name = "dataset",
type = CatalogableEndpoint.class,
description = "A list of what data? E.g. Timeseries, Locations, Ratings, etc")
},
responses = {@OpenApiResponse(status = STATUS_200,
description = "A list of elements the data set you've selected.",
content = {
@OpenApiContent(from = Catalog.class, type = Formats.JSONV2),
@OpenApiContent(from = Catalog.class, type = Formats.XML)
})
},
tags = {TAG}
)
@Override
public void getOne(@NotNull Context ctx, @NotNull String dataSet) {
Expand Down Expand Up @@ -208,6 +225,12 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) {
String boundingOfficeLike = queryParamAsClass(ctx, new String[]{BOUNDING_OFFICE_LIKE},
String.class, null, metrics, name(CatalogController.class.getName(), GET_ONE));

String locationKind = queryParamAsClass(ctx, new String[]{LOCATION_KIND_LIKE},
String.class, null, metrics, name(CatalogController.class.getName(), GET_ONE));

String locationType = queryParamAsClass(ctx, new String[]{LOCATION_TYPE_LIKE},
String.class, null, metrics, name(CatalogController.class.getName(), GET_ONE));

String acceptHeader = ctx.header(ACCEPT);
ContentType contentType = Formats.parseHeaderAndQueryParm(acceptHeader, null);
Catalog cat = null;
Expand All @@ -229,25 +252,16 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) {
.withBoundingOfficeLike(boundingOfficeLike)
.withIncludeExtents(includeExtents)
.withExcludeEmpty(excludeExtents)
.withLocationKind(locationKind)
.withLocationType(locationType)
.build();

cat = tsDao.getTimeSeriesCatalog(cursor, pageSize, parameters);

} else if (LOCATIONS.equalsIgnoreCase(valDataSet)) {

Set<String> notSupported = new LinkedHashSet<>();
notSupported.add(TIMESERIES_CATEGORY_LIKE);
notSupported.add(TIMESERIES_GROUP_LIKE);
notSupported.add(EXCLUDE_EMPTY);
notSupported.add(INCLUDE_EXTENTS);

Map<String, List<String>> queryParamMap = ctx.queryParamMap();
notSupported.retainAll(queryParamMap.keySet());

if (!notSupported.isEmpty()) {
throw new IllegalArgumentException("The following parameters are not yet "
+ "supported for location: " + notSupported);
}
warnAboutNotSupported(ctx, new String[]{TIMESERIES_CATEGORY_LIKE,
TIMESERIES_GROUP_LIKE, EXCLUDE_EMPTY, INCLUDE_EXTENTS});

CatalogRequestParameters parameters = new CatalogRequestParameters.Builder()
.withUnitSystem(unitSystem)
Expand All @@ -256,6 +270,8 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) {
.withLocCatLike(locCategoryLike)
.withLocGroupLike(locGroupLike)
.withBoundingOfficeLike(boundingOfficeLike)
.withLocationKind(locationKind)
.withLocationType(locationType)
.build();

LocationsDao dao = new LocationsDaoImpl(dsl);
Expand All @@ -269,12 +285,25 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) {
final CdaError re = new CdaError("Cannot create catalog of requested "
+ "information");

logger.info(() -> re + "with url:" + ctx.fullUrl());
logger.info(() -> re + " with url:" + ctx.fullUrl());
ctx.json(re).status(HttpCode.NOT_FOUND);
}
}
}

private static void warnAboutNotSupported(@NotNull Context ctx, String[] warnAbout) {
Set<String> notSupported = new LinkedHashSet<>();
Collections.addAll(notSupported, warnAbout);

Map<String, List<String>> queryParamMap = ctx.queryParamMap();
notSupported.retainAll(queryParamMap.keySet());

if (!notSupported.isEmpty()) {
throw new IllegalArgumentException("The following parameters are not yet "
+ "supported for this method: " + notSupported);
}
}

@OpenApi(tags = {"Catalog"}, ignore = true)
@Override
public void update(Context ctx, @NotNull String entry) {
Expand Down
16 changes: 7 additions & 9 deletions cwms-data-api/src/main/java/cwms/cda/api/Controllers.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

package cwms.cda.api;

import static com.codahale.metrics.MetricRegistry.name;

import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
Expand All @@ -41,8 +43,6 @@
import java.time.ZonedDateTime;
import org.jetbrains.annotations.Nullable;

import static com.codahale.metrics.MetricRegistry.name;

public final class Controllers {


Expand Down Expand Up @@ -130,6 +130,8 @@ public final class Controllers {
public static final String SOURCE_ENTITY = "source-entity";
public static final String FORECAST_DATE = "forecast-date";
public static final String ISSUE_DATE = "issue-date";
public static final String LOCATION_KIND_LIKE = "location-kind-like";
public static final String LOCATION_TYPE_LIKE = "location-type-like";

public static final String GROUP_ID = "group-id";
public static final String REPLACE_ASSIGNED_LOCS = "replace-assigned-locs";
Expand Down Expand Up @@ -364,14 +366,10 @@ public static Instant requiredInstant(Context ctx, String param) {
return retval;
}

static void addDeprecatedContentTypeWarning(Context ctx, ContentType type)
{
if (type.getType().equalsIgnoreCase(Formats.TAB))
{
static void addDeprecatedContentTypeWarning(Context ctx, ContentType type) {
if (type.getType().equalsIgnoreCase(Formats.TAB)) {
ctx.res.addHeader(DEPRECATED_HEADER, DEPRECATED_TAB);
}
else if (type.getType().equalsIgnoreCase(Formats.CSV))
{
} else if (type.getType().equalsIgnoreCase(Formats.CSV)) {
ctx.res.addHeader(DEPRECATED_HEADER, DEPRECATED_CSV);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
import cwms.cda.api.errors.CdaError;
import cwms.cda.data.dao.DeleteRule;
import cwms.cda.data.dao.JooqDao;
import cwms.cda.data.dao.ProjectDao;
import cwms.cda.data.dto.Project;
import cwms.cda.data.dto.Projects;
import cwms.cda.data.dao.project.ProjectDao;
import cwms.cda.data.dto.project.Project;
import cwms.cda.data.dto.project.Projects;
import cwms.cda.formatters.ContentType;
import cwms.cda.formatters.Formats;
import cwms.cda.formatters.FormattingException;
Expand Down
Loading
Loading