use of de.ii.xtraplatform.store.domain.entities.EntityRegistry 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.xtraplatform.store.domain.entities.EntityRegistry 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.xtraplatform.store.domain.entities.EntityRegistry in project ldproxy by interactive-instruments.
the class TilesQueriesHandlerImpl method getTileSetsResponse.
private Response getTileSetsResponse(QueryInputTileSets queryInput, ApiRequestContext requestContext) {
OgcApi api = requestContext.getApi();
OgcApiDataV2 apiData = api.getData();
Optional<String> collectionId = queryInput.getCollectionId();
String definitionPath = queryInput.getPath();
String path = collectionId.map(value -> definitionPath.replace("{collectionId}", value)).orElse(definitionPath);
boolean onlyWebMercatorQuad = queryInput.getOnlyWebMercatorQuad();
TileSetsFormatExtension outputFormat = api.getOutputFormat(TileSetsFormatExtension.class, requestContext.getMediaType(), path, collectionId).orElseThrow(() -> new NotAcceptableException(MessageFormat.format("The requested media type ''{0}'' is not supported for this resource.", requestContext.getMediaType())));
final TilesLinkGenerator tilesLinkGenerator = new TilesLinkGenerator();
Optional<FeatureTypeConfigurationOgcApi> featureType = collectionId.map(s -> apiData.getCollections().get(s));
Map<String, MinMax> tileMatrixSetZoomLevels = queryInput.getTileMatrixSetZoomLevels();
List<Double> center = queryInput.getCenter();
List<TileFormatExtension> tileFormats = extensionRegistry.getExtensionsForType(TileFormatExtension.class).stream().filter(format -> collectionId.map(s -> format.isApplicable(apiData, s, definitionPath)).orElseGet(() -> format.isApplicable(apiData, definitionPath))).sorted(Comparator.comparing(format -> queryInput.getTileEncodings().indexOf(format.getMediaType().label()))).collect(Collectors.toUnmodifiableList());
Optional<DataType> dataType = tileFormats.stream().map(TileFormatExtension::getDataType).findAny();
List<Link> links = tilesLinkGenerator.generateTileSetsLinks(requestContext.getUriCustomizer(), requestContext.getMediaType(), requestContext.getAlternateMediaTypes(), tileFormats, i18n, requestContext.getLanguage());
Builder builder = ImmutableTileSets.builder().title(featureType.isPresent() ? featureType.get().getLabel() : apiData.getLabel()).description(featureType.map(ft -> ft.getDescription().orElse("")).orElseGet(() -> apiData.getDescription().orElse(""))).links(links);
List<TileMatrixSet> tileMatrixSets = tileMatrixSetZoomLevels.keySet().stream().map(this::getTileMatrixSetById).filter(tileMatrixSet -> !onlyWebMercatorQuad || tileMatrixSet.getId().equals("WebMercatorQuad")).collect(Collectors.toUnmodifiableList());
dataType.ifPresent(type -> builder.tilesets(tileMatrixSets.stream().map(tileMatrixSet -> TilesHelper.buildTileSet(api, tileMatrixSet, tileMatrixSetZoomLevels.get(tileMatrixSet.getId()), center, collectionId, type, tilesLinkGenerator.generateTileSetEmbeddedLinks(requestContext.getUriCustomizer(), tileMatrixSet.getId(), tileFormats, i18n, requestContext.getLanguage()), Optional.of(requestContext.getUriCustomizer().copy()), crsTransformerFactory, limitsGenerator, providers, entityRegistry)).collect(Collectors.toUnmodifiableList())));
TileSets tileSets = builder.build();
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(tileSets, TileSets.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("tilesets.%s", outputFormat.getMediaType().fileExtension())).entity(outputFormat.getTileSetsEntity(tileSets, collectionId, api, requestContext)).build();
}
use of de.ii.xtraplatform.store.domain.entities.EntityRegistry in project ldproxy by interactive-instruments.
the class MbStyleStylesheet method getLayerMetadata.
// TODO: replace with SchemaDeriverStyleLayer
@JsonIgnore
public List<StyleLayer> getLayerMetadata(OgcApiDataV2 apiData, FeaturesCoreProviders providers, EntityRegistry entityRegistry) {
// prepare a map with the JSON schemas of the feature collections used in the style
JsonSchemaCache schemas = new SchemaCacheStyleLayer(() -> entityRegistry.getEntitiesForType(Codelist.class));
Map<String, JsonSchemaObject> schemaMap = getLayers().stream().filter(layer -> layer.getSource().isPresent() && layer.getSource().get().equals(apiData.getId())).map(layer -> layer.getSourceLayer()).filter(Optional::isPresent).map(Optional::get).distinct().filter(sourceLayer -> apiData.getCollections().containsKey(sourceLayer)).map(collectionId -> {
Optional<FeatureSchema> schema = providers.getFeatureSchema(apiData, apiData.getCollections().get(collectionId));
if (schema.isEmpty())
return null;
return new AbstractMap.SimpleImmutableEntry<>(collectionId, schemas.getSchema(schema.get(), apiData, apiData.getCollections().get(collectionId), Optional.empty()));
}).filter(Objects::nonNull).collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
return getLayers().stream().map(layer -> {
ImmutableStyleLayer.Builder builder = ImmutableStyleLayer.builder().id(layer.getId());
Map<String, Object> md = layer.getMetadata();
if (md.containsKey("description"))
builder.description(md.get("description").toString());
Optional<String> apiId = layer.getSource();
Optional<String> collectionId = layer.getSourceLayer();
final boolean knownSource = apiId.isPresent() && apiId.get().equals(apiData.getId()) && collectionId.isPresent() && schemaMap.containsKey(collectionId.get());
final JsonSchema geometry = knownSource ? schemaMap.get(collectionId.get()).getProperties().get("geometry") : null;
final JsonSchemaObject properties = knownSource ? (JsonSchemaObject) schemaMap.get(collectionId.get()).getProperties().get("properties") : null;
ImmutableSet.Builder<String> attNamesBuilder = ImmutableSet.builder();
attNamesBuilder.addAll(getAttributes(layer.getFilter()));
layer.getLayout().values().forEach(value -> attNamesBuilder.addAll(getAttributes(value)));
layer.getPaint().values().forEach(value -> attNamesBuilder.addAll(getAttributes(value)));
Set<String> attNames = attNamesBuilder.build();
builder.attributes(attNames.stream().sorted().map(attName -> {
if (Objects.nonNull(properties)) {
if (properties.getProperties().containsKey(attName))
return new AbstractMap.SimpleImmutableEntry<>(attName, properties.getProperties().get(attName));
return properties.getPatternProperties().entrySet().stream().filter(entry -> attName.matches(entry.getKey())).map(entry -> new AbstractMap.SimpleImmutableEntry<>(attName, entry.getValue())).findAny().orElse(null);
}
return null;
}).filter(Objects::nonNull).collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)));
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)
builder.type("point");
else if (!point && line && !polygon)
builder.type("line");
else if (!point && !line && polygon)
builder.type("polygon");
else
builder.type("geometry");
} else if (layer.getType().matches("fill|line|symbol|fill\\-extrusion")) {
builder.type("geometry");
} else if (layer.getType().equals("circle")) {
builder.type("point");
} else if (layer.getType().equals("raster")) {
builder.type("raster");
}
if (knownSource) {
builder.sampleData(new ImmutableLink.Builder().rel("start").title("").href(String.format("{serviceUrl}/collections/%s/items", collectionId.get())).templated(true).build());
}
return builder.build();
}).collect(Collectors.toUnmodifiableList());
}
use of de.ii.xtraplatform.store.domain.entities.EntityRegistry in project ldproxy by interactive-instruments.
the class StyleRepositoryFiles method getStyleMetadata.
@Override
public StyleMetadata getStyleMetadata(OgcApiDataV2 apiData, Optional<String> collectionId, String styleId, ApiRequestContext requestContext) {
if (getStylesheetMediaTypes(apiData, collectionId, styleId, true, false).isEmpty()) {
if (collectionId.isEmpty())
throw new NotFoundException(MessageFormat.format("The style ''{0}'' does not exist in this API.", styleId));
throw new NotFoundException(MessageFormat.format("The style ''{0}'' does not exist in this API for collection ''{1}''.", styleId, collectionId.get()));
}
// derive standard links (self/alternate)
List<Link> links = defaultLinkGenerator.generateLinks(requestContext.getUriCustomizer(), requestContext.getMediaType(), requestContext.getAlternateMediaTypes(), i18n, requestContext.getLanguage());
// Derive standard metadata from the style
// TODO move outside of this specific repository implementation
List<StylesheetMetadata> stylesheets = deriveStylesheetMetadata(apiData, collectionId, styleId, requestContext);
Optional<String> title = getTitle(apiData, collectionId, styleId, requestContext);
Optional<StyleFormatExtension> format = getStyleFormatStream(apiData, collectionId).filter(f -> f.canDeriveMetadata()).filter(f -> stylesheetExists(apiData, collectionId, styleId, f, true)).findAny();
ImmutableStyleMetadata.Builder builder = ImmutableStyleMetadata.builder().id(Optional.ofNullable(styleId)).title(title.orElse(styleId)).stylesheets(stylesheets);
if (format.isPresent()) {
builder.layers(format.get().deriveLayerMetadata(getStylesheet(apiData, collectionId, styleId, format.get(), requestContext, true), apiData, providers, entityRegistry));
}
StyleMetadata metadata = builder.build();
Optional<JsonMergePatch> patch = getStyleMetadataPatch(apiData, collectionId, styleId);
if (patch.isEmpty() && collectionId.isPresent() && deriveCollectionStylesEnabled(apiData, collectionId.get())) {
patch = getStyleMetadataPatch(apiData, Optional.empty(), styleId);
}
if (patch.isPresent()) {
try {
metadata = metadataMapper.treeToValue(patch.get().apply(metadataMapper.valueToTree(metadata)), StyleMetadata.class);
} catch (JsonProcessingException | JsonPatchException e) {
if (collectionId.isPresent())
throw new InternalServerErrorException(MessageFormat.format("Style metadata file in styles store is invalid for style ''{0}'' in collection ''{1}'' in API ''{2}''.", styleId, collectionId.get(), apiData.getId()), e);
throw new InternalServerErrorException(MessageFormat.format("Style metadata file in styles store is invalid for style ''{0}'' in API ''{1}''.", styleId, apiData.getId()), e);
}
}
metadata = ImmutableStyleMetadata.builder().from(metadata).addAllLinks(links).build();
URICustomizer uriCustomizer = new URICustomizer(servicesUri).ensureLastPathSegments(apiData.getSubPath().toArray(String[]::new));
String serviceUrl = uriCustomizer.toString();
return metadata.replaceParameters(serviceUrl);
}
Aggregations