Skip to content

Commit

Permalink
move common functionality of expanding feature id wildcard to ThingFi…
Browse files Browse the repository at this point in the history
…eldSelector class and adapt code where the functionality is used

Signed-off-by: Dominik Guggemos <dominik.guggemos@bosch.io>
  • Loading branch information
dguggemos committed Jan 14, 2022
1 parent a37f6e9 commit 57fcf5c
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 209 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,15 @@
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.Nullable;

import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonFieldSelector;
import org.eclipse.ditto.json.JsonKey;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonPointer;
import org.eclipse.ditto.json.JsonValue;
import org.eclipse.ditto.things.model.Thing;
import org.eclipse.ditto.things.model.ThingFieldSelector;
import org.eclipse.ditto.things.model.ThingId;
import org.eclipse.ditto.things.model.signals.events.ThingEvent;

Expand Down Expand Up @@ -59,33 +56,11 @@ default JsonObject applyJsonFieldSelector(final JsonObject jsonObject,
.map(JsonValue::asObject)
.map(JsonObject::getKeys)
.orElse(Collections.emptyList());
final JsonFieldSelector jsonPointers = expandFeatureIdWildcard(fieldSelector, featureIds);
result = jsonObject.get(jsonPointers);
final JsonFieldSelector expandedSelector =
ThingFieldSelector.fromJsonFieldSelector(fieldSelector).expandFeatureIdWildcards(featureIds);
result = jsonObject.get(expandedSelector);
}

return result;
}

