From b99b0be26415d8efbcfa1801e36d4b46bf7ca2d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20J=C3=A4ckle?= Date: Thu, 16 Jan 2025 10:47:34 +0100 Subject: [PATCH 1/2] #2096: fix entityId header was added in the wrong format --- .../service/enforcement/ThingEnforcerActor.java | 6 ++++-- .../commands/AbstractThingCommandStrategy.java | 3 ++- .../service/persistence/actors/ETagTestUtils.java | 2 +- .../actors/ThingPersistenceActorCleanupTest.java | 3 ++- .../actors/ThingPersistenceActorSnapshottingTest.java | 2 +- .../persistence/actors/ThingPersistenceActorTest.java | 11 ++++++----- .../commands/AbstractCommandStrategyTest.java | 3 ++- .../ditto/wot/validation/ValidationContext.java | 4 +++- 8 files changed, 21 insertions(+), 13 deletions(-) diff --git a/things/service/src/main/java/org/eclipse/ditto/things/service/enforcement/ThingEnforcerActor.java b/things/service/src/main/java/org/eclipse/ditto/things/service/enforcement/ThingEnforcerActor.java index f7788435fe..cf59a75149 100644 --- a/things/service/src/main/java/org/eclipse/ditto/things/service/enforcement/ThingEnforcerActor.java +++ b/things/service/src/main/java/org/eclipse/ditto/things/service/enforcement/ThingEnforcerActor.java @@ -200,7 +200,8 @@ protected CompletionStage> performWotBasedSignalValidation(final Signa return performWotBasedMessageCommandValidation(messageCommand.setDittoHeaders( DittoHeaders.of(startedSpan.propagateContext(messageCommand.getDittoHeaders())) .toBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), entityId.toString()) + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), + entityId.getEntityType() + ":" + entityId) .build() )).whenComplete((result, error) -> { if (error instanceof DittoRuntimeException dre) { @@ -243,7 +244,8 @@ protected CompletionStage> performWotBasedResponseValidation( messageCommandResponse.setDittoHeaders( DittoHeaders.of(startedSpan.propagateContext(messageCommandResponse.getDittoHeaders())) .toBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), entityId.toString()) + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), + entityId.getEntityType() + ":" + entityId) .build() ) ) diff --git a/things/service/src/main/java/org/eclipse/ditto/things/service/persistence/actors/strategies/commands/AbstractThingCommandStrategy.java b/things/service/src/main/java/org/eclipse/ditto/things/service/persistence/actors/strategies/commands/AbstractThingCommandStrategy.java index 35509afef7..3a9b9d6767 100644 --- a/things/service/src/main/java/org/eclipse/ditto/things/service/persistence/actors/strategies/commands/AbstractThingCommandStrategy.java +++ b/things/service/src/main/java/org/eclipse/ditto/things/service/persistence/actors/strategies/commands/AbstractThingCommandStrategy.java @@ -95,8 +95,9 @@ public Result> apply(final Context context, @Nullable fin final long nextRevision, final C command) { final var dittoHeaders = command.getDittoHeaders(); + final ThingId thingId = context.getState(); final var dittoHeadersBuilder = dittoHeaders.toBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), context.getState().toString()); + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.getEntityType() + ":" + thingId); final var loggerWithCorrelationId = context.getLog().withCorrelationId(command); final var thingConditionFailed = dittoHeaders.getCondition() .flatMap(condition -> ThingConditionValidator.validate(command, condition, entity)); diff --git a/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ETagTestUtils.java b/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ETagTestUtils.java index 2104e0f747..80f9c58f9f 100644 --- a/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ETagTestUtils.java +++ b/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ETagTestUtils.java @@ -367,7 +367,7 @@ protected static DittoHeaders appendEntityIdAndETagToDittoHeaders(final ThingId final DittoHeaders dittoHeaders ) { return dittoHeaders.toBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.toString()) + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.getEntityType() + ":" + thingId) .eTag(EntityTag.fromEntity(object).get()) .build(); } diff --git a/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorCleanupTest.java b/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorCleanupTest.java index af2c81f790..e3d005a6e3 100644 --- a/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorCleanupTest.java +++ b/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorCleanupTest.java @@ -131,8 +131,9 @@ private EventsourcedEvent sendModifyThing(final Thing modifiedThing, final Ac modifiedThing, null, dittoHeadersV2); underTest.tell(modifyThingCommand, getRef()); + final ThingId thingId = modifiedThing.getEntityId().get(); expectMsgEquals(modifyThingResponse(modifiedThing, dittoHeadersV2.toBuilder().putHeader( - DittoHeaderDefinition.ENTITY_ID.getKey(), modifiedThing.getEntityId().get().toString()) + DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.getEntityType() + ":" + thingId) .build() )); diff --git a/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorSnapshottingTest.java b/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorSnapshottingTest.java index ab99e5c0de..6223b73b3d 100755 --- a/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorSnapshottingTest.java +++ b/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorSnapshottingTest.java @@ -102,7 +102,7 @@ public void deletedThingIsSnapshotWithCorrectDataAndCanBeRecreated() { final DeleteThing deleteThing = DeleteThing.of(thingId, dittoHeadersV2); underTest.tell(deleteThing, getRef()); expectMsgEquals(DeleteThingResponse.of(thingId, dittoHeadersV2.toBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.toString()) + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.getEntityType() + ":" + thingId) .build())); final Thing expectedDeletedSnapshot = toDeletedThing(2); diff --git a/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorTest.java b/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorTest.java index 7569e21efc..dc79ae2311 100755 --- a/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorTest.java +++ b/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/ThingPersistenceActorTest.java @@ -595,8 +595,9 @@ public void deleteThingV2() { final DeleteThing deleteThing = DeleteThing.of(getIdOrThrow(thing), dittoHeadersV2); underTest.tell(deleteThing, getRef()); + final ThingId thingId = thing.getEntityId().get(); expectMsgEquals(DeleteThingResponse.of(getIdOrThrow(thing), dittoHeadersV2.toBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thing.getEntityId().get().toString()) + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.getEntityType() + ":" + thingId) .build())); } }; @@ -623,7 +624,7 @@ public void deleteAndRecreateThingWithMinimumData() { final DeleteThing deleteThing = DeleteThing.of(thingId, dittoHeadersV2); underTest.tell(deleteThing, getRef()); expectMsgEquals(DeleteThingResponse.of(thingId, dittoHeadersV2.toBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.toString()) + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.getEntityType() + ":" + thingId) .build())); final Thing minimalThing = Thing.newBuilder() @@ -839,7 +840,7 @@ public void deleteAttribute() { final ThingCommand authorizedCommand = DeleteAttribute.of(thingId, attributeKey, dittoHeadersV2); underTest.tell(authorizedCommand, getRef()); expectMsgEquals(DeleteAttributeResponse.of(thingId, attributeKey, dittoHeadersV2.toBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.toString()) + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.getEntityType() + ":" + thingId) .build())); } }; @@ -864,7 +865,7 @@ public void tryToRetrieveThingAfterDeletion() { underTest.tell(deleteThingCommand, getRef()); expectMsgEquals(DeleteThingResponse.of(thingId, dittoHeadersV2.toBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.toString()) + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.getEntityType() + ":" + thingId) .build())); underTest.tell(retrieveThingCommand, getRef()); @@ -926,7 +927,7 @@ public void recoverThingDeleted() { final DeleteThing deleteThing = DeleteThing.of(thingId, dittoHeadersV2); underTest.tell(deleteThing, getRef()); expectMsgEquals(DeleteThingResponse.of(thingId, dittoHeadersV2.toBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.toString()) + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.getEntityType() + ":" + thingId) .build())); // restart actor to recover thing state diff --git a/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/strategies/commands/AbstractCommandStrategyTest.java b/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/strategies/commands/AbstractCommandStrategyTest.java index 4173a93d29..396fbbd541 100644 --- a/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/strategies/commands/AbstractCommandStrategyTest.java +++ b/things/service/src/test/java/org/eclipse/ditto/things/service/persistence/actors/strategies/commands/AbstractCommandStrategyTest.java @@ -179,8 +179,9 @@ protected static > void assertUnhandledResult( } protected static DittoHeaders provideHeaders(final CommandStrategy.Context context) { + final ThingId thingId = context.getState(); return DittoHeaders.newBuilder() - .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), context.getState().toString()) + .putHeader(DittoHeaderDefinition.ENTITY_ID.getKey(), thingId.getEntityType() + ":" + thingId) .build(); } diff --git a/wot/validation/src/main/java/org/eclipse/ditto/wot/validation/ValidationContext.java b/wot/validation/src/main/java/org/eclipse/ditto/wot/validation/ValidationContext.java index 1d1cd93041..aa6f4afedb 100644 --- a/wot/validation/src/main/java/org/eclipse/ditto/wot/validation/ValidationContext.java +++ b/wot/validation/src/main/java/org/eclipse/ditto/wot/validation/ValidationContext.java @@ -54,7 +54,9 @@ public static ValidationContext buildValidationContext(final DittoHeaders dittoH } private static Optional extractThingId(final DittoHeaders dittoHeaders) { - return Optional.ofNullable(dittoHeaders.get(DittoHeaderDefinition.ENTITY_ID.getKey())) + final String nullableEntityId = dittoHeaders.get(DittoHeaderDefinition.ENTITY_ID.getKey()); + return Optional.ofNullable(nullableEntityId) + .map(entityId -> entityId.substring(entityId.indexOf(":") + 1)) // starts with "thing:" - cut that off! .map(ThingId::of); } } From 0628ca03078aad4209ac01b145106feb2b68e520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20J=C3=A4ckle?= Date: Thu, 16 Jan 2025 11:06:05 +0100 Subject: [PATCH 2/2] added Ditto 3.6.9 release notes --- .../_data/sidebars/ditto_sidebar.yml | 3 ++ .../pages/ditto/release_notes_369.md | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 documentation/src/main/resources/pages/ditto/release_notes_369.md diff --git a/documentation/src/main/resources/_data/sidebars/ditto_sidebar.yml b/documentation/src/main/resources/_data/sidebars/ditto_sidebar.yml index 8859918fbc..37a52d933a 100644 --- a/documentation/src/main/resources/_data/sidebars/ditto_sidebar.yml +++ b/documentation/src/main/resources/_data/sidebars/ditto_sidebar.yml @@ -23,6 +23,9 @@ entries: - title: Release Notes output: web folderitems: + - title: 3.6.9 + url: /release_notes_369.html + output: web - title: 3.6.8 url: /release_notes_368.html output: web diff --git a/documentation/src/main/resources/pages/ditto/release_notes_369.md b/documentation/src/main/resources/pages/ditto/release_notes_369.md new file mode 100644 index 0000000000..8f6ff73961 --- /dev/null +++ b/documentation/src/main/resources/pages/ditto/release_notes_369.md @@ -0,0 +1,30 @@ +--- +title: Release notes 3.6.9 +tags: [release_notes] +published: true +keywords: release notes, announcements, changelog +summary: "Version 3.6.9 of Eclipse Ditto, released on 16.01.2025" +permalink: release_notes_369.html +--- + +This is a bugfix release, no new features since [3.6.8](release_notes_368.html) were added. + +## Changelog + +Compared to the latest release [3.6.8](release_notes_368.html), the following changes and bugfixes were added. + +### Bugfixes +This is a complete list of the +[merged pull requests](https://github.com/eclipse-ditto/ditto/pulls?q=is%3Apr+milestone%3A3.6.9). + +#### Fix exceptions in WebSocket due to wrongly formatted added "EntityId" header + +Ditto release [3.6.5](release_notes_365.html) introduced an improved log messages for errors in WoT validations, adding +the Thing's ID to the log message. Internally, a change was needed to always provide the thing's ID as internal header. +This added header had however the wrong format, which caused exceptions e.g. in the Ditto WebSocket handling. + +This was reported in issue [#2096](https://github.com/eclipse-ditto/ditto/issues/2096) and was fixed via PR +[#2097](https://github.com/eclipse-ditto/ditto/pull/2097). + +As this is a very critical bug, a bugfix release containing just this one fix is provided: `3.6.9`. +