Skip to content

Commit

Permalink
fix resolving WoT submodels from extended model
Browse files Browse the repository at this point in the history
* right now Ditto `tm:extends` resolving does not preserve the "extended" submodels from a parent model because merging of arrays will replace array content
* this provides a fix to add special handling for merging the "links" array
  • Loading branch information
thjaeckle committed Nov 26, 2024
1 parent b35d77e commit f85e8b9
Showing 1 changed file with 45 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
import static org.eclipse.ditto.base.model.common.ConditionChecker.checkNotNull;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.stream.Stream;

import org.eclipse.ditto.base.model.headers.DittoHeaders;
import org.eclipse.ditto.json.JsonCollectors;
Expand All @@ -28,7 +30,9 @@
import org.eclipse.ditto.json.JsonPointer;
import org.eclipse.ditto.json.JsonValue;
import org.eclipse.ditto.wot.api.provider.WotThingModelFetcher;
import org.eclipse.ditto.wot.model.BaseLink;
import org.eclipse.ditto.wot.model.IRI;
import org.eclipse.ditto.wot.model.Links;
import org.eclipse.ditto.wot.model.ThingModel;
import org.eclipse.ditto.wot.model.WotThingModelRefInvalidException;

Expand Down Expand Up @@ -73,7 +77,7 @@ public CompletionStage<ThingModel> resolveThingModelExtensions(final ThingModel
return CompletableFuture.completedFuture(thingModel);
} else {
CompletionStage<ThingModel.Builder> currentStage =
resolveThingModelExtensions(extendedModels.get(0), dittoHeaders) // recurse!
resolveThingModelExtensions(extendedModels.getFirst(), dittoHeaders) // recurse!
.thenApply(extendedModel ->
mergeThingModelIntoBuilder().apply(tmBuilder, extendedModel)
);
Expand All @@ -91,13 +95,52 @@ public CompletionStage<ThingModel> resolveThingModelExtensions(final ThingModel

private BiFunction<ThingModel.Builder, ThingModel, ThingModel.Builder> mergeThingModelIntoBuilder() {
return (builder, model) -> {
final JsonObject mergedTmObject = JsonFactory.mergeJsonValues(builder.build(), model).asObject();
final ThingModel newModel = builder.build();
final JsonObject mergedTmObject = JsonFactory.mergeJsonValues(newModel, model).asObject();
builder.removeAll();
builder.setAll(mergedTmObject);
mergeLinks(model.getLinks(), newModel.getLinks()).ifPresent(builder::setLinks);
return builder;
};
}

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private static Optional<Links> mergeLinks(final Optional<Links> oldOptionalLinks,
final Optional<Links> newOptionalLinks)
{
return oldOptionalLinks
.map(oldLinks -> filterOutTmExtendsLinkFromOldLinks(newOptionalLinks, oldLinks))
.map(adjustedOldLinks ->
newOptionalLinks.stream()
.flatMap(newLinks -> Stream.concat(adjustedOldLinks, newLinks.stream()))
)
.map(Stream::toList)
.map(Links::of);
}

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private static Stream<BaseLink<?>> filterOutTmExtendsLinkFromOldLinks(final Optional<Links> newOptionalLinks,
final Links oldLinks)
{
return oldLinks.stream()
.filter(oldLink -> {
if (isTmExtendsLink(oldLink)) {
return newOptionalLinks.filter(DefaultWotThingModelExtensionResolver::containsTmExtendsLink)
.isEmpty();
} else {
return true;
}
});
}

private static boolean containsTmExtendsLink(final Links links) {
return links.stream().anyMatch(DefaultWotThingModelExtensionResolver::isTmExtendsLink);
}

private static boolean isTmExtendsLink(final BaseLink<?> link) {
return link.getRel().isPresent() && link.getRel().filter(TM_EXTENDS::equals).isPresent();
}

@Override
public CompletionStage<ThingModel> resolveThingModelRefs(final ThingModel thingModel, final DittoHeaders dittoHeaders) {
return potentiallyResolveRefs(thingModel, dittoHeaders).thenApply(ThingModel::fromJson);
Expand Down

0 comments on commit f85e8b9

Please sign in to comment.