private static JsonFieldSelector expandFeatureIdWildcard(final JsonFieldSelector fieldSelector,
final Collection<JsonKey> featureIds) {

final List<JsonPointer> jsonPointerList = fieldSelector.getPointers().stream()
.flatMap(jsonPointer -> {
if (jsonPointer.getLevelCount() > 1
&& jsonPointer.getRoot()
.map(k -> Thing.JsonFields.FEATURES.getPointer().equals(JsonPointer.of(k)))
.orElse(false)
&& jsonPointer.get(1).map(k -> JsonKey.of("*").equals(k)).orElse(false)) {
return featureIds.stream()
.map(fid -> Thing.JsonFields.FEATURES.getPointer()
.append(JsonPointer.of(fid))
.append(jsonPointer.getSubPointer(2).orElse(JsonPointer.empty())));
} else {
return Stream.of(jsonPointer);
}
}).collect(Collectors.toList());

return JsonFactory.newFieldSelector(jsonPointerList);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@
package org.eclipse.ditto.things.model;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonFieldSelector;
import org.eclipse.ditto.json.JsonKey;
import org.eclipse.ditto.json.JsonParseOptions;
import org.eclipse.ditto.json.JsonPointer;

Expand All @@ -32,6 +36,8 @@
*/
public final class ThingFieldSelector implements JsonFieldSelector {

public static final JsonKey FEATURE_ID_WILDCARD = JsonKey.of("*");

private static final JsonParseOptions JSON_PARSE_OPTIONS = JsonParseOptions.newBuilder()
.withoutUrlDecoding()
.build();
Expand Down Expand Up @@ -88,6 +94,37 @@ public static ThingFieldSelector fromString(final String selectionString) {
throw InvalidThingFieldSelectionException.forExtraFieldSelectionString(selectionString);
}

public JsonFieldSelector expandFeatureIdWildcards(final Features features) {
final Collection<JsonKey> featureIds =
features.stream().map(Feature::getId).map(JsonKey::of).collect(Collectors.toList());
return expandFeatureIdWildcards(featureIds);
}

public JsonFieldSelector expandFeatureIdWildcards(final Collection<JsonKey> featureIds) {
final List<JsonPointer> jsonPointerList = jsonFieldSelector.getPointers().stream()
.flatMap(jsonPointer -> expandFeatureIdWildcard(featureIds, jsonPointer)).collect(Collectors.toList());
return JsonFactory.newFieldSelector(jsonPointerList);
}

private Stream<JsonPointer> expandFeatureIdWildcard(final Collection<JsonKey> featureIds,
final JsonPointer jsonPointer) {
if (hasFeatureIdWildcard(jsonPointer)) {
return featureIds.stream().map(fid -> Thing.JsonFields.FEATURES.getPointer()
.append(JsonPointer.of(fid))
.append(jsonPointer.getSubPointer(2).orElse(JsonPointer.empty())));
} else {
return Stream.of(jsonPointer);
}
}

private boolean hasFeatureIdWildcard(final JsonPointer pointer) {
return pointer.getLevelCount() > 1
&& pointer.getRoot()
.filter(root -> Thing.JsonFields.FEATURES.getPointer().equals(JsonPointer.of(root)))
.isPresent()
&& pointer.get(1).filter(FEATURE_ID_WILDCARD::equals).isPresent();
}

/**
* Returns the underlying JsonFieldSelector.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,32 @@ public void fromJsonFieldSelectorWithThingFieldSelectorReturnsSameInstance() {
assertThat(result).isSameAs(initial);
}

private static final Features FEATURES = Features.newBuilder()
.set(Feature.newBuilder().withId("f1").build())
.set(Feature.newBuilder().withId("f2").build())
.build();

@Test
public void testExpandFeatureIdWildcard() {
final JsonFieldSelector fieldSelector = JsonFieldSelector.newInstance("thingId",
"attributes", "features/*/properties/connected");
final JsonFieldSelector expected = JsonFieldSelector.newInstance("thingId",
"attributes", "features/f1/properties/connected", "features/f2/properties/connected");

final JsonFieldSelector expanded =
ThingFieldSelector.fromJsonFieldSelector(fieldSelector).expandFeatureIdWildcards(FEATURES);
assertThat(expanded).containsExactlyInAnyOrderElementsOf(expected);
}

@Test
public void testExpandFeatureIdWithoutWildcard() {
final JsonFieldSelector fieldSelector = JsonFieldSelector.newInstance("thingId",
"attributes", "features/f1/properties/a", "features/f2/properties/b", "features/f3" +
"/properties/c");

final JsonFieldSelector expanded =
ThingFieldSelector.fromJsonFieldSelector(fieldSelector).expandFeatureIdWildcards(FEATURES);
assertThat(expanded).containsExactlyInAnyOrderElementsOf(fieldSelector);
}

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
*/
package org.eclipse.ditto.things.service.persistence.actors.strategies.commands;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
Expand All @@ -22,11 +24,13 @@
import org.eclipse.ditto.base.model.headers.entitytag.EntityTag;
import org.eclipse.ditto.internal.utils.persistentactors.results.Result;
import org.eclipse.ditto.internal.utils.persistentactors.results.ResultFactory;
import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonFieldSelector;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonPointer;
import org.eclipse.ditto.things.model.Features;
import org.eclipse.ditto.things.model.Thing;
import org.eclipse.ditto.things.model.ThingFieldSelector;
import org.eclipse.ditto.things.model.ThingId;
import org.eclipse.ditto.things.model.signals.commands.query.RetrieveFeatures;
import org.eclipse.ditto.things.model.signals.commands.query.RetrieveFeaturesResponse;
Expand All @@ -36,7 +40,7 @@
* This strategy handles the {@link org.eclipse.ditto.things.model.signals.commands.query.RetrieveFeatures} command.
*/
@Immutable
final class RetrieveFeaturesStrategy extends AbstractRetrieveThingCommandStrategy<RetrieveFeatures> {
final class RetrieveFeaturesStrategy extends AbstractThingCommandStrategy<RetrieveFeatures> {

/**
* Constructs a new {@code RetrieveFeaturesStrategy} object.
Expand Down Expand Up @@ -64,20 +68,38 @@ protected Result<ThingEvent<?>> doApply(final Context<ThingId> context,
.newErrorResult(ExceptionFactory.featuresNotFound(thingId, dittoHeaders), command));
}

private Optional<Features> extractFeatures(final @Nullable Thing thing) {
private Optional<Features> extractFeatures(@Nullable final Thing thing) {
return getEntityOrThrow(thing).getFeatures();
}

private static JsonObject getFeaturesJson(final Features features, final RetrieveFeatures command) {
return command.getSelectedFields()
.map(selectedFields -> {
final JsonFieldSelector expandedFieldSelector =
expandFeatureIdWildcard(selectedFields, JsonPointer.empty(), features);
final JsonFieldSelector expandedFieldSelector = expandFeatureIdWildcard(selectedFields, features);
return features.toJson(command.getImplementedSchemaVersion(), expandedFieldSelector);
})
.orElseGet(() -> features.toJson(command.getImplementedSchemaVersion()));
}

private static JsonFieldSelector expandFeatureIdWildcard(final JsonFieldSelector selectedFields,
final Features features) {
// add /features level for expansion
final List<JsonPointer> normalized = selectedFields.getPointers()
.stream()
.map(selector -> Thing.JsonFields.FEATURES.getPointer().append(selector))
.collect(Collectors.toList());
final JsonFieldSelector expandedPointers =
ThingFieldSelector.fromJsonFieldSelector(JsonFactory.newFieldSelector(normalized))
.expandFeatureIdWildcards(features);
// and remove it again because field selectors are relative to /features
final List<JsonPointer> denormalized =
expandedPointers.getPointers()
.stream()
.map(p -> p.getSubPointer(1).orElse(JsonPointer.empty()))
.collect(Collectors.toList());
return JsonFactory.newFieldSelector(denormalized);
}

@Override
public Optional<EntityTag> previousEntityTag(final RetrieveFeatures command, @Nullable final Thing previousEntity) {
return nextEntityTag(command, previousEntity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import org.eclipse.ditto.internal.utils.persistentactors.results.ResultFactory;
import org.eclipse.ditto.json.JsonFieldSelector;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.things.model.Features;
import org.eclipse.ditto.things.model.Thing;
import org.eclipse.ditto.things.model.ThingFieldSelector;
import org.eclipse.ditto.things.model.ThingId;
import org.eclipse.ditto.things.model.ThingsModelFactory;
import org.eclipse.ditto.things.model.signals.commands.exceptions.ThingNotAccessibleException;
Expand All @@ -38,7 +40,7 @@
* This strategy handles the {@link RetrieveThing} command.
*/
@Immutable
final class RetrieveThingStrategy extends AbstractRetrieveThingCommandStrategy<RetrieveThing> {
final class RetrieveThingStrategy extends AbstractThingCommandStrategy<RetrieveThing> {

/**
* Constructs a new {@code RetrieveThingStrategy} object.
Expand Down Expand Up @@ -83,9 +85,9 @@ private static DittoHeadersSettable<?> getRetrieveThingResponse(@Nullable final
private static JsonObject getThingJson(final Thing thing, final ThingQueryCommand<RetrieveThing> command) {
return command.getSelectedFields()
.map(selectedFields -> {
final JsonFieldSelector expandedFieldSelector = expandFeatureIdWildcard(selectedFields,
Thing.JsonFields.FEATURES.getPointer(),
thing.getFeatures().orElse(ThingsModelFactory.emptyFeatures()));
final Features features = thing.getFeatures().orElse(ThingsModelFactory.emptyFeatures());
final JsonFieldSelector expandedFieldSelector =
ThingFieldSelector.fromJsonFieldSelector(selectedFields).expandFeatureIdWildcards(features);
return thing.toJson(command.getImplementedSchemaVersion(), expandedFieldSelector);
})
.orElseGet(() -> thing.toJson(command.getImplementedSchemaVersion()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.things.api.commands.sudo.SudoRetrieveThing;
import org.eclipse.ditto.things.api.commands.sudo.SudoRetrieveThingResponse;
import org.eclipse.ditto.things.model.Features;
import org.eclipse.ditto.things.model.Thing;
import org.eclipse.ditto.things.model.ThingFieldSelector;
import org.eclipse.ditto.things.model.ThingId;
import org.eclipse.ditto.things.model.ThingsModelFactory;
import org.eclipse.ditto.things.model.signals.commands.exceptions.ThingNotAccessibleException;
Expand All @@ -38,7 +40,7 @@
* This strategy handles the {@link SudoRetrieveThing} command.
*/
@Immutable
final class SudoRetrieveThingStrategy extends AbstractRetrieveThingCommandStrategy<SudoRetrieveThing> {
final class SudoRetrieveThingStrategy extends AbstractThingCommandStrategy<SudoRetrieveThing> {

/**
* Constructs a new {@code SudoRetrieveThingStrategy} object.
Expand Down Expand Up @@ -71,9 +73,9 @@ protected Result<ThingEvent<?>> doApply(final Context<ThingId> context,
final JsonSchemaVersion jsonSchemaVersion = determineSchemaVersion(command, theThing);
final JsonObject thingJson = command.getSelectedFields()
.map(selectedFields -> {
final JsonFieldSelector expandedFieldSelector = expandFeatureIdWildcard(selectedFields,
Thing.JsonFields.FEATURES.getPointer(),
thing.getFeatures().orElse(ThingsModelFactory.emptyFeatures()));
final Features features = thing.getFeatures().orElse(ThingsModelFactory.emptyFeatures());
final JsonFieldSelector expandedFieldSelector =
ThingFieldSelector.fromJsonFieldSelector(selectedFields).expandFeatureIdWildcards(features);
return theThing.toJson(jsonSchemaVersion, expandedFieldSelector, FieldType.regularOrSpecial());
})
.orElseGet(() -> theThing.toJson(jsonSchemaVersion, FieldType.regularOrSpecial()));
Expand Down
Loading

0 comments on commit 57fcf5c

Please sign in to comment.