use of de.ii.ogcapi.tiles.domain.MinMax in project ldproxy by interactive-instruments.
the class TilesQueriesHandlerImpl method getTileSetResponse.
private Response getTileSetResponse(QueryInputTileSet queryInput, ApiRequestContext requestContext) {
OgcApi api = requestContext.getApi();
OgcApiDataV2 apiData = api.getData();
String tileMatrixSetId = queryInput.getTileMatrixSetId();
Optional<String> collectionId = queryInput.getCollectionId();
String definitionPath = queryInput.getPath();
String path = collectionId.map(value -> definitionPath.replace("{collectionId}", value)).orElse(definitionPath).replace("{tileMatrixSetId}", tileMatrixSetId);
TileSetFormatExtension outputFormat = api.getOutputFormat(TileSetFormatExtension.class, requestContext.getMediaType(), path, collectionId).orElseThrow(() -> new NotAcceptableException(MessageFormat.format("The requested media type ''{0}'' is not supported for this resource.", requestContext.getMediaType())));
List<TileFormatExtension> tileFormats = extensionRegistry.getExtensionsForType(TileFormatExtension.class).stream().filter(format -> collectionId.map(s -> format.isApplicable(apiData, s, definitionPath)).orElseGet(() -> format.isApplicable(apiData, definitionPath))).collect(Collectors.toUnmodifiableList());
DataType dataType = tileFormats.stream().map(TileFormatExtension::getDataType).findAny().orElseThrow(() -> new NotFoundException("No encoding found for this tile set."));
final TilesLinkGenerator tilesLinkGenerator = new TilesLinkGenerator();
List<Link> links = tilesLinkGenerator.generateTileSetLinks(requestContext.getUriCustomizer(), requestContext.getMediaType(), requestContext.getAlternateMediaTypes(), tileFormats, i18n, requestContext.getLanguage());
MinMax zoomLevels = queryInput.getZoomLevels();
List<Double> center = queryInput.getCenter();
TileSet tileset = TilesHelper.buildTileSet(api, getTileMatrixSetById(tileMatrixSetId), zoomLevels, center, collectionId, dataType, links, Optional.of(requestContext.getUriCustomizer().copy()), crsTransformerFactory, limitsGenerator, providers, entityRegistry);
Date lastModified = getLastModified(queryInput, requestContext.getApi());
EntityTag etag = !outputFormat.getMediaType().type().equals(MediaType.TEXT_HTML_TYPE) || (collectionId.isEmpty() ? apiData.getExtension(HtmlConfiguration.class) : apiData.getExtension(HtmlConfiguration.class, collectionId.get())).map(HtmlConfiguration::getSendEtags).orElse(false) ? getEtag(tileset, TileSet.FUNNEL, outputFormat) : null;
Response.ResponseBuilder response = evaluatePreconditions(requestContext, lastModified, etag);
if (Objects.nonNull(response))
return response.build();
return prepareSuccessResponse(requestContext, queryInput.getIncludeLinkHeader() ? links : null, lastModified, etag, queryInput.getCacheControl().orElse(null), queryInput.getExpires().orElse(null), null, true, String.format("%s.%s", tileset.getTileMatrixSetId(), outputFormat.getMediaType().fileExtension())).entity(outputFormat.getTileSetEntity(tileset, apiData, collectionId, requestContext)).build();
}
use of de.ii.ogcapi.tiles.domain.MinMax in project ldproxy by interactive-instruments.
the class TilesHelper method buildTileSet.
// TODO: move to TileSet as static of()
/**
* generate the tile set metadata according to the OGC Tile Matrix Set standard (version 2.0.0, draft from June 2021)
* @param api the API
* @param tileMatrixSet the tile matrix set
* @param zoomLevels the range of zoom levels
* @param center the center point
* @param collectionId the collection, empty = all collections in the dataset
* @param dataType vector, map or coverage
* @param links links to include in the object
* @param uriCustomizer optional URI of the resource
* @param limitsGenerator helper to generate the limits for each zoom level based on the bbox of the data
* @param providers helper to access feature providers
* @return the tile set metadata
*/
public static TileSet buildTileSet(OgcApi api, TileMatrixSet tileMatrixSet, MinMax zoomLevels, List<Double> center, Optional<String> collectionId, TileSet.DataType dataType, List<Link> links, Optional<URICustomizer> uriCustomizer, CrsTransformerFactory crsTransformerFactory, TileMatrixSetLimitsGenerator limitsGenerator, FeaturesCoreProviders providers, EntityRegistry entityRegistry) {
OgcApiDataV2 apiData = api.getData();
Builder builder = ImmutableTileSet.builder().dataType(dataType);
builder.tileMatrixSetId(tileMatrixSet.getId());
if (tileMatrixSet.getURI().isPresent())
builder.tileMatrixSetURI(tileMatrixSet.getURI().get().toString());
else
builder.tileMatrixSet(tileMatrixSet.getTileMatrixSetData());
uriCustomizer.ifPresent(uriCustomizer1 -> builder.tileMatrixSetDefinition(uriCustomizer1.removeLastPathSegments(collectionId.isPresent() ? 3 : 1).clearParameters().ensureLastPathSegments("tileMatrixSets", tileMatrixSet.getId()).toString()));
if (Objects.isNull(zoomLevels))
builder.tileMatrixSetLimits(ImmutableList.of());
else
builder.tileMatrixSetLimits(collectionId.isPresent() ? limitsGenerator.getCollectionTileMatrixSetLimits(api, collectionId.get(), tileMatrixSet, zoomLevels) : limitsGenerator.getTileMatrixSetLimits(api, tileMatrixSet, zoomLevels));
try {
BoundingBox boundingBox = api.getSpatialExtent(collectionId).orElse(tileMatrixSet.getBoundingBoxCrs84(crsTransformerFactory));
builder.boundingBox(ImmutableTilesBoundingBox.builder().lowerLeft(BigDecimal.valueOf(boundingBox.getXmin()).setScale(7, RoundingMode.HALF_UP), BigDecimal.valueOf(boundingBox.getYmin()).setScale(7, RoundingMode.HALF_UP)).upperRight(BigDecimal.valueOf(boundingBox.getXmax()).setScale(7, RoundingMode.HALF_UP), BigDecimal.valueOf(boundingBox.getYmax()).setScale(7, RoundingMode.HALF_UP)).crs(OgcCrs.CRS84.toUriString()).build());
} catch (CrsTransformationException e) {
// ignore, just skip the boundingBox
}
if ((Objects.nonNull(zoomLevels) && zoomLevels.getDefault().isPresent()) || !center.isEmpty()) {
ImmutableTilePoint.Builder builder2 = new ImmutableTilePoint.Builder();
if (Objects.nonNull(zoomLevels))
zoomLevels.getDefault().ifPresent(def -> builder2.tileMatrix(String.valueOf(def)));
if (!center.isEmpty())
builder2.coordinates(center);
builder.centerPoint(builder2.build());
}
// prepare a map with the JSON schemas of the feature collections used in the style
JsonSchemaCache schemas = new SchemaCacheTileSet(() -> entityRegistry.getEntitiesForType(Codelist.class));
Map<String, JsonSchemaDocument> schemaMap = collectionId.isPresent() ? apiData.getCollectionData(collectionId.get()).filter(collectionData -> {
Optional<TilesConfiguration> config = collectionData.getExtension(TilesConfiguration.class);
return collectionData.getEnabled() && config.isPresent() && config.get().isEnabled();
}).map(collectionData -> {
Optional<FeatureSchema> schema = providers.getFeatureSchema(apiData, collectionData);
if (schema.isPresent())
return ImmutableMap.of(collectionId.get(), schemas.getSchema(schema.get(), apiData, collectionData, Optional.empty()));
return null;
}).filter(Objects::nonNull).orElse(ImmutableMap.of()) : apiData.getCollections().entrySet().stream().filter(entry -> {
Optional<TilesConfiguration> config = entry.getValue().getExtension(TilesConfiguration.class);
return entry.getValue().getEnabled() && config.isPresent() && config.get().isMultiCollectionEnabled();
}).map(entry -> {
Optional<FeatureSchema> schema = providers.getFeatureSchema(apiData, entry.getValue());
if (schema.isPresent())
return new AbstractMap.SimpleImmutableEntry<>(entry.getKey(), schemas.getSchema(schema.get(), apiData, entry.getValue(), Optional.empty()));
return null;
}).filter(Objects::nonNull).collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
// TODO: replace with SchemaDeriverTileLayers
schemaMap.entrySet().stream().forEach(entry -> {
String collectionId2 = entry.getKey();
FeatureTypeConfigurationOgcApi collectionData = apiData.getCollections().get(collectionId2);
JsonSchemaDocument schema = entry.getValue();
ImmutableTileLayer.Builder builder2 = ImmutableTileLayer.builder().id(collectionId2).title(collectionData.getLabel()).description(collectionData.getDescription()).dataType(dataType);
collectionData.getExtension(TilesConfiguration.class).map(config -> config.getZoomLevelsDerived().get(tileMatrixSet.getId())).ifPresent(minmax -> builder2.minTileMatrix(String.valueOf(minmax.getMin())).maxTileMatrix(String.valueOf(minmax.getMax())));
final JsonSchema geometry = schema.getProperties().get("geometry");
if (Objects.nonNull(geometry)) {
String geomAsString = geometry.toString();
boolean point = geomAsString.contains("GeoJSON Point") || geomAsString.contains("GeoJSON MultiPoint");
boolean line = geomAsString.contains("GeoJSON LineString") || geomAsString.contains("GeoJSON MultiLineString");
boolean polygon = geomAsString.contains("GeoJSON Polygon") || geomAsString.contains("GeoJSON MultiPolygon");
if (point && !line && !polygon)
builder2.geometryType(TileLayer.GeometryType.points);
else if (!point && line && !polygon)
builder2.geometryType(TileLayer.GeometryType.lines);
else if (!point && !line && polygon)
builder2.geometryType(TileLayer.GeometryType.polygons);
}
final JsonSchemaObject properties = (JsonSchemaObject) schema.getProperties().get("properties");
builder2.propertiesSchema(ImmutableJsonSchemaObject.builder().required(properties.getRequired()).properties(properties.getProperties()).patternProperties(properties.getPatternProperties()).build());
builder.addLayers(builder2.build());
});
builder.links(links);
return builder.build();
}
use of de.ii.ogcapi.tiles.domain.MinMax in project ldproxy by interactive-instruments.
the class TileCacheImpl method deleteTilesMbtiles.
private void deleteTilesMbtiles(OgcApi api, Optional<String> collectionId, Map<String, MinMax> zoomLevels, Map<String, BoundingBox> boundingBoxes) throws SQLException, IOException {
for (Map.Entry<String, MinMax> tileSet : zoomLevels.entrySet()) {
TileMatrixSet tileMatrixSet = getTileMatrixSetById(tileSet.getKey());
MinMax levels = tileSet.getValue();
BoundingBox bbox = boundingBoxes.get(tileSet.getKey());
// first the dataset tiles
deleteTilesMbtiles(api, Optional.empty(), tileMatrixSet, levels, bbox);
if (collectionId.isPresent()) {
// also the single collection tiles for the collection
deleteTilesMbtiles(api, collectionId, tileMatrixSet, levels, bbox);
} else {
// all single collection tiles
for (String colId : api.getData().getCollections().keySet()) {
deleteTilesMbtiles(api, Optional.of(colId), tileMatrixSet, levels, bbox);
}
}
}
}
use of de.ii.ogcapi.tiles.domain.MinMax in project ldproxy by interactive-instruments.
the class AbstractEndpointTileSingleCollection method getTile.
protected Response getTile(OgcApi api, ApiRequestContext requestContext, UriInfo uriInfo, String definitionPath, String collectionId, String tileMatrixSetId, String tileMatrix, String tileRow, String tileCol, TileProvider tileProvider) throws CrsTransformationException, IOException, NotFoundException {
OgcApiDataV2 apiData = api.getData();
Map<String, String> queryParams = toFlatMap(uriInfo.getQueryParameters());
FeatureTypeConfigurationOgcApi featureType = apiData.getCollections().get(collectionId);
TilesConfiguration tilesConfiguration = featureType.getExtension(TilesConfiguration.class).orElseThrow();
checkPathParameter(extensionRegistry, apiData, definitionPath, "collectionId", collectionId);
checkPathParameter(extensionRegistry, apiData, definitionPath, "tileMatrixSetId", tileMatrixSetId);
checkPathParameter(extensionRegistry, apiData, definitionPath, "tileMatrix", tileMatrix);
checkPathParameter(extensionRegistry, apiData, definitionPath, "tileRow", tileRow);
checkPathParameter(extensionRegistry, apiData, definitionPath, "tileCol", tileCol);
final List<OgcApiQueryParameter> allowedParameters = getQueryParameters(extensionRegistry, apiData, definitionPath, collectionId);
int row;
int col;
int level;
try {
level = Integer.parseInt(tileMatrix);
row = Integer.parseInt(tileRow);
col = Integer.parseInt(tileCol);
} catch (NumberFormatException e) {
throw new ServerErrorException("Could not convert tile coordinates that have been validated to integers", 500);
}
MinMax zoomLevels = tilesConfiguration.getZoomLevelsDerived().get(tileMatrixSetId);
if (zoomLevels.getMax() < level || zoomLevels.getMin() > level)
throw new NotFoundException("The requested tile is outside the zoom levels for this tile set.");
TileMatrixSet tileMatrixSet = tileMatrixSetRepository.get(tileMatrixSetId).orElseThrow(() -> new NotFoundException("Unknown tile matrix set: " + tileMatrixSetId));
TileMatrixSetLimits tileLimits = limitsGenerator.getCollectionTileMatrixSetLimits(api, collectionId, tileMatrixSet, zoomLevels).stream().filter(limits -> limits.getTileMatrix().equals(tileMatrix)).findAny().orElse(null);
if (tileLimits != null) {
if (tileLimits.getMaxTileCol() < col || tileLimits.getMinTileCol() > col || tileLimits.getMaxTileRow() < row || tileLimits.getMinTileRow() > row)
// return 404, if outside the range
throw new NotFoundException("The requested tile is outside of the limits for this zoom level and tile set.");
}
String path = definitionPath.replace("{collectionId}", collectionId).replace("{tileMatrixSetId}", tileMatrixSetId).replace("{tileMatrix}", tileMatrix).replace("{tileRow}", tileRow).replace("{tileCol}", tileCol);
TileFormatExtension outputFormat = requestContext.getApi().getOutputFormat(TileFormatExtension.class, requestContext.getMediaType(), path, Optional.of(collectionId)).orElseThrow(() -> new NotAcceptableException(MessageFormat.format("The requested media type ''{0}'' is not supported for this resource.", requestContext.getMediaType())));
Optional<FeatureProvider2> featureProvider = providers.getFeatureProvider(apiData);
// check, if the cache can be used (no query parameters except f)
boolean useCache = tileProvider.tilesMayBeCached() && tilesConfiguration.getCache() != TilesConfiguration.TileCacheType.NONE && (queryParams.isEmpty() || (queryParams.size() == 1 && queryParams.containsKey("f")));
// don't store the tile in the cache if it is outside the range
MinMax cacheMinMax = tilesConfiguration.getZoomLevelsDerived().get(tileMatrixSetId);
useCache = useCache && (Objects.isNull(cacheMinMax) || (level <= cacheMinMax.getMax() && level >= cacheMinMax.getMin()));
Tile tile = new ImmutableTile.Builder().tileMatrixSet(tileMatrixSet).tileLevel(level).tileRow(row).tileCol(col).api(api).apiData(apiData).outputFormat(outputFormat).featureProvider(featureProvider).collectionIds(ImmutableList.of(collectionId)).temporary(!useCache).isDatasetTile(false).build();
QueryInput queryInput = null;
// if cache can be used and the tile is cached for the requested format, return the cache
if (useCache) {
// get the tile from the cache and return it
Optional<InputStream> tileStream = Optional.empty();
try {
tileStream = cache.getTile(tile);
} catch (Exception e) {
LOGGER.warn("Failed to retrieve tile {}/{}/{}/{} for collection '{}' from the cache. Reason: {}", tile.getTileMatrixSet().getId(), tile.getTileLevel(), tile.getTileRow(), tile.getTileCol(), collectionId, e.getMessage());
}
if (tileStream.isPresent()) {
queryInput = new Builder().from(getGenericQueryInput(apiData)).tile(tile).tileContent(tileStream.get()).build();
}
}
// not cached or cache access failed
if (Objects.isNull(queryInput))
queryInput = tileProvider.getQueryInput(apiData, requestContext.getUriCustomizer(), queryParams, allowedParameters, getGenericQueryInput(apiData), tile);
TilesQueriesHandler.Query query = null;
if (queryInput instanceof TilesQueriesHandler.QueryInputTileMbtilesTile)
query = TilesQueriesHandler.Query.MBTILES_TILE;
else if (queryInput instanceof TilesQueriesHandler.QueryInputTileTileServerTile)
query = TilesQueriesHandler.Query.TILESERVER_TILE;
else if (queryInput instanceof TilesQueriesHandler.QueryInputTileEmpty)
query = TilesQueriesHandler.Query.EMPTY_TILE;
else if (queryInput instanceof TilesQueriesHandler.QueryInputTileStream)
query = TilesQueriesHandler.Query.TILE_STREAM;
else if (queryInput instanceof TilesQueriesHandler.QueryInputTileMultiLayer)
query = TilesQueriesHandler.Query.MULTI_LAYER_TILE;
else if (queryInput instanceof TilesQueriesHandler.QueryInputTileSingleLayer)
query = TilesQueriesHandler.Query.SINGLE_LAYER_TILE;
return queryHandler.handle(query, queryInput, requestContext);
}
use of de.ii.ogcapi.tiles.domain.MinMax in project ldproxy by interactive-instruments.
the class CapabilityTiles method onStartup.
@Override
public ValidationResult onStartup(OgcApi api, MODE apiValidation) {
// since building block / capability components are currently always enabled,
// we need to test, if the TILES module is enabled for the API and stop, if not
OgcApiDataV2 apiData = api.getData();
if (!apiData.getExtension(TilesConfiguration.class).map(ExtensionConfiguration::isEnabled).orElse(false)) {
return ValidationResult.of();
}
try {
SQLiteJDBCLoader.initialize();
} catch (Exception e) {
return ImmutableValidationResult.builder().mode(apiValidation).addStrictErrors(MessageFormat.format("Could not load SQLite: {}", e.getMessage())).build();
}
if (apiValidation == MODE.NONE) {
return ValidationResult.of();
}
ImmutableValidationResult.Builder builder = ImmutableValidationResult.builder().mode(apiValidation);
for (Map.Entry<String, TilesConfiguration> entry : apiData.getCollections().entrySet().stream().filter(entry -> entry.getValue().getEnabled() && entry.getValue().getExtension(TilesConfiguration.class).isPresent()).map(entry -> new AbstractMap.SimpleImmutableEntry<>(entry.getKey(), entry.getValue().getExtension(TilesConfiguration.class).get())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).entrySet()) {
String collectionId = entry.getKey();
TilesConfiguration config = entry.getValue();
Optional<FeatureSchema> schema = providers.getFeatureSchema(apiData, apiData.getCollections().get(collectionId));
List<String> featureProperties = schema.isPresent() ? schemaInfo.getPropertyNames(schema.get(), false, false) : ImmutableList.of();
List<String> formatLabels = extensionRegistry.getExtensionsForType(TileFormatExtension.class).stream().filter(formatExtension -> formatExtension.isEnabledForApi(apiData)).map(format -> format.getMediaType().label()).collect(Collectors.toUnmodifiableList());
List<String> tileEncodings = config.getTileEncodingsDerived();
if (Objects.isNull(tileEncodings)) {
builder.addStrictErrors(MessageFormat.format("No tile encoding has been specified in the TILES module configuration of collection ''{0}''.", collectionId));
} else {
for (String encoding : config.getTileEncodingsDerived()) {
if (!formatLabels.contains(encoding)) {
builder.addStrictErrors(MessageFormat.format("The tile encoding ''{0}'' is specified in the TILES module configuration of collection ''{1}'', but the format does not exist.", encoding, collectionId));
}
}
}
formatLabels = extensionRegistry.getExtensionsForType(TileSetFormatExtension.class).stream().filter(formatExtension -> formatExtension.isEnabledForApi(apiData)).map(format -> format.getMediaType().label()).collect(Collectors.toUnmodifiableList());
for (String encoding : config.getTileSetEncodings()) {
if (!formatLabels.contains(encoding)) {
builder.addStrictErrors(MessageFormat.format("The tile set encoding ''{0}'' is specified in the TILES module configuration of collection ''{1}'', but the format does not exist.", encoding, collectionId));
}
}
List<Double> center = config.getCenterDerived();
if (center.size() != 0 && center.size() != 2)
builder.addStrictErrors(MessageFormat.format("The center has been specified in the TILES module configuration of collection ''{1}'', but the array length is ''{0}'', not 2.", center.size(), collectionId));
Map<String, MinMax> zoomLevels = config.getZoomLevelsDerived();
for (Map.Entry<String, MinMax> entry2 : zoomLevels.entrySet()) {
String tileMatrixSetId = entry2.getKey();
Optional<TileMatrixSet> tileMatrixSet = tileMatrixSetRepository.get(tileMatrixSetId).filter(tms -> config.getTileMatrixSets().contains(tms.getId()));
if (tileMatrixSet.isEmpty()) {
builder.addStrictErrors(MessageFormat.format("The configuration in the TILES module of collection ''{0}'' references a tile matrix set ''{1}'' that is not available in this API.", collectionId, tileMatrixSetId));
} else {
if (tileMatrixSet.get().getMinLevel() > entry2.getValue().getMin()) {
builder.addStrictErrors(MessageFormat.format("The configuration in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' is specified to start at level ''{2}'', but the minimum level of the tile matrix set is ''{3}''.", collectionId, tileMatrixSetId, entry2.getValue().getMin(), tileMatrixSet.get().getMinLevel()));
}
if (tileMatrixSet.get().getMaxLevel() < entry2.getValue().getMax()) {
builder.addStrictErrors(MessageFormat.format("The configuration in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' is specified to end at level ''{2}'', but the maximum level of the tile matrix set is ''{3}''.", collectionId, tileMatrixSetId, entry2.getValue().getMax(), tileMatrixSet.get().getMaxLevel()));
}
if (entry2.getValue().getDefault().isPresent()) {
Integer defaultLevel = entry2.getValue().getDefault().get();
if (defaultLevel < entry2.getValue().getMin() || defaultLevel > entry2.getValue().getMax()) {
builder.addStrictErrors(MessageFormat.format("The configuration in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' specifies a default level ''{2}'' that is outside of the range [ ''{3}'' : ''{4}'' ].", tileMatrixSetId, defaultLevel, entry2.getValue().getMin(), entry2.getValue().getMax()));
}
}
}
}
if (config.getTileProvider() instanceof TileProviderFeatures) {
Map<String, MinMax> zoomLevelsCache = config.getZoomLevelsCacheDerived();
if (Objects.nonNull(zoomLevelsCache)) {
for (Map.Entry<String, MinMax> entry2 : zoomLevelsCache.entrySet()) {
String tileMatrixSetId = entry2.getKey();
MinMax zoomLevelsTms = getZoomLevels(apiData, tileMatrixSetId);
if (Objects.isNull(zoomLevelsTms)) {
builder.addStrictErrors(MessageFormat.format("The cache in the TILES module of collection ''{0}'' references a tile matrix set ''{1}'' that is not configured for this API.", collectionId, tileMatrixSetId));
} else {
if (zoomLevelsTms.getMin() > entry2.getValue().getMin()) {
builder.addStrictErrors(MessageFormat.format("The cache in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' is specified to start at level ''{2}'', but the minimum level is ''{3}''.", collectionId, tileMatrixSetId, entry2.getValue().getMin(), zoomLevelsTms.getMin()));
}
if (zoomLevelsTms.getMax() < entry2.getValue().getMax()) {
builder.addStrictErrors(MessageFormat.format("The cache in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' is specified to end at level ''{2}'', but the maximum level is ''{3}''.", collectionId, tileMatrixSetId, entry2.getValue().getMax(), zoomLevelsTms.getMax()));
}
}
}
}
Map<String, MinMax> seeding = config.getSeedingDerived();
if (Objects.nonNull(seeding)) {
for (Map.Entry<String, MinMax> entry2 : seeding.entrySet()) {
String tileMatrixSetId = entry2.getKey();
MinMax zoomLevelsTms = getZoomLevels(apiData, tileMatrixSetId);
if (Objects.isNull(zoomLevelsTms)) {
builder.addStrictErrors(MessageFormat.format("The seeding in the TILES module of collection ''{0}'' references a tile matrix set ''{1}'' that is not configured for this API.", collectionId, tileMatrixSetId));
} else {
if (zoomLevelsTms.getMin() > entry2.getValue().getMin()) {
builder.addStrictErrors(MessageFormat.format("The seeding in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' is specified to start at level ''{2}'', but the minimum level is ''{3}''.", collectionId, tileMatrixSetId, entry2.getValue().getMin(), zoomLevelsTms.getMin()));
}
if (zoomLevelsTms.getMax() < entry2.getValue().getMax()) {
builder.addStrictErrors(MessageFormat.format("The seeding in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' is specified to end at level ''{2}'', but the maximum level is ''{3}''.", collectionId, tileMatrixSetId, entry2.getValue().getMax(), zoomLevelsTms.getMax()));
}
}
}
}
final Integer limit = Objects.requireNonNullElse(config.getLimitDerived(), 0);
if (limit < 1) {
builder.addStrictErrors(MessageFormat.format("The feature limit in the TILES module must be a positive integer. Found in collection ''{1}'': {0}.", limit, collectionId));
}
final Map<String, List<PredefinedFilter>> filters = config.getFiltersDerived();
if (Objects.nonNull(filters)) {
for (Map.Entry<String, List<PredefinedFilter>> entry2 : filters.entrySet()) {
String tileMatrixSetId = entry2.getKey();
MinMax zoomLevelsCfg = getZoomLevels(apiData, config, tileMatrixSetId);
if (Objects.isNull(zoomLevelsCfg)) {
builder.addStrictErrors(MessageFormat.format("The filters in the TILES module of collection ''{0}'' references a tile matrix set ''{0}'' that is not configured for this API.", collectionId, tileMatrixSetId));
} else {
for (PredefinedFilter filter : entry2.getValue()) {
if (zoomLevelsCfg.getMin() > filter.getMin()) {
builder.addStrictErrors(MessageFormat.format("A filter in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' is specified to start at level ''{2}'', but the minimum level is ''{3}''.", collectionId, tileMatrixSetId, filter.getMin(), zoomLevelsCfg.getMin()));
}
if (zoomLevelsCfg.getMax() < filter.getMax()) {
builder.addStrictErrors(MessageFormat.format("A filter in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' is specified to end at level ''{2}'', but the maximum level is ''{3}''.", collectionId, tileMatrixSetId, filter.getMax(), zoomLevelsCfg.getMax()));
}
if (filter.getFilter().isPresent()) {
// try to convert the filter to CQL2-text
String expression = filter.getFilter().get();
FeatureTypeConfigurationOgcApi collectionData = apiData.getCollections().get(collectionId);
final Map<String, String> filterableFields = queryParser.getFilterableFields(apiData, collectionData);
final Map<String, String> queryableTypes = queryParser.getQueryableTypes(apiData, collectionData);
try {
queryParser.getFilterFromQuery(ImmutableMap.of("filter", expression), filterableFields, ImmutableSet.of("filter"), queryableTypes, Cql.Format.TEXT);
} catch (Exception e) {
builder.addErrors(MessageFormat.format("A filter ''{0}'' in the TILES module of collection ''{1}'' for tile matrix set ''{2}'' is invalid. Reason: {3}", expression, collectionId, tileMatrixSetId, e.getMessage()));
}
}
}
}
}
}
final Map<String, List<Rule>> rules = config.getRulesDerived();
if (Objects.nonNull(rules)) {
for (Map.Entry<String, List<Rule>> entry2 : rules.entrySet()) {
String tileMatrixSetId = entry2.getKey();
MinMax zoomLevelsCfg = getZoomLevels(apiData, config, tileMatrixSetId);
if (Objects.isNull(zoomLevelsCfg)) {
builder.addStrictErrors(MessageFormat.format("The rules in the TILES module of collection ''{0}'' references a tile matrix set ''{0}'' that is not configured for this API.", collectionId, tileMatrixSetId));
} else {
for (Rule rule : entry2.getValue()) {
if (zoomLevelsCfg.getMin() > rule.getMin()) {
builder.addStrictErrors(MessageFormat.format("A rule in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' is specified to start at level ''{2}'', but the minimum level is ''{3}''.", collectionId, tileMatrixSetId, rule.getMin(), zoomLevelsCfg.getMin()));
}
if (zoomLevelsCfg.getMax() < rule.getMax()) {
builder.addStrictErrors(MessageFormat.format("A rule in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' is specified to end at level ''{2}'', but the maximum level is ''{3}''.", collectionId, tileMatrixSetId, rule.getMax(), zoomLevelsCfg.getMax()));
}
for (String property : rule.getProperties()) {
if (!featureProperties.contains(property)) {
builder.addErrors(MessageFormat.format("A rule in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' references property ''{2}'' that is not part of the feature schema.", collectionId, tileMatrixSetId, property));
}
}
for (String property : rule.getGroupBy()) {
if (!featureProperties.contains(property)) {
builder.addErrors(MessageFormat.format("A rule in the TILES module of collection ''{0}'' for tile matrix set ''{1}'' references group-by property ''{2}'' that is not part of the feature schema.", collectionId, tileMatrixSetId, property));
}
}
}
}
}
}
}
}
return builder.build();
}
Aggregations