use of de.ii.ogcapi.foundation.domain.OgcApiDataV2 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.foundation.domain.OgcApiDataV2 in project ldproxy by interactive-instruments.
the class TilesQueriesHandlerImpl method getMultiLayerTileResponse.
private Response getMultiLayerTileResponse(QueryInputTileMultiLayer queryInput, ApiRequestContext requestContext) {
OgcApi api = requestContext.getApi();
OgcApiDataV2 apiData = api.getData();
Tile multiLayerTile = queryInput.getTile();
List<String> collectionIds = multiLayerTile.getCollectionIds();
Map<String, FeatureQuery> queryMap = queryInput.getQueryMap();
Map<String, Tile> singleLayerTileMap = queryInput.getSingleLayerTileMap();
FeatureProvider2 featureProvider = multiLayerTile.getFeatureProvider().get();
TileMatrixSet tileMatrixSet = multiLayerTile.getTileMatrixSet();
int tileLevel = multiLayerTile.getTileLevel();
int tileRow = multiLayerTile.getTileRow();
int tileCol = multiLayerTile.getTileCol();
if (!(multiLayerTile.getOutputFormat() instanceof TileFormatWithQuerySupportExtension))
throw new RuntimeException(String.format("Unexpected tile format without query support. Found: %s", multiLayerTile.getOutputFormat().getClass().getSimpleName()));
TileFormatWithQuerySupportExtension outputFormat = (TileFormatWithQuerySupportExtension) multiLayerTile.getOutputFormat();
// process parameters and generate query
Optional<CrsTransformer> crsTransformer = Optional.empty();
EpsgCrs targetCrs = tileMatrixSet.getCrs();
if (featureProvider.supportsCrs()) {
EpsgCrs sourceCrs = featureProvider.crs().getNativeCrs();
crsTransformer = crsTransformerFactory.getTransformer(sourceCrs, targetCrs);
}
List<Link> links = new DefaultLinksGenerator().generateLinks(requestContext.getUriCustomizer(), requestContext.getMediaType(), requestContext.getAlternateMediaTypes(), i18n, requestContext.getLanguage());
Map<String, ByteArrayOutputStream> byteArrayMap = new HashMap<>();
for (String collectionId : collectionIds) {
// TODO limitation of the current model: all layers have to come from the same feature provider and use the same CRS
Tile tile = singleLayerTileMap.get(collectionId);
if (!multiLayerTile.getTemporary()) {
// use cached tile
try {
Optional<InputStream> tileContent = tileCache.getTile(tile);
if (tileContent.isPresent()) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ByteStreams.copy(tileContent.get(), buffer);
byteArrayMap.put(collectionId, buffer);
continue;
}
} catch (SQLException | IOException e) {
// could not read the cache, generate the tile
}
}
String featureTypeId = apiData.getCollections().get(collectionId).getExtension(FeaturesCoreConfiguration.class).map(cfg -> cfg.getFeatureType().orElse(collectionId)).orElse(collectionId);
FeatureQuery query = queryMap.get(collectionId);
ImmutableFeatureTransformationContextTiles transformationContext;
try {
transformationContext = new ImmutableFeatureTransformationContextTiles.Builder().api(api).apiData(apiData).featureSchema(featureProvider.getData().getTypes().get(featureTypeId)).tile(tile).tileCache(tileCache).collectionId(collectionId).ogcApiRequest(requestContext).crsTransformer(crsTransformer).codelists(entityRegistry.getEntitiesForType(Codelist.class).stream().collect(Collectors.toMap(PersistentEntity::getId, c -> c))).defaultCrs(queryInput.getDefaultCrs()).links(links).isFeatureCollection(true).fields(query.getFields()).limit(query.getLimit()).offset(0).i18n(i18n).outputStream(new OutputStreamToByteConsumer()).build();
} catch (Exception e) {
throw new RuntimeException("Error building the tile transformation context.", e);
}
Optional<FeatureTokenEncoder<?>> encoder = outputFormat.getFeatureEncoder(transformationContext);
if (outputFormat.supportsFeatureQuery() && encoder.isPresent()) {
FeatureStream featureStream = featureProvider.queries().getFeatureStream(query);
ResultReduced<byte[]> result = generateTile(featureStream, encoder.get(), transformationContext, outputFormat);
if (result.isSuccess()) {
byte[] bytes = result.reduced();
ByteArrayOutputStream buffer = new ByteArrayOutputStream(bytes.length);
buffer.write(bytes, 0, bytes.length);
byteArrayMap.put(collectionId, buffer);
}
} else {
throw new NotAcceptableException(MessageFormat.format("The requested media type {0} cannot be generated, because it does not support streaming.", requestContext.getMediaType().type()));
}
}
TileFormatWithQuerySupportExtension.MultiLayerTileContent result;
try {
result = outputFormat.combineSingleLayerTilesToMultiLayerTile(tileMatrixSet, singleLayerTileMap, byteArrayMap);
} catch (IOException e) {
throw new RuntimeException("Error accessing the tile cache.", e);
}
// try to write/update tile in cache, if all collections have been processed
if (result.isComplete) {
try {
tileCache.storeTile(multiLayerTile, result.byteArray);
} catch (Throwable e) {
String msg = "Failure to write the multi-layer file of tile {}/{}/{}/{} in dataset '{}', format '{}' to the cache";
LogContext.errorAsInfo(LOGGER, e, msg, tileMatrixSet.getId(), tileLevel, tileRow, tileCol, api.getId(), outputFormat.getExtension());
}
}
Date lastModified = null;
EntityTag etag = getEtag(result.byteArray);
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_%d_%d_%d.%s", tileMatrixSet.getId(), tileLevel, tileRow, tileCol, outputFormat.getMediaType().fileExtension())).entity(result.byteArray).build();
}
use of de.ii.ogcapi.foundation.domain.OgcApiDataV2 in project ldproxy by interactive-instruments.
the class AbstractEndpointTileSingleCollection method computeDefinition.
protected ApiEndpointDefinition computeDefinition(OgcApiDataV2 apiData, String apiEntrypoint, int sortPriority, String basePath, String subSubPath, List<String> tags) {
ImmutableApiEndpointDefinition.Builder definitionBuilder = new ImmutableApiEndpointDefinition.Builder().apiEntrypoint(apiEntrypoint).sortPriority(sortPriority);
final String path = basePath + subSubPath;
final HttpMethods method = HttpMethods.GET;
final List<OgcApiPathParameter> pathParameters = getPathParameters(extensionRegistry, apiData, path);
final Optional<OgcApiPathParameter> optCollectionIdParam = pathParameters.stream().filter(param -> param.getName().equals("collectionId")).findAny();
if (optCollectionIdParam.isEmpty()) {
LOGGER.error("Path parameter 'collectionId' missing for resource at path '" + path + "'. The GET method will not be available.");
} else {
final OgcApiPathParameter collectionIdParam = optCollectionIdParam.get();
boolean explode = collectionIdParam.getExplodeInOpenApi(apiData);
final List<String> collectionIds = (explode) ? collectionIdParam.getValues(apiData) : ImmutableList.of("{collectionId}");
for (String collectionId : collectionIds) {
List<OgcApiQueryParameter> queryParameters = getQueryParameters(extensionRegistry, apiData, path, collectionId);
String operationSummary = "fetch a tile of the collection '" + collectionId + "'";
Optional<String> operationDescription = Optional.of("The tile in the requested tiling scheme ('{tileMatrixSetId}'), " + "on the requested zoom level ('{tileMatrix}'), with the requested grid coordinates ('{tileRow}', '{tileCol}') is returned. " + "The tile has a single layer with all selected features in the bounding box of the tile with the requested properties.");
String resourcePath = path.replace("{collectionId}", collectionId);
ImmutableOgcApiResourceData.Builder resourceBuilder = new ImmutableOgcApiResourceData.Builder().path(resourcePath).pathParameters(pathParameters);
ApiOperation operation = addOperation(apiData, HttpMethods.GET, queryParameters, collectionId, subSubPath, operationSummary, operationDescription, tags);
if (operation != null)
resourceBuilder.putOperations(method.name(), operation);
definitionBuilder.putResources(resourcePath, resourceBuilder.build());
}
}
return definitionBuilder.build();
}
use of de.ii.ogcapi.foundation.domain.OgcApiDataV2 in project ldproxy by interactive-instruments.
the class EndpointStylesCollection method computeDefinition.
protected ApiEndpointDefinition computeDefinition(OgcApiDataV2 apiData) {
ImmutableApiEndpointDefinition.Builder definitionBuilder = new ImmutableApiEndpointDefinition.Builder().apiEntrypoint("collections").sortPriority(ApiEndpointDefinition.SORT_PRIORITY_STYLES_COLLECTION);
final String subSubPath = "/styles";
final String path = "/collections/{collectionId}" + subSubPath;
final HttpMethods method = HttpMethods.GET;
final List<OgcApiPathParameter> pathParameters = getPathParameters(extensionRegistry, apiData, path);
final Optional<OgcApiPathParameter> optCollectionIdParam = pathParameters.stream().filter(param -> param.getName().equals("collectionId")).findAny();
if (!optCollectionIdParam.isPresent()) {
LOGGER.error("Path parameter 'collectionId' missing for resource at path '" + path + "'. The GET method will not be available.");
} else {
final OgcApiPathParameter collectionIdParam = optCollectionIdParam.get();
boolean explode = collectionIdParam.getExplodeInOpenApi(apiData);
final List<String> collectionIds = (explode) ? collectionIdParam.getValues(apiData) : ImmutableList.of("{collectionId}");
for (String collectionId : collectionIds) {
List<OgcApiQueryParameter> queryParameters = getQueryParameters(extensionRegistry, apiData, path, collectionId);
String operationSummary = "retrieve a list of the available styles for collection `" + collectionId + "`";
Optional<String> operationDescription = Optional.of("This operation fetches the set of styles available for this collection. " + "For each style the id, a title, links to the stylesheet of the style in each supported encoding, " + "and the link to the metadata is provided.");
String resourcePath = path.replace("{collectionId}", collectionId);
ImmutableOgcApiResourceSet.Builder resourceBuilder = new ImmutableOgcApiResourceSet.Builder().path(resourcePath).pathParameters(pathParameters).subResourceType("Style");
ApiOperation operation = addOperation(apiData, HttpMethods.GET, queryParameters, collectionId, subSubPath, operationSummary, operationDescription, TAGS);
if (operation != null)
resourceBuilder.putOperations(method.name(), operation);
definitionBuilder.putResources(resourcePath, resourceBuilder.build());
}
}
return definitionBuilder.build();
}
use of de.ii.ogcapi.foundation.domain.OgcApiDataV2 in project ldproxy by interactive-instruments.
the class EndpointStylesCollection method getStyles.
/**
* fetch all available styles for the service
*
* @return all styles in a JSON styles object or an HTML page
*/
@Path("/{collectionId}/styles")
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_HTML })
public Response getStyles(@Context OgcApi api, @Context ApiRequestContext requestContext, @PathParam("collectionId") String collectionId) {
OgcApiDataV2 apiData = api.getData();
checkPathParameter(extensionRegistry, apiData, "/collections/{collectionId}/styles", "collectionId", collectionId);
checkCollectionExists(apiData, collectionId);
QueriesHandlerStyles.QueryInputStyles queryInput = new Builder().from(getGenericQueryInput(api.getData())).collectionId(collectionId).build();
return queryHandler.handle(QueriesHandlerStyles.Query.STYLES, queryInput, requestContext);
}
Aggregations