Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,7 @@ project(":here-naksha-app-service") {
//implementation(project(":here-naksha-lib-extension"))
implementation(project(":here-naksha-lib-hub"))
implementation(project(":here-naksha-common-http"))
implementation(project(":here-naksha-lib-mom10"))

implementation(log4j_slf4j)
implementation(log4j_api)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,33 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.here.naksha.app.service.http.HttpResponseType;
import com.here.naksha.app.service.http.NakshaHttpVerticle;
import com.here.naksha.app.service.http.tasks.processor.FeaturePostProcessor;
import com.here.naksha.app.service.models.IterateHandle;
import com.here.naksha.lib.core.AbstractTask;
import com.here.naksha.lib.core.INaksha;
import com.here.naksha.lib.core.NakshaContext;
import com.here.naksha.lib.core.exceptions.NoCursor;
import com.here.naksha.lib.core.lambdas.F1;
import com.here.naksha.lib.core.models.XyzError;
import com.here.naksha.lib.core.models.geojson.implementation.XyzFeature;
import com.here.naksha.lib.core.models.geojson.implementation.XyzFeatureCollection;
import com.here.naksha.lib.core.models.geojson.implementation.XyzGeometry;
import com.here.naksha.lib.core.models.payload.XyzResponse;
import com.here.naksha.lib.core.models.storage.*;
import com.here.naksha.lib.core.models.storage.ContextXyzFeatureResult;
import com.here.naksha.lib.core.models.storage.EExecutedOp;
import com.here.naksha.lib.core.models.storage.ErrorResult;
import com.here.naksha.lib.core.models.storage.ReadFeatures;
import com.here.naksha.lib.core.models.storage.Result;
import com.here.naksha.lib.core.models.storage.WriteFeatures;
import com.here.naksha.lib.core.storage.IReadSession;
import com.here.naksha.lib.core.storage.IWriteSession;
import com.here.naksha.lib.core.util.PropertyPathUtil;
import com.here.naksha.lib.core.util.json.Json;
import com.here.naksha.lib.core.util.json.JsonSerializable;
import com.here.naksha.lib.core.view.ViewDeserialize;
import io.vertx.ext.web.RoutingContext;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.util.GeometryFixer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -98,8 +101,10 @@ protected AbstractApiTask(
}

protected <R extends XyzFeature> @NotNull XyzResponse transformReadResultToXyzFeatureResponse(
final @NotNull Result rdResult, final @NotNull Class<R> type, @Nullable F1<R, R> preResponseProcessing) {
return transformResultToXyzFeatureResponse(rdResult, type, NOT_FOUND_ON_NO_ELEMENTS, preResponseProcessing);
final @NotNull Result rdResult,
final @NotNull Class<R> type,
@Nullable FeaturePostProcessor<R> postProcessor) {
return transformResultToXyzFeatureResponse(rdResult, type, NOT_FOUND_ON_NO_ELEMENTS, postProcessor);
}

protected <R extends XyzFeature> @NotNull XyzResponse transformWriteResultToXyzFeatureResponse(
Expand All @@ -108,8 +113,10 @@ protected AbstractApiTask(
}

protected <R extends XyzFeature> @NotNull XyzResponse transformWriteResultToXyzFeatureResponse(
final @Nullable Result wrResult, final @NotNull Class<R> type, @Nullable F1<R, R> preResponseProcessing) {
return transformResultToXyzFeatureResponse(wrResult, type, FAIL_ON_NO_ELEMENTS, preResponseProcessing);
final @Nullable Result wrResult,
final @NotNull Class<R> type,
@Nullable FeaturePostProcessor<R> postProcessor) {
return transformResultToXyzFeatureResponse(wrResult, type, FAIL_ON_NO_ELEMENTS, postProcessor);
}

protected <R extends XyzFeature> @NotNull XyzResponse transformDeleteResultToXyzFeatureResponse(
Expand All @@ -118,8 +125,10 @@ protected AbstractApiTask(
}

protected <R extends XyzFeature> @NotNull XyzResponse transformDeleteResultToXyzFeatureResponse(
final @Nullable Result wrResult, final @NotNull Class<R> type, @Nullable F1<R, R> postProcessing) {
return transformResultToXyzFeatureResponse(wrResult, type, NOT_FOUND_ON_NO_ELEMENTS, postProcessing);
final @Nullable Result wrResult,
final @NotNull Class<R> type,
@Nullable FeaturePostProcessor<R> postProcessor) {
return transformResultToXyzFeatureResponse(wrResult, type, NOT_FOUND_ON_NO_ELEMENTS, postProcessor);
}

protected XyzResponse handleNoElements(NoElementsStrategy noElementsStrategy) {
Expand All @@ -130,16 +139,16 @@ protected XyzResponse handleNoElements(NoElementsStrategy noElementsStrategy) {
final @Nullable Result result,
final @NotNull Class<R> type,
final @NotNull NoElementsStrategy noElementsStrategy,
final @Nullable F1<R, R> preResponseProcessing) {
final @Nullable FeaturePostProcessor<R> postProcessor) {
final XyzResponse validatedErrorResponse = validateErrorResult(result);
if (validatedErrorResponse != null) {
return validatedErrorResponse;
} else {
try {
final R feature = readFeatureFromResult(result, type);
R processedFeature = feature;
if (feature != null && preResponseProcessing != null) {
processedFeature = preResponseProcessing.call(feature);
if (feature != null && postProcessor != null) {
processedFeature = postProcessor.postProcess(feature);
}
if (processedFeature == null) {
return verticle.sendErrorResponse(
Expand All @@ -161,9 +170,9 @@ protected XyzResponse handleNoElements(NoElementsStrategy noElementsStrategy) {
protected <R extends XyzFeature> @NotNull XyzResponse transformReadResultToXyzCollectionResponse(
final @Nullable Result rdResult,
final @NotNull Class<R> type,
final @Nullable F1<R, R> preResponseProcessing) {
final @Nullable FeaturePostProcessor<R> featurePostProcessor) {
return transformReadResultToXyzCollectionResponse(
rdResult, type, 0, DEF_ADMIN_FEATURE_LIMIT, null, preResponseProcessing);
rdResult, type, 0, DEF_ADMIN_FEATURE_LIMIT, null, featurePostProcessor);
}

protected <R extends XyzFeature> @NotNull XyzResponse transformReadResultToXyzCollectionResponse(
Expand All @@ -182,18 +191,18 @@ protected XyzResponse handleNoElements(NoElementsStrategy noElementsStrategy) {
final long offset,
final long maxLimit,
final @Nullable IterateHandle handle,
final @Nullable F1<R, R> preResponseProcessing) {
final @Nullable FeaturePostProcessor<R> featurePostProcessor) {
final XyzResponse validatedErrorResponse = validateErrorResultEmptyCollection(rdResult);
if (validatedErrorResponse != null) {
return validatedErrorResponse;
} else {
try {
final List<R> features = readFeaturesFromResult(rdResult, type, offset, maxLimit);
List<R> processedFeatures = features;
if (preResponseProcessing != null) {
if (featurePostProcessor != null) {
processedFeatures = new ArrayList<>();
for (R feature : features) {
final R processedFeature = preResponseProcessing.call(feature);
final R processedFeature = featurePostProcessor.postProcess(feature);
if (processedFeature != null) {
processedFeatures.add(processedFeature);
}
Expand All @@ -218,7 +227,9 @@ protected XyzResponse handleNoElements(NoElementsStrategy noElementsStrategy) {
private static String getIterateHandleAsString(
long featuresFound, long crtOffset, long maxLimit, final @Nullable IterateHandle handle) {
// nothing to populate if handle is not provided OR if we don't have more features to iterate
if (handle == null || featuresFound < maxLimit) return null;
if (handle == null || featuresFound < maxLimit) {
return null;
}
handle.setOffset(crtOffset + featuresFound); // set offset for next iteration
handle.setLimit(maxLimit);
return handle.base64EncodedSerializedJson();
Expand Down Expand Up @@ -309,38 +320,4 @@ XyzFeatureCollection emptyFeatureCollection() {
return json.reader(ViewDeserialize.User.class).forType(type).readValue(bodyJson);
}
}

protected <F extends XyzFeature> @Nullable F1<F, F> standardReadFeaturesPreResponseProcessing(
final @Nullable Set<String> propPaths, final boolean clip, final Geometry clipGeo) {
if (propPaths == null && !clip) return null;
return f -> {
F newF = f;
// Apply prop selection if enabled
if (propPaths != null) newF = applyPropertySelection(newF, propPaths);
// Apply geometry clipping if enabled
if (clip) applyGeometryClipping(newF, clipGeo);
return newF;
};
}

@SuppressWarnings("unchecked")
private <F extends XyzFeature> @NotNull F applyPropertySelection(
final @NotNull F f, final @NotNull Set<String> propPaths) {
final Map<String, Object> tgtMap = PropertyPathUtil.extractPropertyMapFromFeature(f, propPaths);
return (F) JsonSerializable.fromMap(tgtMap, f.getClass());
}

private <F extends XyzFeature> void applyGeometryClipping(final @NotNull F f, final Geometry clipGeo) {
// clip Feature geometry (if present) to a given clipGeo geometry
final XyzGeometry xyzGeo = f.getGeometry();
if (xyzGeo != null) {
// NOTE - in JTS when we say:
// GeometryFixer.fix(geom).intersection(bbox)
// it is the best available way of clipping geometry, equivalent to PostGIS approach of:
// ST_Intersection(ST_MakeValid(geo, 'method=structure'), bbox)
final Geometry clippedGeo =
GeometryFixer.fix(xyzGeo.getJTSGeometry()).intersection(clipGeo);
f.setGeometry(XyzGeometry.convertJTSGeometry(clippedGeo));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@
*/
package com.here.naksha.app.service.http.tasks;

import static com.here.naksha.app.service.http.ops.MaskingUtil.maskProperties;
import static com.here.naksha.common.http.apis.ApiParamsConst.HANDLER_ID;
import static com.here.naksha.lib.core.NakshaAdminCollection.EVENT_HANDLERS;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.here.naksha.app.service.http.NakshaHttpVerticle;
import com.here.naksha.app.service.http.apis.ApiParams;
import com.here.naksha.app.service.http.tasks.processor.FeaturePostProcessor;
import com.here.naksha.app.service.http.tasks.processor.MaskingPostProcessor;
import com.here.naksha.lib.core.INaksha;
import com.here.naksha.lib.core.NakshaContext;
import com.here.naksha.lib.core.exceptions.XyzErrorException;
Expand All @@ -47,6 +48,7 @@
public class EventHandlerApiTask<T extends XyzResponse> extends AbstractApiTask<XyzResponse> {

private static final Logger logger = LoggerFactory.getLogger(EventHandlerApiTask.class);
private static final FeaturePostProcessor<EventHandler> HANDLER_MASKING = new MaskingPostProcessor<>();

private final @NotNull EventHandlerApiReqType reqType;

Expand Down Expand Up @@ -107,8 +109,7 @@ protected void init() {}
// Submit request to NH Space Storage
try (Result rdResult = executeReadRequestFromSpaceStorage(request)) {
// transform ReadResult to Http FeatureCollection response
return transformReadResultToXyzCollectionResponse(
rdResult, EventHandler.class, this::handlerWithMaskedSensitiveProperties);
return transformReadResultToXyzCollectionResponse(rdResult, EventHandler.class, HANDLER_MASKING);
}
}

Expand Down Expand Up @@ -136,33 +137,25 @@ protected void init() {}
final String handlerId = ApiParams.extractMandatoryPathParam(routingContext, HANDLER_ID);
final WriteXyzFeatures wrRequest = RequestHelper.deleteFeatureByIdRequest(EVENT_HANDLERS, handlerId);
try (Result wrResult = executeWriteRequestFromSpaceStorage(wrRequest)) {
return transformDeleteResultToXyzFeatureResponse(
wrResult, EventHandler.class, this::handlerWithMaskedSensitiveProperties);
return transformDeleteResultToXyzFeatureResponse(wrResult, EventHandler.class, HANDLER_MASKING);
}
}

@NotNull
private XyzResponse transformResponseFor(ReadFeatures rdRequest) {
try (Result rdResult = executeReadRequestFromSpaceStorage(rdRequest)) {
return transformReadResultToXyzFeatureResponse(
rdResult, EventHandler.class, this::handlerWithMaskedSensitiveProperties);
return transformReadResultToXyzFeatureResponse(rdResult, EventHandler.class, HANDLER_MASKING);
}
}

@NotNull
private XyzResponse transformResponseFor(WriteXyzFeatures updateHandlerReq) {
// persist new handler in Admin DB (if doesn't exist already)
try (Result updateHandlerResult = executeWriteRequestFromSpaceStorage(updateHandlerReq)) {
return transformWriteResultToXyzFeatureResponse(
updateHandlerResult, EventHandler.class, this::handlerWithMaskedSensitiveProperties);
return transformWriteResultToXyzFeatureResponse(updateHandlerResult, EventHandler.class, HANDLER_MASKING);
}
}

private EventHandler handlerWithMaskedSensitiveProperties(EventHandler handler) {
maskProperties(handler);
return handler;
}

private @NotNull EventHandler handlerFromRequestBody() throws JsonProcessingException {
try (final Json json = Json.get()) {
final String bodyJson = routingContext.body().asString();
Expand Down
Loading
Loading