From d9ccf641e8de497548a4572f89f40d72a670d88b Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sun, 19 Oct 2025 18:49:30 +0200 Subject: [PATCH 01/30] Introduce Delta Protocol core classes, including commands (`AddProperty`, `DeleteProperty`, etc.), queries (`SignOn`, `SubscribeToPartitionContents`, etc.), events (`PropertyAdded`), and supporting classes (`DeltaChannel`, `DeltaProtocolVersion`). --- .../io/lionweb/client/delta/DeltaChannel.java | 33 ++++++++++++ .../client/delta/DeltaEventReceiver.java | 8 +++ .../delta/messages/DeltaCommandResponse.java | 3 ++ .../delta/messages/commands/AddChild.java | 25 +++++++++ .../delta/messages/commands/AddPartition.java | 13 +++++ .../delta/messages/commands/AddProperty.java | 54 +++++++++++++++++++ .../messages/commands/ChangeProperty.java | 54 +++++++++++++++++++ .../messages/commands/DeletePartition.java | 12 +++++ .../messages/commands/DeleteProperty.java | 15 ++++++ .../MoveChildFromOtherContainment.java | 24 +++++++++ .../delta/messages/events/PropertyAdded.java | 18 +++++++ .../messages/queries/GetAvailableIds.java | 13 +++++ .../delta/messages/queries/SignOff.java | 11 ++++ .../client/delta/messages/queries/SignOn.java | 19 +++++++ .../SubscribeToChangingPartitions.java | 28 ++++++++++ .../queries/SubscribeToPartitionContents.java | 15 ++++++ .../UnsubscribeFromPartitionContents.java | 13 +++++ 17 files changed, 358 insertions(+) create mode 100644 client/src/main/java/io/lionweb/client/delta/DeltaChannel.java create mode 100644 client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/events/PropertyAdded.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/GetAvailableIds.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/SignOff.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/SignOn.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToChangingPartitions.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToPartitionContents.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/UnsubscribeFromPartitionContents.java diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java new file mode 100644 index 000000000..dbc19a469 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java @@ -0,0 +1,33 @@ +package io.lionweb.client.delta; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.client.delta.messages.DeltaCommandResponse; +import io.lionweb.client.delta.messages.DeltaQuery; +import io.lionweb.client.delta.messages.DeltaQueryResponse; + +/** + * The DeltaChannel must be a specific link between a Client and the Server. Different clients + * should use different DeltaChannels because the clientId must be determined from the channel. + */ +public interface DeltaChannel { + /** + * Queries initiated/requested by the client, with synchronous response by the repository. A query + * requests some information from the repository without changing the repository’s contents. The + * repository gathers all information needed to answer the query, and sends the information back. + * The repository might reply invalid queries with a failure message. We also use queries for + * managing participations. + */ + DeltaQueryResponse sendQuery(DeltaQuery query); + + /** + * Commands initiated/requested by the client, with synchronous response by the repository. A + * command requests some change to the repository. The repository quickly confirms having received + * the command, or rejects a failed command.[5] However, the repository processes the command + * asynchronously, and eventually broadcasts the effect(s) as event. + */ + DeltaCommandResponse sendCommand(DeltaCommand command); + + void registerEventReceiver(DeltaEventReceiver deltaEventReceiver); + + void unregisterEventReceiver(DeltaEventReceiver deltaEventReceiver); +} diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java b/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java new file mode 100644 index 000000000..b55769145 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java @@ -0,0 +1,8 @@ +package io.lionweb.client.delta; + +import io.lionweb.client.delta.messages.DeltaEvent; + +public interface DeltaEventReceiver { + + void receiveEvent(DeltaEvent event); +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java b/client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java new file mode 100644 index 000000000..6263ad522 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java @@ -0,0 +1,3 @@ +package io.lionweb.client.delta.messages; + +public class DeltaCommandResponse {} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java new file mode 100644 index 000000000..3623350b5 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java @@ -0,0 +1,25 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import io.lionweb.serialization.data.SerializationChunk; + +public class AddChild extends DeltaCommand { + public String parent; + public SerializationChunk newChild; + public MetaPointer containment; + public int index; + + public AddChild( + String commandId, + String parent, + SerializationChunk newChild, + MetaPointer containment, + int index) { + super(commandId); + this.parent = parent; + this.newChild = newChild; + this.containment = containment; + this.index = index; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java new file mode 100644 index 000000000..453887d8a --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java @@ -0,0 +1,13 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.SerializationChunk; + +public class AddPartition extends DeltaCommand { + public SerializationChunk newPartition; + + public AddPartition(String commandId, SerializationChunk newPartition) { + super(commandId); + this.newPartition = newPartition; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java new file mode 100644 index 000000000..ed64acd12 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java @@ -0,0 +1,54 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import java.util.Objects; +import org.jetbrains.annotations.Nullable; + +public class AddProperty extends DeltaCommand { + public String node; + public MetaPointer property; + public @Nullable String newValue; + + public AddProperty( + String commandId, String node, MetaPointer property, @Nullable String newValue) { + super(commandId); + this.node = node; + this.property = property; + this.newValue = newValue; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + AddProperty that = (AddProperty) o; + return Objects.equals(commandId, that.commandId) + && Objects.equals(node, that.node) + && Objects.equals(property, that.property) + && Objects.equals(newValue, that.newValue); + } + + @Override + public int hashCode() { + return Objects.hash(commandId, node, property, newValue); + } + + @Override + public String toString() { + return "AddProperty{" + + "node='" + + node + + '\'' + + ", property=" + + property + + ", newValue='" + + newValue + + '\'' + + ", commandId='" + + commandId + + '\'' + + ", protocolMessages=" + + protocolMessages + + '}'; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java new file mode 100644 index 000000000..99a12464f --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java @@ -0,0 +1,54 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import java.util.Objects; +import org.jetbrains.annotations.Nullable; + +public class ChangeProperty extends DeltaCommand { + public String node; + public MetaPointer property; + public @Nullable String newValue; + + public ChangeProperty( + String commandId, String node, MetaPointer property, @Nullable String newValue) { + super(commandId); + this.node = node; + this.property = property; + this.newValue = newValue; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + ChangeProperty that = (ChangeProperty) o; + return Objects.equals(commandId, that.commandId) + && Objects.equals(node, that.node) + && Objects.equals(property, that.property) + && Objects.equals(newValue, that.newValue); + } + + @Override + public int hashCode() { + return Objects.hash(commandId, node, property, newValue); + } + + @Override + public String toString() { + return "ChangeProperty{" + + "node='" + + node + + '\'' + + ", property=" + + property + + ", newValue='" + + newValue + + '\'' + + ", commandId='" + + commandId + + '\'' + + ", protocolMessages=" + + protocolMessages + + '}'; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java new file mode 100644 index 000000000..bf5a98809 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java @@ -0,0 +1,12 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; + +public class DeletePartition extends DeltaCommand { + public String deletedPartition; + + public DeletePartition(String commandId, String deletedPartition) { + super(commandId); + this.deletedPartition = deletedPartition; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java new file mode 100644 index 000000000..eae0c0854 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java @@ -0,0 +1,15 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; + +public class DeleteProperty extends DeltaCommand { + public String node; + public MetaPointer property; + + public DeleteProperty(String commandId, String node, MetaPointer property) { + super(commandId); + this.node = node; + this.property = property; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java new file mode 100644 index 000000000..307e3e1b5 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java @@ -0,0 +1,24 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; + +public class MoveChildFromOtherContainment extends DeltaCommand { + public String newParent; + public MetaPointer newContainment; + public int newIndex; + public String movedChild; + + public MoveChildFromOtherContainment( + String commandId, + String newParent, + MetaPointer newContainment, + int newIndex, + String movedChild) { + super(commandId); + this.newParent = newParent; + this.newContainment = newContainment; + this.newIndex = newIndex; + this.movedChild = movedChild; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/events/PropertyAdded.java b/client/src/main/java/io/lionweb/client/delta/messages/events/PropertyAdded.java new file mode 100644 index 000000000..b8d63ddda --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/events/PropertyAdded.java @@ -0,0 +1,18 @@ +package io.lionweb.client.delta.messages.events; + +import io.lionweb.client.delta.messages.DeltaEvent; +import io.lionweb.serialization.data.MetaPointer; + +public class PropertyAdded extends DeltaEvent { + + public final String node; + public final MetaPointer property; + public final String newValue; + + public PropertyAdded(int sequenceNumber, String node, MetaPointer property, String newValue) { + super(sequenceNumber); + this.node = node; + this.property = property; + this.newValue = newValue; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/GetAvailableIds.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/GetAvailableIds.java new file mode 100644 index 000000000..b181b2e92 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/GetAvailableIds.java @@ -0,0 +1,13 @@ +package io.lionweb.client.delta.messages.queries; + +import io.lionweb.client.delta.messages.DeltaQuery; +import org.jetbrains.annotations.NotNull; + +public class GetAvailableIds extends DeltaQuery { + public int count; + + public GetAvailableIds(@NotNull String queryId, int count) { + super(queryId); + this.count = count; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/SignOff.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/SignOff.java new file mode 100644 index 000000000..cc89a3579 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/SignOff.java @@ -0,0 +1,11 @@ +package io.lionweb.client.delta.messages.queries; + +import io.lionweb.client.delta.messages.DeltaQuery; +import org.jetbrains.annotations.NotNull; + +public class SignOff extends DeltaQuery { + + public SignOff(@NotNull String queryId) { + super(queryId); + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/SignOn.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/SignOn.java new file mode 100644 index 000000000..bbfa9b25a --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/SignOn.java @@ -0,0 +1,19 @@ +package io.lionweb.client.delta.messages.queries; + +import io.lionweb.client.delta.DeltaProtocolVersion; +import io.lionweb.client.delta.messages.DeltaQuery; +import org.jetbrains.annotations.NotNull; + +public class SignOn extends DeltaQuery { + public final @NotNull DeltaProtocolVersion deltaProtocolVersion; + public final @NotNull String clientId; + + public SignOn( + @NotNull String queryId, + @NotNull DeltaProtocolVersion deltaProtocolVersion, + @NotNull String clientId) { + super(queryId); + this.deltaProtocolVersion = deltaProtocolVersion; + this.clientId = clientId; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToChangingPartitions.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToChangingPartitions.java new file mode 100644 index 000000000..077c3ff4d --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToChangingPartitions.java @@ -0,0 +1,28 @@ +package io.lionweb.client.delta.messages.queries; + +import io.lionweb.client.delta.messages.DeltaQuery; +import org.jetbrains.annotations.NotNull; + +public class SubscribeToChangingPartitions extends DeltaQuery { + /** + * Whether this client wants to receive events on newly created partitions (true), or not (false) + */ + private boolean creation; + + /** Whether this client wants to receive events on deleted partitions (true), or not (false). */ + private boolean deletion; + + /** + * Whether this client wants to automatically subscribe to newly created partitions (true), or not + * (false). + */ + private boolean partitions; + + public SubscribeToChangingPartitions( + @NotNull String queryId, boolean creation, boolean deletion, boolean partitions) { + super(queryId); + this.creation = creation; + this.deletion = deletion; + this.partitions = partitions; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToPartitionContents.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToPartitionContents.java new file mode 100644 index 000000000..e5424b128 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToPartitionContents.java @@ -0,0 +1,15 @@ +package io.lionweb.client.delta.messages.queries; + +import io.lionweb.client.delta.messages.DeltaQuery; +import org.jetbrains.annotations.NotNull; + +public class SubscribeToPartitionContents extends DeltaQuery { + + /** TargetNode Node id of the partition this client wants to receive events of. */ + private String partition; + + public SubscribeToPartitionContents(@NotNull String queryId, String partition) { + super(queryId); + this.partition = partition; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/UnsubscribeFromPartitionContents.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/UnsubscribeFromPartitionContents.java new file mode 100644 index 000000000..5a0bcf9d2 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/UnsubscribeFromPartitionContents.java @@ -0,0 +1,13 @@ +package io.lionweb.client.delta.messages.queries; + +import io.lionweb.client.delta.messages.DeltaQuery; + +public class UnsubscribeFromPartitionContents extends DeltaQuery { + + public final String partition; + + public UnsubscribeFromPartitionContents(String queryId, String partition) { + super(queryId); + this.partition = partition; + } +} From 38bea1096ea3bdb49c9d25af7d4498aeee084455 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sun, 19 Oct 2025 19:10:12 +0200 Subject: [PATCH 02/30] Introduce new DeltaCommand classes for operations: Add/Delete/Move/Replace references, annotations, and children, covering various parent and containment scenarios with documentation updates and null checks. --- .../messages/commands/AddAnnotation.java | 25 ++++++++++++++ .../delta/messages/commands/AddChild.java | 9 ++++- .../delta/messages/commands/AddReference.java | 30 +++++++++++++++++ .../messages/commands/DeleteAnnotation.java | 23 +++++++++++++ .../delta/messages/commands/DeleteChild.java | 29 ++++++++++++++++ .../messages/commands/DeleteReference.java | 30 +++++++++++++++++ ...veAndReplaceAnnotationFromOtherParent.java | 29 ++++++++++++++++ .../MoveAndReplaceAnnotationInSameParent.java | 23 +++++++++++++ ...veAndReplaceChildFromOtherContainment.java | 32 ++++++++++++++++++ ...ChildFromOtherContainmentInSameParent.java | 31 +++++++++++++++++ .../MoveAndReplaceChildInSameContainment.java | 22 +++++++++++++ .../MoveAnnotationFromOtherParent.java | 19 +++++++++++ .../commands/MoveAnnotationInSameParent.java | 17 ++++++++++ .../MoveChildFromOtherContainment.java | 1 + ...ChildFromOtherContainmentInSameParent.java | 22 +++++++++++++ .../commands/MoveChildInSameContainment.java | 15 +++++++++ .../messages/commands/ReplaceAnnotation.java | 33 +++++++++++++++++++ .../delta/messages/commands/ReplaceChild.java | 33 +++++++++++++++++++ 18 files changed, 422 insertions(+), 1 deletion(-) create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java new file mode 100644 index 000000000..393a95e0c --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java @@ -0,0 +1,25 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.SerializationChunk; +import org.jetbrains.annotations.NotNull; + +/** + * Add new node newAnnotation to parent's annotations at index. newAnnotation might be a single node + * or an arbitrary complex subtree. All nodes in that subtree MUST be new, i.e. their id MUST NOT + * exist in the repository. Nodes in that subtree MAY have references to already existing nodes, and + * already existing nodes MAY have references to nodes in that subtree. + */ +public class AddAnnotation extends DeltaCommand { + public String parent; + public SerializationChunk newAnnotation; + public int index; + + public AddAnnotation( + @NotNull String commandId, String parent, SerializationChunk newAnnotation, int index) { + super(commandId); + this.parent = parent; + this.newAnnotation = newAnnotation; + this.index = index; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java index 3623350b5..4c59bc1c8 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java @@ -3,7 +3,14 @@ import io.lionweb.client.delta.messages.DeltaCommand; import io.lionweb.serialization.data.MetaPointer; import io.lionweb.serialization.data.SerializationChunk; +import org.jetbrains.annotations.NotNull; +/** + * Add new node newChild to parent in containment at index. newChild might be a single node or an + * arbitrary complex subtree. All nodes in that subtree MUST be new, i.e. their id MUST NOT exist in + * the repository. Nodes in that subtree MAY have references to already existing nodes, and already + * existing nodes MAY have references to nodes in that subtree. + */ public class AddChild extends DeltaCommand { public String parent; public SerializationChunk newChild; @@ -11,7 +18,7 @@ public class AddChild extends DeltaCommand { public int index; public AddChild( - String commandId, + @NotNull String commandId, String parent, SerializationChunk newChild, MetaPointer containment, diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java new file mode 100644 index 000000000..4ac3b8436 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java @@ -0,0 +1,30 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** Add newTarget / newResolveInfo to parent's reference at index. */ +public class AddReference extends DeltaCommand { + public String parent; + public MetaPointer reference; + public int index; + public @Nullable String newTarget; + public @Nullable String newResolveInfo; + + public AddReference( + @NotNull String commandId, + String parent, + MetaPointer reference, + int index, + @Nullable String newTarget, + @Nullable String newResolveInfo) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.index = index; + this.newTarget = newTarget; + this.newResolveInfo = newResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java new file mode 100644 index 000000000..3672d98b1 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java @@ -0,0 +1,23 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import org.jetbrains.annotations.NotNull; + +/** + * Delete existing node deletedAnnotation from parent's annotations at index, and all its + * descendants (including annotation instances). Does NOT change references to any of the deleted + * nodes. + */ +public class DeleteAnnotation extends DeltaCommand { + public String node; + public int index; + public String deletedAnnotation; + + public DeleteAnnotation( + @NotNull String commandId, String node, int index, String deletedAnnotation) { + super(commandId); + this.node = node; + this.index = index; + this.deletedAnnotation = deletedAnnotation; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java new file mode 100644 index 000000000..d14c5010a --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java @@ -0,0 +1,29 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; + +/** + * Delete existing node deletedChild from parent's containment at index, and all its descendants + * (including annotation instances). Does NOT change references to any of the deleted nodes. + */ +public class DeleteChild extends DeltaCommand { + public String parent; + public MetaPointer containment; + public int index; + public String deletedChild; + + public DeleteChild( + @NotNull String commandId, + String parent, + MetaPointer containment, + int index, + String deletedChild) { + super(commandId); + this.parent = parent; + this.containment = containment; + this.index = index; + this.deletedChild = deletedChild; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java new file mode 100644 index 000000000..d3f0e24e1 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java @@ -0,0 +1,30 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** Delete existing entry deletedTarget/deletedResolveInfo from parent's reference at index. */ +public class DeleteReference extends DeltaCommand { + public String parent; + public MetaPointer reference; + public int index; + public @Nullable String deletedTarget; + public @Nullable String deletedResolveInfo; + + public DeleteReference( + @NotNull String commandId, + String parent, + MetaPointer reference, + int index, + @Nullable String deletedTarget, + @Nullable String deletedResolveInfo) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.index = index; + this.deletedTarget = deletedTarget; + this.deletedResolveInfo = deletedResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java new file mode 100644 index 000000000..dab25a080 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java @@ -0,0 +1,29 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import org.jetbrains.annotations.NotNull; + +/** + * Move existing node movedAnnotation inside newParent's annotations at newIndex. Delete current + * node replacedAnnotation at newParent's annotations at newIndex, and all its descendants + * (including annotation instances). Does NOT change references to any of the deleted nodes + */ +public class MoveAndReplaceAnnotationFromOtherParent extends DeltaCommand { + public String newParent; + public int newIndex; + public String replacedAnnotation; + public String movedAnnotation; + + public MoveAndReplaceAnnotationFromOtherParent( + @NotNull String commandId, + String newParent, + int newIndex, + String replacedAnnotation, + String movedAnnotation) { + super(commandId); + this.newParent = newParent; + this.newIndex = newIndex; + this.replacedAnnotation = replacedAnnotation; + this.movedAnnotation = movedAnnotation; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java new file mode 100644 index 000000000..e18567cbb --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java @@ -0,0 +1,23 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import org.jetbrains.annotations.NotNull; + +/** + * Move existing node movedAnnotation within the same parent to newIndex. Delete current node + * replacedAnnotation at movedAnnotation's parent’s annotations at newIndex, and all its descendants + * (including annotation instances). Does NOT change references to any of the deleted nodes. + */ +public class MoveAndReplaceAnnotationInSameParent extends DeltaCommand { + public int newIndex; + public String replacedAnnotation; + public String movedAnnotation; + + public MoveAndReplaceAnnotationInSameParent( + @NotNull String commandId, int newIndex, String replacedAnnotation, String movedAnnotation) { + super(commandId); + this.newIndex = newIndex; + this.replacedAnnotation = replacedAnnotation; + this.movedAnnotation = movedAnnotation; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java new file mode 100644 index 000000000..840b019fd --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java @@ -0,0 +1,32 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; + +/** + * Move existing node movedChild inside newParent's newContainment at newIndex. Delete current child + * replacedChild inside newParent's newContainment at newIndex, and all its descendants (including + * annotation instances). Does NOT change references to any of the deleted nodes. + */ +public class MoveAndReplaceChildFromOtherContainment extends DeltaCommand { + public String newParent; + public MetaPointer newContainment; + public int newIndex; + public String replacedChild; + public String movedChild; + + public MoveAndReplaceChildFromOtherContainment( + String commandId, + String newParent, + MetaPointer newContainment, + int newIndex, + String replacedChild, + String movedChild) { + super(commandId); + this.newParent = newParent; + this.newContainment = newContainment; + this.newIndex = newIndex; + this.replacedChild = replacedChild; + this.movedChild = movedChild; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java new file mode 100644 index 000000000..f4d5e60d4 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java @@ -0,0 +1,31 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; + +/** + * Move existing node movedChild (currently inside one of movedChild's parent’s containments other + * than newContainment) inside movedChild's parent’s newContainment at newIndex. Delete current + * child replacedChild inside movedChild's parent’s newContainment at newIndex, and all its + * descendants (including annotation instances). Does NOT change references to any of the deleted + * nodes. + */ +public class MoveAndReplaceChildFromOtherContainmentInSameParent extends DeltaCommand { + public MetaPointer newContainment; + public int newIndex; + public String replacedChild; + public String movedChild; + + public MoveAndReplaceChildFromOtherContainmentInSameParent( + String commandId, + MetaPointer newContainment, + int newIndex, + String replacedChild, + String movedChild) { + super(commandId); + this.newContainment = newContainment; + this.newIndex = newIndex; + this.replacedChild = replacedChild; + this.movedChild = movedChild; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java new file mode 100644 index 000000000..e31ffc765 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java @@ -0,0 +1,22 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; + +/** + * Move existing node movedChild within its current containment to newIndex. Delete current child + * replacedChild inside the same containment at newIndex, and all its descendants (including + * annotation instances). Does NOT change references to any of the deleted nodes + */ +public class MoveAndReplaceChildInSameContainment extends DeltaCommand { + public int newIndex; + public String replacedChild; + public String movedChild; + + public MoveAndReplaceChildInSameContainment( + String commandId, int newIndex, String replacedChild, String movedChild) { + super(commandId); + this.newIndex = newIndex; + this.replacedChild = replacedChild; + this.movedChild = movedChild; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java new file mode 100644 index 000000000..977be70a7 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java @@ -0,0 +1,19 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import org.jetbrains.annotations.NotNull; + +/** Move existing node movedAnnotation inside newParent's annotations at newIndex. */ +public class MoveAnnotationFromOtherParent extends DeltaCommand { + public String newParent; + public int newIndex; + public String movedAnnotation; + + public MoveAnnotationFromOtherParent( + @NotNull String commandId, String newParent, int newIndex, String movedAnnotation) { + super(commandId); + this.newParent = newParent; + this.newIndex = newIndex; + this.movedAnnotation = movedAnnotation; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java new file mode 100644 index 000000000..05fcc396d --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java @@ -0,0 +1,17 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import org.jetbrains.annotations.NotNull; + +/** Move existing node movedAnnotation within the same parent to newIndex. */ +public class MoveAnnotationInSameParent extends DeltaCommand { + public int newIndex; + public String movedAnnotation; + + public MoveAnnotationInSameParent( + @NotNull String commandId, int newIndex, String movedAnnotation) { + super(commandId); + this.newIndex = newIndex; + this.movedAnnotation = movedAnnotation; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java index 307e3e1b5..cb4d3ab15 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java @@ -3,6 +3,7 @@ import io.lionweb.client.delta.messages.DeltaCommand; import io.lionweb.serialization.data.MetaPointer; +/** Move existing node movedChild inside newParent's newContainment at newIndex. */ public class MoveChildFromOtherContainment extends DeltaCommand { public String newParent; public MetaPointer newContainment; diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java new file mode 100644 index 000000000..2fc1641b6 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java @@ -0,0 +1,22 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; + +/** + * Move existing node movedChild (currently inside one of movedChild's parent’s containments other + * than newContainment) inside movedChild's parent’s newContainment at newIndex. + */ +public class MoveChildFromOtherContainmentInSameParent extends DeltaCommand { + public MetaPointer newContainment; + public int newIndex; + public String movedChild; + + public MoveChildFromOtherContainmentInSameParent( + String commandId, MetaPointer newContainment, int newIndex, String movedChild) { + super(commandId); + this.newContainment = newContainment; + this.newIndex = newIndex; + this.movedChild = movedChild; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java new file mode 100644 index 000000000..331d08e56 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java @@ -0,0 +1,15 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; + +/** Move existing node movedChild within its current containment to newIndex. */ +public class MoveChildInSameContainment extends DeltaCommand { + public int newIndex; + public String movedChild; + + public MoveChildInSameContainment(String commandId, int newIndex, String movedChild) { + super(commandId); + this.newIndex = newIndex; + this.movedChild = movedChild; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java new file mode 100644 index 000000000..59125495f --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java @@ -0,0 +1,33 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import io.lionweb.serialization.data.SerializationChunk; +import org.jetbrains.annotations.NotNull; + +/** + * Delete current node replacedAnnotation at parent's annotations at index, and all its descendants + * (including annotation instances). Does NOT change references to any of the deleted nodes. + */ +public class ReplaceAnnotation extends DeltaCommand { + public SerializationChunk newAnnotation; + public String parent; + public int index; + public MetaPointer containment; + public String replacedAnnotation; + + public ReplaceAnnotation( + @NotNull String commandId, + SerializationChunk newAnnotation, + String parent, + MetaPointer containment, + int index, + String replacedAnnotation) { + super(commandId); + this.newAnnotation = newAnnotation; + this.parent = parent; + this.containment = containment; + this.index = index; + this.replacedAnnotation = replacedAnnotation; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java new file mode 100644 index 000000000..d32ed3f66 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java @@ -0,0 +1,33 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import io.lionweb.serialization.data.SerializationChunk; +import org.jetbrains.annotations.NotNull; + +/** + * Delete current child replacedChild inside parent's containment at index, and all its descendants + * (including annotation instances). Does NOT change references to any of the deleted nodes + */ +public class ReplaceChild extends DeltaCommand { + public SerializationChunk newChild; + public String parent; + public MetaPointer containment; + public int index; + public String replacedChild; + + public ReplaceChild( + @NotNull String commandId, + SerializationChunk newChild, + String parent, + MetaPointer containment, + int index, + String replacedChild) { + super(commandId); + this.newChild = newChild; + this.parent = parent; + this.containment = containment; + this.index = index; + this.replacedChild = replacedChild; + } +} From 85c8624ab00b017b3139960bf135c2f308c4f82b Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sun, 19 Oct 2025 19:21:09 +0200 Subject: [PATCH 03/30] Introduce new DeltaCommand classes for moving and replacing entries across and within references, refactor existing commands to use `final` fields for immutability. --- .../messages/commands/AddAnnotation.java | 8 +-- .../delta/messages/commands/AddChild.java | 10 ++-- .../delta/messages/commands/AddPartition.java | 4 +- .../delta/messages/commands/AddProperty.java | 8 +-- .../delta/messages/commands/AddReference.java | 12 ++--- .../messages/commands/ChangeProperty.java | 8 +-- .../messages/commands/ChangeReference.java | 39 +++++++++++++++ .../messages/commands/DeleteAnnotation.java | 8 +-- .../delta/messages/commands/DeleteChild.java | 10 ++-- .../messages/commands/DeletePartition.java | 4 +- .../messages/commands/DeleteProperty.java | 6 +-- .../messages/commands/DeleteReference.java | 12 ++--- ...veAndReplaceAnnotationFromOtherParent.java | 10 ++-- .../MoveAndReplaceAnnotationInSameParent.java | 8 +-- ...veAndReplaceChildFromOtherContainment.java | 12 ++--- ...ChildFromOtherContainmentInSameParent.java | 10 ++-- .../MoveAndReplaceChildInSameContainment.java | 8 +-- ...MoveAndReplaceEntryFromOtherReference.java | 49 +++++++++++++++++++ .../MoveAnnotationFromOtherParent.java | 8 +-- .../commands/MoveAnnotationInSameParent.java | 6 +-- .../MoveChildFromOtherContainment.java | 10 ++-- ...ChildFromOtherContainmentInSameParent.java | 8 +-- .../commands/MoveChildInSameContainment.java | 6 +-- .../commands/MoveEntryFromOtherReference.java | 42 ++++++++++++++++ ...veEntryFromOtherReferenceInSameParent.java | 39 +++++++++++++++ .../commands/MoveEntryInSameReference.java | 36 ++++++++++++++ .../messages/commands/ReplaceAnnotation.java | 12 ++--- .../delta/messages/commands/ReplaceChild.java | 12 ++--- 28 files changed, 305 insertions(+), 100 deletions(-) create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReference.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReference.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReference.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReferenceInSameParent.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryInSameReference.java diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java index 393a95e0c..7952cfc4d 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java @@ -10,10 +10,10 @@ * exist in the repository. Nodes in that subtree MAY have references to already existing nodes, and * already existing nodes MAY have references to nodes in that subtree. */ -public class AddAnnotation extends DeltaCommand { - public String parent; - public SerializationChunk newAnnotation; - public int index; +public final class AddAnnotation extends DeltaCommand { + public final String parent; + public final SerializationChunk newAnnotation; + public final int index; public AddAnnotation( @NotNull String commandId, String parent, SerializationChunk newAnnotation, int index) { diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java index 4c59bc1c8..ca5a327ef 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java @@ -11,11 +11,11 @@ * the repository. Nodes in that subtree MAY have references to already existing nodes, and already * existing nodes MAY have references to nodes in that subtree. */ -public class AddChild extends DeltaCommand { - public String parent; - public SerializationChunk newChild; - public MetaPointer containment; - public int index; +public final class AddChild extends DeltaCommand { + public final String parent; + public final SerializationChunk newChild; + public final MetaPointer containment; + public final int index; public AddChild( @NotNull String commandId, diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java index 453887d8a..2cfbd94a9 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java @@ -3,8 +3,8 @@ import io.lionweb.client.delta.messages.DeltaCommand; import io.lionweb.serialization.data.SerializationChunk; -public class AddPartition extends DeltaCommand { - public SerializationChunk newPartition; +public final class AddPartition extends DeltaCommand { + public final SerializationChunk newPartition; public AddPartition(String commandId, SerializationChunk newPartition) { super(commandId); diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java index ed64acd12..af66470bf 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java @@ -5,10 +5,10 @@ import java.util.Objects; import org.jetbrains.annotations.Nullable; -public class AddProperty extends DeltaCommand { - public String node; - public MetaPointer property; - public @Nullable String newValue; +public final class AddProperty extends DeltaCommand { + public final String node; + public final MetaPointer property; + public final @Nullable String newValue; public AddProperty( String commandId, String node, MetaPointer property, @Nullable String newValue) { diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java index 4ac3b8436..9deedc3e6 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java @@ -6,12 +6,12 @@ import org.jetbrains.annotations.Nullable; /** Add newTarget / newResolveInfo to parent's reference at index. */ -public class AddReference extends DeltaCommand { - public String parent; - public MetaPointer reference; - public int index; - public @Nullable String newTarget; - public @Nullable String newResolveInfo; +public final class AddReference extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int index; + public final @Nullable String newTarget; + public final @Nullable String newResolveInfo; public AddReference( @NotNull String commandId, diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java index 99a12464f..a6d4a2643 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java @@ -5,10 +5,10 @@ import java.util.Objects; import org.jetbrains.annotations.Nullable; -public class ChangeProperty extends DeltaCommand { - public String node; - public MetaPointer property; - public @Nullable String newValue; +public final class ChangeProperty extends DeltaCommand { + public final String node; + public final MetaPointer property; + public final @Nullable String newValue; public ChangeProperty( String commandId, String node, MetaPointer property, @Nullable String newValue) { diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReference.java new file mode 100644 index 000000000..3e8a1c9a8 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReference.java @@ -0,0 +1,39 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Replace existing entry oldTarget/oldResolveInfo inside parent's reference at index with + * newTarget/newResolveInfo. + */ +public final class ChangeReference extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int index; + public final @Nullable String oldTarget; + public final @Nullable String oldResolveInfo; + public final @Nullable String newTarget; + public final @Nullable String newResolveInfo; + + public ChangeReference( + @NotNull String commandId, + String parent, + MetaPointer reference, + int index, + @Nullable String oldTarget, + @Nullable String oldResolveInfo, + @Nullable String newTarget, + @Nullable String newResolveInfo) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.index = index; + this.oldTarget = oldTarget; + this.oldResolveInfo = oldResolveInfo; + this.newTarget = newTarget; + this.newResolveInfo = newResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java index 3672d98b1..5ed033482 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java @@ -8,10 +8,10 @@ * descendants (including annotation instances). Does NOT change references to any of the deleted * nodes. */ -public class DeleteAnnotation extends DeltaCommand { - public String node; - public int index; - public String deletedAnnotation; +public final class DeleteAnnotation extends DeltaCommand { + public final String node; + public final int index; + public final String deletedAnnotation; public DeleteAnnotation( @NotNull String commandId, String node, int index, String deletedAnnotation) { diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java index d14c5010a..4c8503c82 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java @@ -8,11 +8,11 @@ * Delete existing node deletedChild from parent's containment at index, and all its descendants * (including annotation instances). Does NOT change references to any of the deleted nodes. */ -public class DeleteChild extends DeltaCommand { - public String parent; - public MetaPointer containment; - public int index; - public String deletedChild; +public final class DeleteChild extends DeltaCommand { + public final String parent; + public final MetaPointer containment; + public final int index; + public final String deletedChild; public DeleteChild( @NotNull String commandId, diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java index bf5a98809..0e8cad72b 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java @@ -2,8 +2,8 @@ import io.lionweb.client.delta.messages.DeltaCommand; -public class DeletePartition extends DeltaCommand { - public String deletedPartition; +public final class DeletePartition extends DeltaCommand { + public final String deletedPartition; public DeletePartition(String commandId, String deletedPartition) { super(commandId); diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java index eae0c0854..b269fa7a6 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java @@ -3,9 +3,9 @@ import io.lionweb.client.delta.messages.DeltaCommand; import io.lionweb.serialization.data.MetaPointer; -public class DeleteProperty extends DeltaCommand { - public String node; - public MetaPointer property; +public final class DeleteProperty extends DeltaCommand { + public final String node; + public final MetaPointer property; public DeleteProperty(String commandId, String node, MetaPointer property) { super(commandId); diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java index d3f0e24e1..af2254bb0 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java @@ -6,12 +6,12 @@ import org.jetbrains.annotations.Nullable; /** Delete existing entry deletedTarget/deletedResolveInfo from parent's reference at index. */ -public class DeleteReference extends DeltaCommand { - public String parent; - public MetaPointer reference; - public int index; - public @Nullable String deletedTarget; - public @Nullable String deletedResolveInfo; +public final class DeleteReference extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int index; + public final @Nullable String deletedTarget; + public final @Nullable String deletedResolveInfo; public DeleteReference( @NotNull String commandId, diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java index dab25a080..657b4ce35 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java @@ -8,11 +8,11 @@ * node replacedAnnotation at newParent's annotations at newIndex, and all its descendants * (including annotation instances). Does NOT change references to any of the deleted nodes */ -public class MoveAndReplaceAnnotationFromOtherParent extends DeltaCommand { - public String newParent; - public int newIndex; - public String replacedAnnotation; - public String movedAnnotation; +public final class MoveAndReplaceAnnotationFromOtherParent extends DeltaCommand { + public final String newParent; + public final int newIndex; + public final String replacedAnnotation; + public final String movedAnnotation; public MoveAndReplaceAnnotationFromOtherParent( @NotNull String commandId, diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java index e18567cbb..bcb4f95af 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java @@ -8,10 +8,10 @@ * replacedAnnotation at movedAnnotation's parent’s annotations at newIndex, and all its descendants * (including annotation instances). Does NOT change references to any of the deleted nodes. */ -public class MoveAndReplaceAnnotationInSameParent extends DeltaCommand { - public int newIndex; - public String replacedAnnotation; - public String movedAnnotation; +public final class MoveAndReplaceAnnotationInSameParent extends DeltaCommand { + public final int newIndex; + public final String replacedAnnotation; + public final String movedAnnotation; public MoveAndReplaceAnnotationInSameParent( @NotNull String commandId, int newIndex, String replacedAnnotation, String movedAnnotation) { diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java index 840b019fd..5ac53cfb3 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java @@ -8,12 +8,12 @@ * replacedChild inside newParent's newContainment at newIndex, and all its descendants (including * annotation instances). Does NOT change references to any of the deleted nodes. */ -public class MoveAndReplaceChildFromOtherContainment extends DeltaCommand { - public String newParent; - public MetaPointer newContainment; - public int newIndex; - public String replacedChild; - public String movedChild; +public final class MoveAndReplaceChildFromOtherContainment extends DeltaCommand { + public final String newParent; + public final MetaPointer newContainment; + public final int newIndex; + public final String replacedChild; + public final String movedChild; public MoveAndReplaceChildFromOtherContainment( String commandId, diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java index f4d5e60d4..2fcb418c0 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java @@ -10,11 +10,11 @@ * descendants (including annotation instances). Does NOT change references to any of the deleted * nodes. */ -public class MoveAndReplaceChildFromOtherContainmentInSameParent extends DeltaCommand { - public MetaPointer newContainment; - public int newIndex; - public String replacedChild; - public String movedChild; +public final class MoveAndReplaceChildFromOtherContainmentInSameParent extends DeltaCommand { + public final MetaPointer newContainment; + public final int newIndex; + public final String replacedChild; + public final String movedChild; public MoveAndReplaceChildFromOtherContainmentInSameParent( String commandId, diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java index e31ffc765..efcfa9f36 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java @@ -7,10 +7,10 @@ * replacedChild inside the same containment at newIndex, and all its descendants (including * annotation instances). Does NOT change references to any of the deleted nodes */ -public class MoveAndReplaceChildInSameContainment extends DeltaCommand { - public int newIndex; - public String replacedChild; - public String movedChild; +public final class MoveAndReplaceChildInSameContainment extends DeltaCommand { + public final int newIndex; + public final String replacedChild; + public final String movedChild; public MoveAndReplaceChildInSameContainment( String commandId, int newIndex, String replacedChild, String movedChild) { diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReference.java new file mode 100644 index 000000000..d4492ecfa --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReference.java @@ -0,0 +1,49 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Move existing entry movedTarget/movedResolveInfo inside oldParent's oldReference at oldIndex to + * newParent's newReference at newIndex, replacing existing entry replacedTarget/replacedResolveInfo + * in newParent's newReference at newIndex. + */ +public final class MoveAndReplaceEntryFromOtherReference extends DeltaCommand { + public final String newParent; + public final MetaPointer newReference; + public final int newIndex; + public final @Nullable String replacedTarget; + public final @Nullable String replacedResolveInfo; + public final String oldParent; + public final MetaPointer oldReference; + public final int oldIndex; + public final @Nullable String movedTarget; + public final @Nullable String movedResolveInfo; + + public MoveAndReplaceEntryFromOtherReference( + @NotNull String commandId, + String newParent, + MetaPointer newReference, + int newIndex, + @Nullable String replacedTarget, + @Nullable String replacedResolveInfo, + String oldParent, + MetaPointer oldReference, + int oldIndex, + @Nullable String movedTarget, + @Nullable String movedResolveInfo) { + super(commandId); + this.newParent = newParent; + this.newReference = newReference; + this.newIndex = newIndex; + this.replacedTarget = replacedTarget; + this.replacedResolveInfo = replacedResolveInfo; + this.oldParent = oldParent; + this.oldReference = oldReference; + this.oldIndex = oldIndex; + this.movedTarget = movedTarget; + this.movedResolveInfo = movedResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java index 977be70a7..8b58f9715 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java @@ -4,10 +4,10 @@ import org.jetbrains.annotations.NotNull; /** Move existing node movedAnnotation inside newParent's annotations at newIndex. */ -public class MoveAnnotationFromOtherParent extends DeltaCommand { - public String newParent; - public int newIndex; - public String movedAnnotation; +public final class MoveAnnotationFromOtherParent extends DeltaCommand { + public final String newParent; + public final int newIndex; + public final String movedAnnotation; public MoveAnnotationFromOtherParent( @NotNull String commandId, String newParent, int newIndex, String movedAnnotation) { diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java index 05fcc396d..04cb4ce99 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java @@ -4,9 +4,9 @@ import org.jetbrains.annotations.NotNull; /** Move existing node movedAnnotation within the same parent to newIndex. */ -public class MoveAnnotationInSameParent extends DeltaCommand { - public int newIndex; - public String movedAnnotation; +public final class MoveAnnotationInSameParent extends DeltaCommand { + public final int newIndex; + public final String movedAnnotation; public MoveAnnotationInSameParent( @NotNull String commandId, int newIndex, String movedAnnotation) { diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java index cb4d3ab15..b2f6e66a9 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java @@ -4,11 +4,11 @@ import io.lionweb.serialization.data.MetaPointer; /** Move existing node movedChild inside newParent's newContainment at newIndex. */ -public class MoveChildFromOtherContainment extends DeltaCommand { - public String newParent; - public MetaPointer newContainment; - public int newIndex; - public String movedChild; +public final class MoveChildFromOtherContainment extends DeltaCommand { + public final String newParent; + public final MetaPointer newContainment; + public final int newIndex; + public final String movedChild; public MoveChildFromOtherContainment( String commandId, diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java index 2fc1641b6..bed229644 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java @@ -7,10 +7,10 @@ * Move existing node movedChild (currently inside one of movedChild's parent’s containments other * than newContainment) inside movedChild's parent’s newContainment at newIndex. */ -public class MoveChildFromOtherContainmentInSameParent extends DeltaCommand { - public MetaPointer newContainment; - public int newIndex; - public String movedChild; +public final class MoveChildFromOtherContainmentInSameParent extends DeltaCommand { + public final MetaPointer newContainment; + public final int newIndex; + public final String movedChild; public MoveChildFromOtherContainmentInSameParent( String commandId, MetaPointer newContainment, int newIndex, String movedChild) { diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java index 331d08e56..4c1f29113 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java @@ -3,9 +3,9 @@ import io.lionweb.client.delta.messages.DeltaCommand; /** Move existing node movedChild within its current containment to newIndex. */ -public class MoveChildInSameContainment extends DeltaCommand { - public int newIndex; - public String movedChild; +public final class MoveChildInSameContainment extends DeltaCommand { + public final int newIndex; + public final String movedChild; public MoveChildInSameContainment(String commandId, int newIndex, String movedChild) { super(commandId); diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReference.java new file mode 100644 index 000000000..8daf50e84 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReference.java @@ -0,0 +1,42 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Move existing entry movedTarget/movedResolveInfo inside oldParent's oldReference at oldIndex to + * newParent's newReference at newIndex. + */ +public final class MoveEntryFromOtherReference extends DeltaCommand { + public final String newParent; + public final MetaPointer newReference; + public final int newIndex; + public final @NotNull String oldParent; + public final MetaPointer oldReference; + public final int oldIndex; + public final @Nullable String movedTarget; + public final @Nullable String movedResolveInfo; + + public MoveEntryFromOtherReference( + @NotNull String commandId, + String newParent, + MetaPointer newReference, + int newIndex, + @NotNull String oldParent, + MetaPointer oldReference, + int oldIndex, + @Nullable String movedTarget, + @Nullable String movedResolveInfo) { + super(commandId); + this.newParent = newParent; + this.newReference = newReference; + this.newIndex = newIndex; + this.oldParent = oldParent; + this.oldReference = oldReference; + this.oldIndex = oldIndex; + this.movedTarget = movedTarget; + this.movedResolveInfo = movedResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReferenceInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReferenceInSameParent.java new file mode 100644 index 000000000..5ef7a82fa --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReferenceInSameParent.java @@ -0,0 +1,39 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Move existing entry movedTarget/movedResolveInfo inside parent's oldReference at oldIndex to + * parent's newReference at newIndex. + */ +public final class MoveEntryFromOtherReferenceInSameParent extends DeltaCommand { + public final String parent; + public final MetaPointer newReference; + public final int newIndex; + public final MetaPointer oldReference; + public final int oldIndex; + public final @Nullable String movedTarget; + public final @Nullable String movedResolveInfo; + + public MoveEntryFromOtherReferenceInSameParent( + @NotNull String commandId, + String parent, + MetaPointer newReference, + int newIndex, + MetaPointer oldReference, + int oldIndex, + @Nullable String movedTarget, + @Nullable String movedResolveInfo) { + super(commandId); + this.parent = parent; + this.newReference = newReference; + this.newIndex = newIndex; + this.oldReference = oldReference; + this.oldIndex = oldIndex; + this.movedTarget = movedTarget; + this.movedResolveInfo = movedResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryInSameReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryInSameReference.java new file mode 100644 index 000000000..26347f4ba --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryInSameReference.java @@ -0,0 +1,36 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Move existing entry movedTarget/movedResolveInfo inside parent's reference at oldIndex inside + * parent's reference at newIndex. + */ +public final class MoveEntryInSameReference extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int oldIndex; + public final int newIndex; + public final @Nullable String movedTarget; + public final @Nullable String movedResolveInfo; + + public MoveEntryInSameReference( + @NotNull String commandId, + String parent, + MetaPointer reference, + int oldIndex, + int newIndex, + @Nullable String movedTarget, + @Nullable String movedResolveInfo) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.oldIndex = oldIndex; + this.newIndex = newIndex; + this.movedTarget = movedTarget; + this.movedResolveInfo = movedResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java index 59125495f..b7c96ceed 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java @@ -9,12 +9,12 @@ * Delete current node replacedAnnotation at parent's annotations at index, and all its descendants * (including annotation instances). Does NOT change references to any of the deleted nodes. */ -public class ReplaceAnnotation extends DeltaCommand { - public SerializationChunk newAnnotation; - public String parent; - public int index; - public MetaPointer containment; - public String replacedAnnotation; +public final class ReplaceAnnotation extends DeltaCommand { + public final SerializationChunk newAnnotation; + public final String parent; + public final int index; + public final MetaPointer containment; + public final String replacedAnnotation; public ReplaceAnnotation( @NotNull String commandId, diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java index d32ed3f66..021624fab 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java @@ -9,12 +9,12 @@ * Delete current child replacedChild inside parent's containment at index, and all its descendants * (including annotation instances). Does NOT change references to any of the deleted nodes */ -public class ReplaceChild extends DeltaCommand { - public SerializationChunk newChild; - public String parent; - public MetaPointer containment; - public int index; - public String replacedChild; +public final class ReplaceChild extends DeltaCommand { + public final SerializationChunk newChild; + public final String parent; + public final MetaPointer containment; + public final int index; + public final String replacedChild; public ReplaceChild( @NotNull String commandId, From 1ddb5b0e5aca1b477b533204b33dc752756cc9d7 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sun, 19 Oct 2025 19:30:56 +0200 Subject: [PATCH 04/30] Introduce new DeltaCommand classes for composite, add, delete, change, and move operations across references, with immutability improvements and comprehensive documentation updates. --- .../commands/AddReferenceResolveInfo.java | 26 +++++++++++ .../messages/commands/AddReferenceTarget.java | 26 +++++++++++ .../commands/ChangeReferenceResolveInfo.java | 29 ++++++++++++ .../commands/ChangeReferenceTarget.java | 29 ++++++++++++ .../commands/DeleteReferenceResolveInfo.java | 26 +++++++++++ .../commands/DeleteReferenceTarget.java | 26 +++++++++++ ...ceEntryFromOtherReferenceInSameParent.java | 46 +++++++++++++++++++ .../MoveAndReplaceEntryInSameReference.java | 43 +++++++++++++++++ 8 files changed, 251 insertions(+) create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceResolveInfo.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceTarget.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceResolveInfo.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceTarget.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceResolveInfo.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceTarget.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReferenceInSameParent.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryInSameReference.java diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceResolveInfo.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceResolveInfo.java new file mode 100644 index 000000000..946778a25 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceResolveInfo.java @@ -0,0 +1,26 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; + +/** Add newResolveInfo as ResolveInfo to existing entry inside parent's reference at index. */ +public final class AddReferenceResolveInfo extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int index; + public final String newResolveInfo; + + public AddReferenceResolveInfo( + @NotNull String commandId, + String parent, + MetaPointer reference, + int index, + String newResolveInfo) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.index = index; + this.newResolveInfo = newResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceTarget.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceTarget.java new file mode 100644 index 000000000..c3828d85e --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceTarget.java @@ -0,0 +1,26 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; + +/** Add newTarget as target to existing entry inside parent's reference at index. */ +public final class AddReferenceTarget extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int index; + public final String newTarget; + + public AddReferenceTarget( + @NotNull String commandId, + String parent, + MetaPointer reference, + int index, + String newTarget) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.index = index; + this.newTarget = newTarget; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceResolveInfo.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceResolveInfo.java new file mode 100644 index 000000000..a76b4fc7f --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceResolveInfo.java @@ -0,0 +1,29 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; + +/** Change oldResolveInfo of existing entry inside parent's reference at index to newResolveInfo. */ +public final class ChangeReferenceResolveInfo extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int index; + public final String oldResolveInfo; + public final String newResolveInfo; + + public ChangeReferenceResolveInfo( + @NotNull String commandId, + String parent, + MetaPointer reference, + int index, + String oldResolveInfo, + String newResolveInfo) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.index = index; + this.oldResolveInfo = oldResolveInfo; + this.newResolveInfo = newResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceTarget.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceTarget.java new file mode 100644 index 000000000..2670fbfba --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceTarget.java @@ -0,0 +1,29 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; + +/** Change oldTarget of existing entry inside parent's reference at index to newTarget. */ +public final class ChangeReferenceTarget extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int index; + public final String oldTarget; + public final String newTarget; + + public ChangeReferenceTarget( + @NotNull String commandId, + String parent, + MetaPointer reference, + int index, + String oldTarget, + String newTarget) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.index = index; + this.oldTarget = oldTarget; + this.newTarget = newTarget; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceResolveInfo.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceResolveInfo.java new file mode 100644 index 000000000..bb74ff0fa --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceResolveInfo.java @@ -0,0 +1,26 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; + +/** Delete existing deletedResolveInfo from existing entry inside parent's reference at index. */ +public final class DeleteReferenceResolveInfo extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int index; + public final String deletedResolveInfo; + + public DeleteReferenceResolveInfo( + @NotNull String commandId, + String parent, + MetaPointer reference, + int index, + String deletedResolveInfo) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.index = index; + this.deletedResolveInfo = deletedResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceTarget.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceTarget.java new file mode 100644 index 000000000..580cac39a --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceTarget.java @@ -0,0 +1,26 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; + +/** Delete existing deletedTarget from existing entry inside parent's reference at index. */ +public final class DeleteReferenceTarget extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int index; + public final String deletedTarget; + + public DeleteReferenceTarget( + @NotNull String commandId, + String parent, + MetaPointer reference, + int index, + String deletedTarget) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.index = index; + this.deletedTarget = deletedTarget; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReferenceInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReferenceInSameParent.java new file mode 100644 index 000000000..8813187ca --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReferenceInSameParent.java @@ -0,0 +1,46 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Move existing entry movedTarget/movedResolveInfo inside parent's oldReference at oldIndex to + * parent's newReference at newIndex, replacing existing entry + * replacedTarget/replacedResolveInfo[32] in parent's newReference at newIndex. + */ +public final class MoveAndReplaceEntryFromOtherReferenceInSameParent extends DeltaCommand { + public final String parent; + public final MetaPointer newReference; + public final int newIndex; + public final @Nullable String replacedTarget; + public final @Nullable String replacedResolveInfo; + public final MetaPointer oldReference; + public final int oldIndex; + public final @Nullable String movedTarget; + public final @Nullable String movedResolveInfo; + + public MoveAndReplaceEntryFromOtherReferenceInSameParent( + @NotNull String commandId, + String parent, + MetaPointer newReference, + int newIndex, + @Nullable String replacedTarget, + @Nullable String replacedResolveInfo, + MetaPointer oldReference, + int oldIndex, + @Nullable String movedTarget, + @Nullable String movedResolveInfo) { + super(commandId); + this.parent = parent; + this.newReference = newReference; + this.newIndex = newIndex; + this.replacedTarget = replacedTarget; + this.replacedResolveInfo = replacedResolveInfo; + this.oldReference = oldReference; + this.oldIndex = oldIndex; + this.movedTarget = movedTarget; + this.movedResolveInfo = movedResolveInfo; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryInSameReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryInSameReference.java new file mode 100644 index 000000000..53afc0299 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryInSameReference.java @@ -0,0 +1,43 @@ +package io.lionweb.client.delta.messages.commands; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.serialization.data.MetaPointer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Move existing entry movedTarget/movedResolveInfo[32] inside parent's reference at oldIndex inside + * parent's reference at newIndex, replacing existing entry replacedTarget/replacedResolveInfo[32] + * in parent's reference at newIndex. + */ +public final class MoveAndReplaceEntryInSameReference extends DeltaCommand { + public final String parent; + public final MetaPointer reference; + public final int oldIndex; + public final @Nullable String movedTarget; + public final @Nullable String movedResolveInfo; + public final int newIndex; + public final @Nullable String replacedTarget; + public final @Nullable String replacedResolveInfo; + + public MoveAndReplaceEntryInSameReference( + @NotNull String commandId, + String parent, + MetaPointer reference, + int oldIndex, + @Nullable String movedTarget, + @Nullable String movedResolveInfo, + int newIndex, + @Nullable String replacedTarget, + @Nullable String replacedResolveInfo) { + super(commandId); + this.parent = parent; + this.reference = reference; + this.oldIndex = oldIndex; + this.movedTarget = movedTarget; + this.movedResolveInfo = movedResolveInfo; + this.newIndex = newIndex; + this.replacedTarget = replacedTarget; + this.replacedResolveInfo = replacedResolveInfo; + } +} From 8c60ac75430abace7e7602cc1bd5f20e00d30d00 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 20 Oct 2025 20:38:51 +0200 Subject: [PATCH 05/30] Introduce new DeltaEvent classes for references, annotations, children, and general events, enhancing immutability and adding comprehensive documentation. --- .../client/delta/DeltaEventReceiver.java | 4 +- .../delta/messages/CommonDeltaEvent.java | 18 +++++++ .../messages/commands/AddAnnotation.java | 25 --------- .../delta/messages/commands/AddChild.java | 32 ----------- .../delta/messages/commands/AddPartition.java | 13 ----- .../delta/messages/commands/AddProperty.java | 54 ------------------- .../delta/messages/commands/AddReference.java | 30 ----------- .../commands/AddReferenceResolveInfo.java | 26 --------- .../messages/commands/AddReferenceTarget.java | 26 --------- .../messages/commands/ChangeProperty.java | 54 ------------------- .../messages/commands/ChangeReference.java | 39 -------------- .../commands/ChangeReferenceResolveInfo.java | 29 ---------- .../commands/ChangeReferenceTarget.java | 29 ---------- .../messages/commands/DeleteAnnotation.java | 23 -------- .../delta/messages/commands/DeleteChild.java | 29 ---------- .../messages/commands/DeletePartition.java | 12 ----- .../messages/commands/DeleteProperty.java | 15 ------ .../messages/commands/DeleteReference.java | 30 ----------- .../commands/DeleteReferenceResolveInfo.java | 26 --------- .../commands/DeleteReferenceTarget.java | 26 --------- ...veAndReplaceAnnotationFromOtherParent.java | 29 ---------- .../MoveAndReplaceAnnotationInSameParent.java | 23 -------- ...veAndReplaceChildFromOtherContainment.java | 32 ----------- ...ChildFromOtherContainmentInSameParent.java | 31 ----------- .../MoveAndReplaceChildInSameContainment.java | 22 -------- ...MoveAndReplaceEntryFromOtherReference.java | 49 ----------------- ...ceEntryFromOtherReferenceInSameParent.java | 46 ---------------- .../MoveAndReplaceEntryInSameReference.java | 43 --------------- .../MoveAnnotationFromOtherParent.java | 19 ------- .../commands/MoveAnnotationInSameParent.java | 17 ------ .../MoveChildFromOtherContainment.java | 25 --------- ...ChildFromOtherContainmentInSameParent.java | 22 -------- .../commands/MoveChildInSameContainment.java | 15 ------ .../commands/MoveEntryFromOtherReference.java | 42 --------------- ...veEntryFromOtherReferenceInSameParent.java | 39 -------------- .../commands/MoveEntryInSameReference.java | 36 ------------- .../messages/commands/ReplaceAnnotation.java | 33 ------------ .../delta/messages/commands/ReplaceChild.java | 33 ------------ .../delta/messages/events/PropertyAdded.java | 18 ------- 39 files changed, 20 insertions(+), 1094 deletions(-) create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/CommonDeltaEvent.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceResolveInfo.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceTarget.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReference.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceResolveInfo.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceTarget.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceResolveInfo.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceTarget.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReference.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReferenceInSameParent.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryInSameReference.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReference.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReferenceInSameParent.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryInSameReference.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/events/PropertyAdded.java diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java b/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java index b55769145..53c15a545 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java @@ -1,8 +1,8 @@ package io.lionweb.client.delta; -import io.lionweb.client.delta.messages.DeltaEvent; +import io.lionweb.client.delta.messages.CommonDeltaEvent; public interface DeltaEventReceiver { - void receiveEvent(DeltaEvent event); + void receiveEvent(CommonDeltaEvent event); } diff --git a/client/src/main/java/io/lionweb/client/delta/messages/CommonDeltaEvent.java b/client/src/main/java/io/lionweb/client/delta/messages/CommonDeltaEvent.java new file mode 100644 index 000000000..849b0f709 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/CommonDeltaEvent.java @@ -0,0 +1,18 @@ +package io.lionweb.client.delta.messages; + +import io.lionweb.client.delta.CommandSource; +import java.util.LinkedList; +import java.util.List; + +public class CommonDeltaEvent extends DeltaEvent { + public final int sequenceNumber; + public final List originCommands = new LinkedList<>(); + + public CommonDeltaEvent(int sequenceNumber) { + this.sequenceNumber = sequenceNumber; + } + + public void addSource(CommandSource source) { + originCommands.add(source); + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java deleted file mode 100644 index 7952cfc4d..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddAnnotation.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.SerializationChunk; -import org.jetbrains.annotations.NotNull; - -/** - * Add new node newAnnotation to parent's annotations at index. newAnnotation might be a single node - * or an arbitrary complex subtree. All nodes in that subtree MUST be new, i.e. their id MUST NOT - * exist in the repository. Nodes in that subtree MAY have references to already existing nodes, and - * already existing nodes MAY have references to nodes in that subtree. - */ -public final class AddAnnotation extends DeltaCommand { - public final String parent; - public final SerializationChunk newAnnotation; - public final int index; - - public AddAnnotation( - @NotNull String commandId, String parent, SerializationChunk newAnnotation, int index) { - super(commandId); - this.parent = parent; - this.newAnnotation = newAnnotation; - this.index = index; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java deleted file mode 100644 index ca5a327ef..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddChild.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import io.lionweb.serialization.data.SerializationChunk; -import org.jetbrains.annotations.NotNull; - -/** - * Add new node newChild to parent in containment at index. newChild might be a single node or an - * arbitrary complex subtree. All nodes in that subtree MUST be new, i.e. their id MUST NOT exist in - * the repository. Nodes in that subtree MAY have references to already existing nodes, and already - * existing nodes MAY have references to nodes in that subtree. - */ -public final class AddChild extends DeltaCommand { - public final String parent; - public final SerializationChunk newChild; - public final MetaPointer containment; - public final int index; - - public AddChild( - @NotNull String commandId, - String parent, - SerializationChunk newChild, - MetaPointer containment, - int index) { - super(commandId); - this.parent = parent; - this.newChild = newChild; - this.containment = containment; - this.index = index; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java deleted file mode 100644 index 2cfbd94a9..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddPartition.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.SerializationChunk; - -public final class AddPartition extends DeltaCommand { - public final SerializationChunk newPartition; - - public AddPartition(String commandId, SerializationChunk newPartition) { - super(commandId); - this.newPartition = newPartition; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java deleted file mode 100644 index af66470bf..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddProperty.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import java.util.Objects; -import org.jetbrains.annotations.Nullable; - -public final class AddProperty extends DeltaCommand { - public final String node; - public final MetaPointer property; - public final @Nullable String newValue; - - public AddProperty( - String commandId, String node, MetaPointer property, @Nullable String newValue) { - super(commandId); - this.node = node; - this.property = property; - this.newValue = newValue; - } - - @Override - public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; - AddProperty that = (AddProperty) o; - return Objects.equals(commandId, that.commandId) - && Objects.equals(node, that.node) - && Objects.equals(property, that.property) - && Objects.equals(newValue, that.newValue); - } - - @Override - public int hashCode() { - return Objects.hash(commandId, node, property, newValue); - } - - @Override - public String toString() { - return "AddProperty{" - + "node='" - + node - + '\'' - + ", property=" - + property - + ", newValue='" - + newValue - + '\'' - + ", commandId='" - + commandId - + '\'' - + ", protocolMessages=" - + protocolMessages - + '}'; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java deleted file mode 100644 index 9deedc3e6..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReference.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** Add newTarget / newResolveInfo to parent's reference at index. */ -public final class AddReference extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int index; - public final @Nullable String newTarget; - public final @Nullable String newResolveInfo; - - public AddReference( - @NotNull String commandId, - String parent, - MetaPointer reference, - int index, - @Nullable String newTarget, - @Nullable String newResolveInfo) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.index = index; - this.newTarget = newTarget; - this.newResolveInfo = newResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceResolveInfo.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceResolveInfo.java deleted file mode 100644 index 946778a25..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceResolveInfo.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; - -/** Add newResolveInfo as ResolveInfo to existing entry inside parent's reference at index. */ -public final class AddReferenceResolveInfo extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int index; - public final String newResolveInfo; - - public AddReferenceResolveInfo( - @NotNull String commandId, - String parent, - MetaPointer reference, - int index, - String newResolveInfo) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.index = index; - this.newResolveInfo = newResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceTarget.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceTarget.java deleted file mode 100644 index c3828d85e..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/AddReferenceTarget.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; - -/** Add newTarget as target to existing entry inside parent's reference at index. */ -public final class AddReferenceTarget extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int index; - public final String newTarget; - - public AddReferenceTarget( - @NotNull String commandId, - String parent, - MetaPointer reference, - int index, - String newTarget) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.index = index; - this.newTarget = newTarget; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java deleted file mode 100644 index a6d4a2643..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeProperty.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import java.util.Objects; -import org.jetbrains.annotations.Nullable; - -public final class ChangeProperty extends DeltaCommand { - public final String node; - public final MetaPointer property; - public final @Nullable String newValue; - - public ChangeProperty( - String commandId, String node, MetaPointer property, @Nullable String newValue) { - super(commandId); - this.node = node; - this.property = property; - this.newValue = newValue; - } - - @Override - public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; - ChangeProperty that = (ChangeProperty) o; - return Objects.equals(commandId, that.commandId) - && Objects.equals(node, that.node) - && Objects.equals(property, that.property) - && Objects.equals(newValue, that.newValue); - } - - @Override - public int hashCode() { - return Objects.hash(commandId, node, property, newValue); - } - - @Override - public String toString() { - return "ChangeProperty{" - + "node='" - + node - + '\'' - + ", property=" - + property - + ", newValue='" - + newValue - + '\'' - + ", commandId='" - + commandId - + '\'' - + ", protocolMessages=" - + protocolMessages - + '}'; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReference.java deleted file mode 100644 index 3e8a1c9a8..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReference.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Replace existing entry oldTarget/oldResolveInfo inside parent's reference at index with - * newTarget/newResolveInfo. - */ -public final class ChangeReference extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int index; - public final @Nullable String oldTarget; - public final @Nullable String oldResolveInfo; - public final @Nullable String newTarget; - public final @Nullable String newResolveInfo; - - public ChangeReference( - @NotNull String commandId, - String parent, - MetaPointer reference, - int index, - @Nullable String oldTarget, - @Nullable String oldResolveInfo, - @Nullable String newTarget, - @Nullable String newResolveInfo) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.index = index; - this.oldTarget = oldTarget; - this.oldResolveInfo = oldResolveInfo; - this.newTarget = newTarget; - this.newResolveInfo = newResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceResolveInfo.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceResolveInfo.java deleted file mode 100644 index a76b4fc7f..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceResolveInfo.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; - -/** Change oldResolveInfo of existing entry inside parent's reference at index to newResolveInfo. */ -public final class ChangeReferenceResolveInfo extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int index; - public final String oldResolveInfo; - public final String newResolveInfo; - - public ChangeReferenceResolveInfo( - @NotNull String commandId, - String parent, - MetaPointer reference, - int index, - String oldResolveInfo, - String newResolveInfo) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.index = index; - this.oldResolveInfo = oldResolveInfo; - this.newResolveInfo = newResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceTarget.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceTarget.java deleted file mode 100644 index 2670fbfba..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/ChangeReferenceTarget.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; - -/** Change oldTarget of existing entry inside parent's reference at index to newTarget. */ -public final class ChangeReferenceTarget extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int index; - public final String oldTarget; - public final String newTarget; - - public ChangeReferenceTarget( - @NotNull String commandId, - String parent, - MetaPointer reference, - int index, - String oldTarget, - String newTarget) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.index = index; - this.oldTarget = oldTarget; - this.newTarget = newTarget; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java deleted file mode 100644 index 5ed033482..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteAnnotation.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import org.jetbrains.annotations.NotNull; - -/** - * Delete existing node deletedAnnotation from parent's annotations at index, and all its - * descendants (including annotation instances). Does NOT change references to any of the deleted - * nodes. - */ -public final class DeleteAnnotation extends DeltaCommand { - public final String node; - public final int index; - public final String deletedAnnotation; - - public DeleteAnnotation( - @NotNull String commandId, String node, int index, String deletedAnnotation) { - super(commandId); - this.node = node; - this.index = index; - this.deletedAnnotation = deletedAnnotation; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java deleted file mode 100644 index 4c8503c82..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteChild.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; - -/** - * Delete existing node deletedChild from parent's containment at index, and all its descendants - * (including annotation instances). Does NOT change references to any of the deleted nodes. - */ -public final class DeleteChild extends DeltaCommand { - public final String parent; - public final MetaPointer containment; - public final int index; - public final String deletedChild; - - public DeleteChild( - @NotNull String commandId, - String parent, - MetaPointer containment, - int index, - String deletedChild) { - super(commandId); - this.parent = parent; - this.containment = containment; - this.index = index; - this.deletedChild = deletedChild; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java deleted file mode 100644 index 0e8cad72b..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeletePartition.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; - -public final class DeletePartition extends DeltaCommand { - public final String deletedPartition; - - public DeletePartition(String commandId, String deletedPartition) { - super(commandId); - this.deletedPartition = deletedPartition; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java deleted file mode 100644 index b269fa7a6..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteProperty.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; - -public final class DeleteProperty extends DeltaCommand { - public final String node; - public final MetaPointer property; - - public DeleteProperty(String commandId, String node, MetaPointer property) { - super(commandId); - this.node = node; - this.property = property; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java deleted file mode 100644 index af2254bb0..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReference.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** Delete existing entry deletedTarget/deletedResolveInfo from parent's reference at index. */ -public final class DeleteReference extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int index; - public final @Nullable String deletedTarget; - public final @Nullable String deletedResolveInfo; - - public DeleteReference( - @NotNull String commandId, - String parent, - MetaPointer reference, - int index, - @Nullable String deletedTarget, - @Nullable String deletedResolveInfo) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.index = index; - this.deletedTarget = deletedTarget; - this.deletedResolveInfo = deletedResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceResolveInfo.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceResolveInfo.java deleted file mode 100644 index bb74ff0fa..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceResolveInfo.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; - -/** Delete existing deletedResolveInfo from existing entry inside parent's reference at index. */ -public final class DeleteReferenceResolveInfo extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int index; - public final String deletedResolveInfo; - - public DeleteReferenceResolveInfo( - @NotNull String commandId, - String parent, - MetaPointer reference, - int index, - String deletedResolveInfo) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.index = index; - this.deletedResolveInfo = deletedResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceTarget.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceTarget.java deleted file mode 100644 index 580cac39a..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/DeleteReferenceTarget.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; - -/** Delete existing deletedTarget from existing entry inside parent's reference at index. */ -public final class DeleteReferenceTarget extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int index; - public final String deletedTarget; - - public DeleteReferenceTarget( - @NotNull String commandId, - String parent, - MetaPointer reference, - int index, - String deletedTarget) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.index = index; - this.deletedTarget = deletedTarget; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java deleted file mode 100644 index 657b4ce35..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationFromOtherParent.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import org.jetbrains.annotations.NotNull; - -/** - * Move existing node movedAnnotation inside newParent's annotations at newIndex. Delete current - * node replacedAnnotation at newParent's annotations at newIndex, and all its descendants - * (including annotation instances). Does NOT change references to any of the deleted nodes - */ -public final class MoveAndReplaceAnnotationFromOtherParent extends DeltaCommand { - public final String newParent; - public final int newIndex; - public final String replacedAnnotation; - public final String movedAnnotation; - - public MoveAndReplaceAnnotationFromOtherParent( - @NotNull String commandId, - String newParent, - int newIndex, - String replacedAnnotation, - String movedAnnotation) { - super(commandId); - this.newParent = newParent; - this.newIndex = newIndex; - this.replacedAnnotation = replacedAnnotation; - this.movedAnnotation = movedAnnotation; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java deleted file mode 100644 index bcb4f95af..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceAnnotationInSameParent.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import org.jetbrains.annotations.NotNull; - -/** - * Move existing node movedAnnotation within the same parent to newIndex. Delete current node - * replacedAnnotation at movedAnnotation's parent’s annotations at newIndex, and all its descendants - * (including annotation instances). Does NOT change references to any of the deleted nodes. - */ -public final class MoveAndReplaceAnnotationInSameParent extends DeltaCommand { - public final int newIndex; - public final String replacedAnnotation; - public final String movedAnnotation; - - public MoveAndReplaceAnnotationInSameParent( - @NotNull String commandId, int newIndex, String replacedAnnotation, String movedAnnotation) { - super(commandId); - this.newIndex = newIndex; - this.replacedAnnotation = replacedAnnotation; - this.movedAnnotation = movedAnnotation; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java deleted file mode 100644 index 5ac53cfb3..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainment.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; - -/** - * Move existing node movedChild inside newParent's newContainment at newIndex. Delete current child - * replacedChild inside newParent's newContainment at newIndex, and all its descendants (including - * annotation instances). Does NOT change references to any of the deleted nodes. - */ -public final class MoveAndReplaceChildFromOtherContainment extends DeltaCommand { - public final String newParent; - public final MetaPointer newContainment; - public final int newIndex; - public final String replacedChild; - public final String movedChild; - - public MoveAndReplaceChildFromOtherContainment( - String commandId, - String newParent, - MetaPointer newContainment, - int newIndex, - String replacedChild, - String movedChild) { - super(commandId); - this.newParent = newParent; - this.newContainment = newContainment; - this.newIndex = newIndex; - this.replacedChild = replacedChild; - this.movedChild = movedChild; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java deleted file mode 100644 index 2fcb418c0..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildFromOtherContainmentInSameParent.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; - -/** - * Move existing node movedChild (currently inside one of movedChild's parent’s containments other - * than newContainment) inside movedChild's parent’s newContainment at newIndex. Delete current - * child replacedChild inside movedChild's parent’s newContainment at newIndex, and all its - * descendants (including annotation instances). Does NOT change references to any of the deleted - * nodes. - */ -public final class MoveAndReplaceChildFromOtherContainmentInSameParent extends DeltaCommand { - public final MetaPointer newContainment; - public final int newIndex; - public final String replacedChild; - public final String movedChild; - - public MoveAndReplaceChildFromOtherContainmentInSameParent( - String commandId, - MetaPointer newContainment, - int newIndex, - String replacedChild, - String movedChild) { - super(commandId); - this.newContainment = newContainment; - this.newIndex = newIndex; - this.replacedChild = replacedChild; - this.movedChild = movedChild; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java deleted file mode 100644 index efcfa9f36..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceChildInSameContainment.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; - -/** - * Move existing node movedChild within its current containment to newIndex. Delete current child - * replacedChild inside the same containment at newIndex, and all its descendants (including - * annotation instances). Does NOT change references to any of the deleted nodes - */ -public final class MoveAndReplaceChildInSameContainment extends DeltaCommand { - public final int newIndex; - public final String replacedChild; - public final String movedChild; - - public MoveAndReplaceChildInSameContainment( - String commandId, int newIndex, String replacedChild, String movedChild) { - super(commandId); - this.newIndex = newIndex; - this.replacedChild = replacedChild; - this.movedChild = movedChild; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReference.java deleted file mode 100644 index d4492ecfa..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReference.java +++ /dev/null @@ -1,49 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Move existing entry movedTarget/movedResolveInfo inside oldParent's oldReference at oldIndex to - * newParent's newReference at newIndex, replacing existing entry replacedTarget/replacedResolveInfo - * in newParent's newReference at newIndex. - */ -public final class MoveAndReplaceEntryFromOtherReference extends DeltaCommand { - public final String newParent; - public final MetaPointer newReference; - public final int newIndex; - public final @Nullable String replacedTarget; - public final @Nullable String replacedResolveInfo; - public final String oldParent; - public final MetaPointer oldReference; - public final int oldIndex; - public final @Nullable String movedTarget; - public final @Nullable String movedResolveInfo; - - public MoveAndReplaceEntryFromOtherReference( - @NotNull String commandId, - String newParent, - MetaPointer newReference, - int newIndex, - @Nullable String replacedTarget, - @Nullable String replacedResolveInfo, - String oldParent, - MetaPointer oldReference, - int oldIndex, - @Nullable String movedTarget, - @Nullable String movedResolveInfo) { - super(commandId); - this.newParent = newParent; - this.newReference = newReference; - this.newIndex = newIndex; - this.replacedTarget = replacedTarget; - this.replacedResolveInfo = replacedResolveInfo; - this.oldParent = oldParent; - this.oldReference = oldReference; - this.oldIndex = oldIndex; - this.movedTarget = movedTarget; - this.movedResolveInfo = movedResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReferenceInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReferenceInSameParent.java deleted file mode 100644 index 8813187ca..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryFromOtherReferenceInSameParent.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Move existing entry movedTarget/movedResolveInfo inside parent's oldReference at oldIndex to - * parent's newReference at newIndex, replacing existing entry - * replacedTarget/replacedResolveInfo[32] in parent's newReference at newIndex. - */ -public final class MoveAndReplaceEntryFromOtherReferenceInSameParent extends DeltaCommand { - public final String parent; - public final MetaPointer newReference; - public final int newIndex; - public final @Nullable String replacedTarget; - public final @Nullable String replacedResolveInfo; - public final MetaPointer oldReference; - public final int oldIndex; - public final @Nullable String movedTarget; - public final @Nullable String movedResolveInfo; - - public MoveAndReplaceEntryFromOtherReferenceInSameParent( - @NotNull String commandId, - String parent, - MetaPointer newReference, - int newIndex, - @Nullable String replacedTarget, - @Nullable String replacedResolveInfo, - MetaPointer oldReference, - int oldIndex, - @Nullable String movedTarget, - @Nullable String movedResolveInfo) { - super(commandId); - this.parent = parent; - this.newReference = newReference; - this.newIndex = newIndex; - this.replacedTarget = replacedTarget; - this.replacedResolveInfo = replacedResolveInfo; - this.oldReference = oldReference; - this.oldIndex = oldIndex; - this.movedTarget = movedTarget; - this.movedResolveInfo = movedResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryInSameReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryInSameReference.java deleted file mode 100644 index 53afc0299..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAndReplaceEntryInSameReference.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Move existing entry movedTarget/movedResolveInfo[32] inside parent's reference at oldIndex inside - * parent's reference at newIndex, replacing existing entry replacedTarget/replacedResolveInfo[32] - * in parent's reference at newIndex. - */ -public final class MoveAndReplaceEntryInSameReference extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int oldIndex; - public final @Nullable String movedTarget; - public final @Nullable String movedResolveInfo; - public final int newIndex; - public final @Nullable String replacedTarget; - public final @Nullable String replacedResolveInfo; - - public MoveAndReplaceEntryInSameReference( - @NotNull String commandId, - String parent, - MetaPointer reference, - int oldIndex, - @Nullable String movedTarget, - @Nullable String movedResolveInfo, - int newIndex, - @Nullable String replacedTarget, - @Nullable String replacedResolveInfo) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.oldIndex = oldIndex; - this.movedTarget = movedTarget; - this.movedResolveInfo = movedResolveInfo; - this.newIndex = newIndex; - this.replacedTarget = replacedTarget; - this.replacedResolveInfo = replacedResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java deleted file mode 100644 index 8b58f9715..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationFromOtherParent.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import org.jetbrains.annotations.NotNull; - -/** Move existing node movedAnnotation inside newParent's annotations at newIndex. */ -public final class MoveAnnotationFromOtherParent extends DeltaCommand { - public final String newParent; - public final int newIndex; - public final String movedAnnotation; - - public MoveAnnotationFromOtherParent( - @NotNull String commandId, String newParent, int newIndex, String movedAnnotation) { - super(commandId); - this.newParent = newParent; - this.newIndex = newIndex; - this.movedAnnotation = movedAnnotation; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java deleted file mode 100644 index 04cb4ce99..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveAnnotationInSameParent.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import org.jetbrains.annotations.NotNull; - -/** Move existing node movedAnnotation within the same parent to newIndex. */ -public final class MoveAnnotationInSameParent extends DeltaCommand { - public final int newIndex; - public final String movedAnnotation; - - public MoveAnnotationInSameParent( - @NotNull String commandId, int newIndex, String movedAnnotation) { - super(commandId); - this.newIndex = newIndex; - this.movedAnnotation = movedAnnotation; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java deleted file mode 100644 index b2f6e66a9..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainment.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; - -/** Move existing node movedChild inside newParent's newContainment at newIndex. */ -public final class MoveChildFromOtherContainment extends DeltaCommand { - public final String newParent; - public final MetaPointer newContainment; - public final int newIndex; - public final String movedChild; - - public MoveChildFromOtherContainment( - String commandId, - String newParent, - MetaPointer newContainment, - int newIndex, - String movedChild) { - super(commandId); - this.newParent = newParent; - this.newContainment = newContainment; - this.newIndex = newIndex; - this.movedChild = movedChild; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java deleted file mode 100644 index bed229644..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildFromOtherContainmentInSameParent.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; - -/** - * Move existing node movedChild (currently inside one of movedChild's parent’s containments other - * than newContainment) inside movedChild's parent’s newContainment at newIndex. - */ -public final class MoveChildFromOtherContainmentInSameParent extends DeltaCommand { - public final MetaPointer newContainment; - public final int newIndex; - public final String movedChild; - - public MoveChildFromOtherContainmentInSameParent( - String commandId, MetaPointer newContainment, int newIndex, String movedChild) { - super(commandId); - this.newContainment = newContainment; - this.newIndex = newIndex; - this.movedChild = movedChild; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java deleted file mode 100644 index 4c1f29113..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveChildInSameContainment.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; - -/** Move existing node movedChild within its current containment to newIndex. */ -public final class MoveChildInSameContainment extends DeltaCommand { - public final int newIndex; - public final String movedChild; - - public MoveChildInSameContainment(String commandId, int newIndex, String movedChild) { - super(commandId); - this.newIndex = newIndex; - this.movedChild = movedChild; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReference.java deleted file mode 100644 index 8daf50e84..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReference.java +++ /dev/null @@ -1,42 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Move existing entry movedTarget/movedResolveInfo inside oldParent's oldReference at oldIndex to - * newParent's newReference at newIndex. - */ -public final class MoveEntryFromOtherReference extends DeltaCommand { - public final String newParent; - public final MetaPointer newReference; - public final int newIndex; - public final @NotNull String oldParent; - public final MetaPointer oldReference; - public final int oldIndex; - public final @Nullable String movedTarget; - public final @Nullable String movedResolveInfo; - - public MoveEntryFromOtherReference( - @NotNull String commandId, - String newParent, - MetaPointer newReference, - int newIndex, - @NotNull String oldParent, - MetaPointer oldReference, - int oldIndex, - @Nullable String movedTarget, - @Nullable String movedResolveInfo) { - super(commandId); - this.newParent = newParent; - this.newReference = newReference; - this.newIndex = newIndex; - this.oldParent = oldParent; - this.oldReference = oldReference; - this.oldIndex = oldIndex; - this.movedTarget = movedTarget; - this.movedResolveInfo = movedResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReferenceInSameParent.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReferenceInSameParent.java deleted file mode 100644 index 5ef7a82fa..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryFromOtherReferenceInSameParent.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Move existing entry movedTarget/movedResolveInfo inside parent's oldReference at oldIndex to - * parent's newReference at newIndex. - */ -public final class MoveEntryFromOtherReferenceInSameParent extends DeltaCommand { - public final String parent; - public final MetaPointer newReference; - public final int newIndex; - public final MetaPointer oldReference; - public final int oldIndex; - public final @Nullable String movedTarget; - public final @Nullable String movedResolveInfo; - - public MoveEntryFromOtherReferenceInSameParent( - @NotNull String commandId, - String parent, - MetaPointer newReference, - int newIndex, - MetaPointer oldReference, - int oldIndex, - @Nullable String movedTarget, - @Nullable String movedResolveInfo) { - super(commandId); - this.parent = parent; - this.newReference = newReference; - this.newIndex = newIndex; - this.oldReference = oldReference; - this.oldIndex = oldIndex; - this.movedTarget = movedTarget; - this.movedResolveInfo = movedResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryInSameReference.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryInSameReference.java deleted file mode 100644 index 26347f4ba..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/MoveEntryInSameReference.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Move existing entry movedTarget/movedResolveInfo inside parent's reference at oldIndex inside - * parent's reference at newIndex. - */ -public final class MoveEntryInSameReference extends DeltaCommand { - public final String parent; - public final MetaPointer reference; - public final int oldIndex; - public final int newIndex; - public final @Nullable String movedTarget; - public final @Nullable String movedResolveInfo; - - public MoveEntryInSameReference( - @NotNull String commandId, - String parent, - MetaPointer reference, - int oldIndex, - int newIndex, - @Nullable String movedTarget, - @Nullable String movedResolveInfo) { - super(commandId); - this.parent = parent; - this.reference = reference; - this.oldIndex = oldIndex; - this.newIndex = newIndex; - this.movedTarget = movedTarget; - this.movedResolveInfo = movedResolveInfo; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java deleted file mode 100644 index b7c96ceed..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceAnnotation.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import io.lionweb.serialization.data.SerializationChunk; -import org.jetbrains.annotations.NotNull; - -/** - * Delete current node replacedAnnotation at parent's annotations at index, and all its descendants - * (including annotation instances). Does NOT change references to any of the deleted nodes. - */ -public final class ReplaceAnnotation extends DeltaCommand { - public final SerializationChunk newAnnotation; - public final String parent; - public final int index; - public final MetaPointer containment; - public final String replacedAnnotation; - - public ReplaceAnnotation( - @NotNull String commandId, - SerializationChunk newAnnotation, - String parent, - MetaPointer containment, - int index, - String replacedAnnotation) { - super(commandId); - this.newAnnotation = newAnnotation; - this.parent = parent; - this.containment = containment; - this.index = index; - this.replacedAnnotation = replacedAnnotation; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java b/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java deleted file mode 100644 index 021624fab..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/commands/ReplaceChild.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.lionweb.client.delta.messages.commands; - -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.serialization.data.MetaPointer; -import io.lionweb.serialization.data.SerializationChunk; -import org.jetbrains.annotations.NotNull; - -/** - * Delete current child replacedChild inside parent's containment at index, and all its descendants - * (including annotation instances). Does NOT change references to any of the deleted nodes - */ -public final class ReplaceChild extends DeltaCommand { - public final SerializationChunk newChild; - public final String parent; - public final MetaPointer containment; - public final int index; - public final String replacedChild; - - public ReplaceChild( - @NotNull String commandId, - SerializationChunk newChild, - String parent, - MetaPointer containment, - int index, - String replacedChild) { - super(commandId); - this.newChild = newChild; - this.parent = parent; - this.containment = containment; - this.index = index; - this.replacedChild = replacedChild; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/events/PropertyAdded.java b/client/src/main/java/io/lionweb/client/delta/messages/events/PropertyAdded.java deleted file mode 100644 index b8d63ddda..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/events/PropertyAdded.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.lionweb.client.delta.messages.events; - -import io.lionweb.client.delta.messages.DeltaEvent; -import io.lionweb.serialization.data.MetaPointer; - -public class PropertyAdded extends DeltaEvent { - - public final String node; - public final MetaPointer property; - public final String newValue; - - public PropertyAdded(int sequenceNumber, String node, MetaPointer property, String newValue) { - super(sequenceNumber); - this.node = node; - this.property = property; - this.newValue = newValue; - } -} From 2f486da9a39014ab2261be7efb3872207f6f8896 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 20 Oct 2025 20:42:25 +0200 Subject: [PATCH 06/30] Refactor DeltaQuery classes: reorganize packages, add `ListPartitions` and `Reconnect` classes, and improve structure for queries and subscriptions. --- .../delta/messages/queries/ListPartitions.java | 11 +++++++++++ .../queries/partitcipations/Reconnect.java | 16 ++++++++++++++++ .../queries/{ => partitcipations}/SignOff.java | 2 +- .../queries/{ => partitcipations}/SignOn.java | 2 +- .../SubscribeToChangingPartitions.java | 2 +- .../SubscribeToPartitionContents.java | 2 +- .../UnsubscribeFromPartitionContents.java | 2 +- 7 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/ListPartitions.java create mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/Reconnect.java rename client/src/main/java/io/lionweb/client/delta/messages/queries/{ => partitcipations}/SignOff.java (76%) rename client/src/main/java/io/lionweb/client/delta/messages/queries/{ => partitcipations}/SignOn.java (89%) rename client/src/main/java/io/lionweb/client/delta/messages/queries/{ => subscriptions}/SubscribeToChangingPartitions.java (92%) rename client/src/main/java/io/lionweb/client/delta/messages/queries/{ => subscriptions}/SubscribeToPartitionContents.java (86%) rename client/src/main/java/io/lionweb/client/delta/messages/queries/{ => subscriptions}/UnsubscribeFromPartitionContents.java (82%) diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/ListPartitions.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/ListPartitions.java new file mode 100644 index 000000000..8aba32c33 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/ListPartitions.java @@ -0,0 +1,11 @@ +package io.lionweb.client.delta.messages.queries; + +import io.lionweb.client.delta.messages.DeltaQuery; +import org.jetbrains.annotations.NotNull; + +public class ListPartitions extends DeltaQuery { + + public ListPartitions(@NotNull String queryId) { + super(queryId); + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/Reconnect.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/Reconnect.java new file mode 100644 index 000000000..c0f94dda5 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/Reconnect.java @@ -0,0 +1,16 @@ +package io.lionweb.client.delta.messages.queries.partitcipations; + +import io.lionweb.client.delta.messages.DeltaQuery; +import org.jetbrains.annotations.NotNull; + +public class Reconnect extends DeltaQuery { + public final String participationId; + public final String lastReceivedSequenceNumber; + + public Reconnect( + @NotNull String queryId, String participationId, String lastReceivedSequenceNumber) { + super(queryId); + this.participationId = participationId; + this.lastReceivedSequenceNumber = lastReceivedSequenceNumber; + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/SignOff.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOff.java similarity index 76% rename from client/src/main/java/io/lionweb/client/delta/messages/queries/SignOff.java rename to client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOff.java index cc89a3579..7e4899365 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/SignOff.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOff.java @@ -1,4 +1,4 @@ -package io.lionweb.client.delta.messages.queries; +package io.lionweb.client.delta.messages.queries.partitcipations; import io.lionweb.client.delta.messages.DeltaQuery; import org.jetbrains.annotations.NotNull; diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/SignOn.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOn.java similarity index 89% rename from client/src/main/java/io/lionweb/client/delta/messages/queries/SignOn.java rename to client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOn.java index bbfa9b25a..57aa70240 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/SignOn.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOn.java @@ -1,4 +1,4 @@ -package io.lionweb.client.delta.messages.queries; +package io.lionweb.client.delta.messages.queries.partitcipations; import io.lionweb.client.delta.DeltaProtocolVersion; import io.lionweb.client.delta.messages.DeltaQuery; diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToChangingPartitions.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToChangingPartitions.java similarity index 92% rename from client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToChangingPartitions.java rename to client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToChangingPartitions.java index 077c3ff4d..982ca7622 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToChangingPartitions.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToChangingPartitions.java @@ -1,4 +1,4 @@ -package io.lionweb.client.delta.messages.queries; +package io.lionweb.client.delta.messages.queries.subscriptions; import io.lionweb.client.delta.messages.DeltaQuery; import org.jetbrains.annotations.NotNull; diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToPartitionContents.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToPartitionContents.java similarity index 86% rename from client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToPartitionContents.java rename to client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToPartitionContents.java index e5424b128..ecfc9c77a 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/SubscribeToPartitionContents.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToPartitionContents.java @@ -1,4 +1,4 @@ -package io.lionweb.client.delta.messages.queries; +package io.lionweb.client.delta.messages.queries.subscriptions; import io.lionweb.client.delta.messages.DeltaQuery; import org.jetbrains.annotations.NotNull; diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/UnsubscribeFromPartitionContents.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/UnsubscribeFromPartitionContents.java similarity index 82% rename from client/src/main/java/io/lionweb/client/delta/messages/queries/UnsubscribeFromPartitionContents.java rename to client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/UnsubscribeFromPartitionContents.java index 5a0bcf9d2..2cba431ae 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/UnsubscribeFromPartitionContents.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/UnsubscribeFromPartitionContents.java @@ -1,4 +1,4 @@ -package io.lionweb.client.delta.messages.queries; +package io.lionweb.client.delta.messages.queries.subscriptions; import io.lionweb.client.delta.messages.DeltaQuery; From 106eff22f2882bb4af765a4aebb2bdb6be0950b3 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Tue, 21 Oct 2025 19:30:25 +0200 Subject: [PATCH 07/30] Introduce DeltaClient with synchronization support and event handling for properties, including tests, new utility methods in `ClassifierInstanceUtils`, and `InMemoryDeltaChannel` implementation. --- .../io/lionweb/client/delta/DeltaChannel.java | 10 +- .../io/lionweb/client/delta/DeltaClient.java | 158 ++++++++++++++++++ .../client/delta/DeltaEventReceiver.java | 4 +- .../client/delta/InMemoryDeltaChannel.java | 39 +++++ .../lionweb/client/delta/DeltaClientTest.java | 32 ++++ 5 files changed, 236 insertions(+), 7 deletions(-) create mode 100644 client/src/main/java/io/lionweb/client/delta/DeltaClient.java create mode 100644 client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java create mode 100644 client/src/test/java/io/lionweb/client/delta/DeltaClientTest.java diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java index dbc19a469..053104a22 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java @@ -1,9 +1,7 @@ package io.lionweb.client.delta; -import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.client.delta.messages.DeltaCommandResponse; -import io.lionweb.client.delta.messages.DeltaQuery; -import io.lionweb.client.delta.messages.DeltaQueryResponse; +import io.lionweb.client.delta.messages.*; +import java.util.function.Function; /** * The DeltaChannel must be a specific link between a Client and the Server. Different clients @@ -25,7 +23,9 @@ public interface DeltaChannel { * the command, or rejects a failed command.[5] However, the repository processes the command * asynchronously, and eventually broadcasts the effect(s) as event. */ - DeltaCommandResponse sendCommand(DeltaCommand command); + DeltaCommandResponse sendCommand(Function commandProducer); + + void sendEvent(Function eventProducer); void registerEventReceiver(DeltaEventReceiver deltaEventReceiver); diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java new file mode 100644 index 000000000..d2a57ba8a --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -0,0 +1,158 @@ +package io.lionweb.client.delta; + +import io.lionweb.LionWebVersion; +import io.lionweb.client.delta.messages.DeltaEvent; +import io.lionweb.client.delta.messages.events.properties.PropertyChanged; +import io.lionweb.language.Containment; +import io.lionweb.language.Property; +import io.lionweb.language.Reference; +import io.lionweb.model.*; +import io.lionweb.serialization.PrimitiveValuesSerialization; +import io.lionweb.serialization.data.MetaPointer; +import java.lang.ref.WeakReference; +import java.util.*; +import org.jetbrains.annotations.NotNull; + +public class DeltaClient implements DeltaEventReceiver { + private LionWebVersion lionWebVersion; + private DeltaChannel channel; + private MonitoringObserver observer = new MonitoringObserver(); + private HashMap>>> nodes = new HashMap<>(); + private PrimitiveValuesSerialization primitiveValuesSerialization = + new PrimitiveValuesSerialization(); + + public DeltaClient(DeltaChannel channel) { + this(LionWebVersion.currentVersion, channel); + this.channel = channel; + this.channel.registerEventReceiver(this); + } + + public DeltaClient(LionWebVersion lionWebVersion, DeltaChannel channel) { + this.lionWebVersion = lionWebVersion; + this.channel = channel; + this.channel.registerEventReceiver(this); + this.primitiveValuesSerialization.registerLionBuiltinsPrimitiveSerializersAndDeserializers( + lionWebVersion); + } + + public void synchronize(@NotNull Node partition) { + Objects.requireNonNull(partition, "partition should not be null"); + synchronized (partition) { + partition + .thisAndAllDescendants() + .forEach( + n -> + nodes + .computeIfAbsent(n.getID(), id -> new HashSet<>()) + .add(new WeakReference<>(n))); + partition.registerPartitionObserver(observer); + } + } + + @Override + public void receiveEvent(DeltaEvent event) { + if (event instanceof PropertyChanged) { + PropertyChanged propertyChanged = (PropertyChanged) event; + for (WeakReference> classifierInstanceRef : + nodes.get(propertyChanged.node)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + ClassifierInstanceUtils.setPropertyValueByMetaPointer( + classifierInstance, propertyChanged.property, propertyChanged.newValue); + } + } + } else { + throw new UnsupportedOperationException( + "Unsupported event type: " + event.getClass().getName()); + } + } + + public void cleanUp() { + // optional: call periodically to remove dead refs globally + Iterator>>>> it = + nodes.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry>>> e = it.next(); + e.getValue().removeIf(ref -> ref.get() == null); + if (e.getValue().isEmpty()) it.remove(); + } + } + + private class MonitoringObserver implements PartitionObserver { + + @Override + public void propertyChanged( + ClassifierInstance classifierInstance, + Property property, + Object oldValue, + Object newValue) { + channel.sendEvent( + sequenceNumber -> + new PropertyChanged( + sequenceNumber, + classifierInstance.getID(), + MetaPointer.from(property), + primitiveValuesSerialization.serialize(property.getType().getID(), newValue), + primitiveValuesSerialization.serialize(property.getType().getID(), oldValue))); + } + + @Override + public void childAdded( + ClassifierInstance classifierInstance, + Containment containment, + int index, + Node newChild) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void childRemoved( + ClassifierInstance classifierInstance, + Containment containment, + int index, + Node removedChild) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void annotationAdded( + ClassifierInstance node, int index, AnnotationInstance newAnnotation) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void annotationRemoved( + ClassifierInstance node, int index, AnnotationInstance removedAnnotation) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void referenceValueAdded( + ClassifierInstance classifierInstance, + Reference reference, + ReferenceValue referenceValue) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void referenceValueChanged( + ClassifierInstance classifierInstance, + Reference reference, + int index, + String oldReferred, + String oldResolveInfo, + String newReferred, + String newResolveInfo) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void referenceValueRemoved( + ClassifierInstance classifierInstance, + Reference reference, + int index, + ReferenceValue referenceValue) { + throw new UnsupportedOperationException("Not supported yet."); + } + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java b/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java index 53c15a545..b55769145 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaEventReceiver.java @@ -1,8 +1,8 @@ package io.lionweb.client.delta; -import io.lionweb.client.delta.messages.CommonDeltaEvent; +import io.lionweb.client.delta.messages.DeltaEvent; public interface DeltaEventReceiver { - void receiveEvent(CommonDeltaEvent event); + void receiveEvent(DeltaEvent event); } diff --git a/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java new file mode 100644 index 000000000..46b4539cd --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java @@ -0,0 +1,39 @@ +package io.lionweb.client.delta; + +import io.lionweb.client.delta.messages.*; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Function; + +public class InMemoryDeltaChannel implements DeltaChannel { + private final Set receivers = new HashSet<>(); + private int nextCmdId = 1; + + @Override + public DeltaQueryResponse sendQuery(DeltaQuery query) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public DeltaCommandResponse sendCommand(Function commandProducer) { + // String commandId = "cmd-" + nextCmdId++; + // DeltaCommand command = commandProducer.apply(commandId); + // receivers.forEach(receiver -> receiver.); + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void registerEventReceiver(DeltaEventReceiver deltaEventReceiver) { + receivers.add(deltaEventReceiver); + } + + @Override + public void unregisterEventReceiver(DeltaEventReceiver deltaEventReceiver) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void sendEvent(Function eventProducer) { + receivers.forEach(receiver -> receiver.receiveEvent(eventProducer.apply(nextCmdId++))); + } +} diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientTest.java new file mode 100644 index 000000000..e968689bb --- /dev/null +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientTest.java @@ -0,0 +1,32 @@ +package io.lionweb.client.delta; + +import static org.junit.Assert.assertEquals; + +import io.lionweb.language.Language; +import org.junit.jupiter.api.Test; + +public class DeltaClientTest { + + @Test + public void simpleSynchronizationOfNodesInstances() { + Language language1 = new Language("Language A", "lang-a", "lang-a-key"); + Language language2 = new Language("Language A", "lang-a", "lang-a-key"); + + DeltaChannel channel = new InMemoryDeltaChannel(); + DeltaClient client = new DeltaClient(channel); + + client.synchronize(language1); + client.synchronize(language2); + + assertEquals("Language A", language1.getName()); + assertEquals("Language A", language2.getName()); + + language1.setName("Language B"); + assertEquals("Language B", language1.getName()); + assertEquals("Language B", language2.getName()); + + language2.setName("Language C"); + assertEquals("Language C", language1.getName()); + assertEquals("Language C", language2.getName()); + } +} From 6eae5913cf64a7ddcfd6f163da15487a766ebb6b Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Fri, 24 Oct 2025 09:37:26 +0200 Subject: [PATCH 08/30] Introduce `DeltaServer` to handle server-side processing of `DeltaEvent` and refactor tests for client-server synchronization. --- .../io/lionweb/client/delta/DeltaClient.java | 11 +---- .../io/lionweb/client/delta/DeltaServer.java | 48 +++++++++++++++++++ ...est.java => DeltaClientAndServerTest.java} | 5 +- 3 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 client/src/main/java/io/lionweb/client/delta/DeltaServer.java rename client/src/test/java/io/lionweb/client/delta/{DeltaClientTest.java => DeltaClientAndServerTest.java} (84%) diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index d2a57ba8a..80c054996 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -67,16 +67,7 @@ public void receiveEvent(DeltaEvent event) { } } - public void cleanUp() { - // optional: call periodically to remove dead refs globally - Iterator>>>> it = - nodes.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry>>> e = it.next(); - e.getValue().removeIf(ref -> ref.get() == null); - if (e.getValue().isEmpty()) it.remove(); - } - } + private class MonitoringObserver implements PartitionObserver { diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaServer.java b/client/src/main/java/io/lionweb/client/delta/DeltaServer.java new file mode 100644 index 000000000..e13fa27ff --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/DeltaServer.java @@ -0,0 +1,48 @@ +package io.lionweb.client.delta; + +import io.lionweb.client.delta.messages.DeltaEvent; +import io.lionweb.client.delta.messages.events.properties.PropertyChanged; +import io.lionweb.model.ClassifierInstance; +import io.lionweb.model.ClassifierInstanceUtils; + +import java.lang.ref.WeakReference; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class DeltaServer implements DeltaEventReceiver { + private DeltaChannel channel; + + public DeltaServer(DeltaChannel channel) { + this.channel = channel; + } + + @Override + public void receiveEvent(DeltaEvent event) { + if (event instanceof PropertyChanged) { + PropertyChanged propertyChanged = (PropertyChanged) event; + for (WeakReference> classifierInstanceRef : + nodes.get(propertyChanged.node)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + ClassifierInstanceUtils.setPropertyValueByMetaPointer( + classifierInstance, propertyChanged.property, propertyChanged.newValue); + } + } + } else { + throw new UnsupportedOperationException( + "Unsupported event type: " + event.getClass().getName()); + } + } + + public void cleanUp() { + // optional: call periodically to remove dead refs globally + Iterator>>>> it = + nodes.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry>>> e = it.next(); + e.getValue().removeIf(ref -> ref.get() == null); + if (e.getValue().isEmpty()) it.remove(); + } + } +} diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java similarity index 84% rename from client/src/test/java/io/lionweb/client/delta/DeltaClientTest.java rename to client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index e968689bb..41e0f242b 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -5,7 +5,7 @@ import io.lionweb.language.Language; import org.junit.jupiter.api.Test; -public class DeltaClientTest { +public class DeltaClientAndServerTest { @Test public void simpleSynchronizationOfNodesInstances() { @@ -14,6 +14,9 @@ public void simpleSynchronizationOfNodesInstances() { DeltaChannel channel = new InMemoryDeltaChannel(); DeltaClient client = new DeltaClient(channel); + DeltaServer server = new DeltaServer(channel); + + // TODO should we first create the nodes on the server and then check them out? client.synchronize(language1); client.synchronize(language2); From 78c983bf78015a7554363481f5e4438593173ac1 Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Fri, 24 Oct 2025 12:05:09 +0200 Subject: [PATCH 09/30] Introduce support for `DeltaCommand` handling in `InMemoryServer` with new `DeltaCommandReceiver` interface, including server-side partition and property synchronization enhancements. --- .../io/lionweb/client/delta/DeltaChannel.java | 4 + .../io/lionweb/client/delta/DeltaClient.java | 73 +++++++------ .../client/delta/DeltaCommandReceiver.java | 10 ++ ...taServer.java => DeltaInMemoryServer.java} | 6 +- .../client/delta/InMemoryDeltaChannel.java | 33 ++++-- .../client/inmemory/InMemoryServer.java | 103 ++++++++++++++++++ .../delta/DeltaClientAndServerTest.java | 32 +++++- 7 files changed, 209 insertions(+), 52 deletions(-) create mode 100644 client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java rename client/src/main/java/io/lionweb/client/delta/{DeltaServer.java => DeltaInMemoryServer.java} (87%) diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java index 053104a22..0e286e24e 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java @@ -30,4 +30,8 @@ public interface DeltaChannel { void registerEventReceiver(DeltaEventReceiver deltaEventReceiver); void unregisterEventReceiver(DeltaEventReceiver deltaEventReceiver); + + void registerCommandReceiver(DeltaCommandReceiver deltaCommandReceiver); + + void unregisterCommandReceiver(DeltaCommandReceiver deltaCommandReceiver); } diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index 80c054996..6adb774d4 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -2,6 +2,7 @@ import io.lionweb.LionWebVersion; import io.lionweb.client.delta.messages.DeltaEvent; +import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; import io.lionweb.language.Containment; import io.lionweb.language.Property; @@ -30,46 +31,49 @@ public DeltaClient(DeltaChannel channel) { public DeltaClient(LionWebVersion lionWebVersion, DeltaChannel channel) { this.lionWebVersion = lionWebVersion; this.channel = channel; - this.channel.registerEventReceiver(this); + this.channel.registerEventReceiver(this); this.primitiveValuesSerialization.registerLionBuiltinsPrimitiveSerializersAndDeserializers( lionWebVersion); } - public void synchronize(@NotNull Node partition) { + /** + * It is responsibility of the caller to ensure that the partition is initially + * in sync with the server. + */ + public void monitor(@NotNull Node partition) { Objects.requireNonNull(partition, "partition should not be null"); - synchronized (partition) { - partition - .thisAndAllDescendants() - .forEach( - n -> - nodes - .computeIfAbsent(n.getID(), id -> new HashSet<>()) - .add(new WeakReference<>(n))); - partition.registerPartitionObserver(observer); - } + synchronized (partition) { + partition + .thisAndAllDescendants() + .forEach( + n -> + nodes + .computeIfAbsent(n.getID(), id -> new HashSet<>()) + .add(new WeakReference<>(n))); + partition.registerPartitionObserver(observer); + } } - @Override - public void receiveEvent(DeltaEvent event) { - if (event instanceof PropertyChanged) { - PropertyChanged propertyChanged = (PropertyChanged) event; - for (WeakReference> classifierInstanceRef : - nodes.get(propertyChanged.node)) { - ClassifierInstance classifierInstance = classifierInstanceRef.get(); - if (classifierInstance != null) { - ClassifierInstanceUtils.setPropertyValueByMetaPointer( - classifierInstance, propertyChanged.property, propertyChanged.newValue); + @Override + public void receiveEvent(DeltaEvent event) { + if (event instanceof PropertyChanged) { + PropertyChanged propertyChanged = (PropertyChanged) event; + for (WeakReference> classifierInstanceRef : + nodes.get(propertyChanged.node)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + ClassifierInstanceUtils.setPropertyValueByMetaPointer( + classifierInstance, propertyChanged.property, propertyChanged.newValue); + } + } + } else { + throw new UnsupportedOperationException( + "Unsupported event type: " + event.getClass().getName()); } - } - } else { - throw new UnsupportedOperationException( - "Unsupported event type: " + event.getClass().getName()); } - } - - private class MonitoringObserver implements PartitionObserver { + private class MonitoringObserver implements PartitionObserver { @Override public void propertyChanged( @@ -77,14 +81,13 @@ public void propertyChanged( Property property, Object oldValue, Object newValue) { - channel.sendEvent( - sequenceNumber -> - new PropertyChanged( - sequenceNumber, + channel.sendCommand( + commandId -> + new ChangeProperty( + commandId, classifierInstance.getID(), MetaPointer.from(property), - primitiveValuesSerialization.serialize(property.getType().getID(), newValue), - primitiveValuesSerialization.serialize(property.getType().getID(), oldValue))); + primitiveValuesSerialization.serialize(property.getType().getID(), newValue))); } @Override diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java b/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java new file mode 100644 index 000000000..6ab2f2b10 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java @@ -0,0 +1,10 @@ +package io.lionweb.client.delta; + +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.client.delta.messages.DeltaCommandResponse; +import io.lionweb.client.delta.messages.DeltaEvent; + +public interface DeltaCommandReceiver { + + DeltaCommandResponse receiveCommand(DeltaCommand command); +} diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaServer.java b/client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java similarity index 87% rename from client/src/main/java/io/lionweb/client/delta/DeltaServer.java rename to client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java index e13fa27ff..8abbe59cb 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaServer.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java @@ -6,14 +6,16 @@ import io.lionweb.model.ClassifierInstanceUtils; import java.lang.ref.WeakReference; +import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; -public class DeltaServer implements DeltaEventReceiver { +public class DeltaInMemoryServer implements DeltaEventReceiver { private DeltaChannel channel; + private HashMap>>> nodes = new HashMap<>(); - public DeltaServer(DeltaChannel channel) { + public DeltaInMemoryServer(DeltaChannel channel) { this.channel = channel; } diff --git a/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java index 46b4539cd..c642d3721 100644 --- a/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java +++ b/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java @@ -1,13 +1,17 @@ package io.lionweb.client.delta; import io.lionweb.client.delta.messages.*; +import org.jetbrains.annotations.Nullable; + import java.util.HashSet; import java.util.Set; import java.util.function.Function; public class InMemoryDeltaChannel implements DeltaChannel { - private final Set receivers = new HashSet<>(); - private int nextCmdId = 1; + private final Set eventReceivers = new HashSet<>(); + private @Nullable DeltaCommandReceiver commandReceiver; + private int nextEventId = 1; + private int nextCommandId = 1; @Override public DeltaQueryResponse sendQuery(DeltaQuery query) { @@ -16,15 +20,16 @@ public DeltaQueryResponse sendQuery(DeltaQuery query) { @Override public DeltaCommandResponse sendCommand(Function commandProducer) { - // String commandId = "cmd-" + nextCmdId++; - // DeltaCommand command = commandProducer.apply(commandId); - // receivers.forEach(receiver -> receiver.); - throw new UnsupportedOperationException("Not supported yet."); + if (commandReceiver != null) { + return commandReceiver.receiveCommand(commandProducer.apply("cmd-"+nextCommandId++)); + } else { + return null; + } } @Override public void registerEventReceiver(DeltaEventReceiver deltaEventReceiver) { - receivers.add(deltaEventReceiver); + eventReceivers.add(deltaEventReceiver); } @Override @@ -32,8 +37,18 @@ public void unregisterEventReceiver(DeltaEventReceiver deltaEventReceiver) { throw new UnsupportedOperationException("Not supported yet."); } - @Override + @Override + public void registerCommandReceiver(DeltaCommandReceiver commandReceiver) { + this.commandReceiver = commandReceiver; + } + + @Override + public void unregisterCommandReceiver(DeltaCommandReceiver deltaCommandReceiver) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override public void sendEvent(Function eventProducer) { - receivers.forEach(receiver -> receiver.receiveEvent(eventProducer.apply(nextCmdId++))); + eventReceivers.forEach(receiver -> receiver.receiveEvent(eventProducer.apply(nextEventId++))); } } diff --git a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java index b640f5aa8..8a38d607d 100644 --- a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java @@ -1,9 +1,27 @@ package io.lionweb.client.inmemory; +import io.lionweb.LionWebVersion; import io.lionweb.client.api.*; +import io.lionweb.client.delta.DeltaChannel; +import io.lionweb.client.delta.DeltaCommandReceiver; +import io.lionweb.client.delta.DeltaEventReceiver; +import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.client.delta.messages.DeltaCommandResponse; +import io.lionweb.client.delta.messages.DeltaEvent; +import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; +import io.lionweb.client.delta.messages.events.properties.PropertyChanged; +import io.lionweb.model.ClassifierInstance; +import io.lionweb.model.Node; +import io.lionweb.serialization.AbstractSerialization; +import io.lionweb.serialization.JsonSerialization; +import io.lionweb.serialization.LowLevelJsonSerialization; +import io.lionweb.serialization.SerializationProvider; import io.lionweb.serialization.data.MetaPointer; +import io.lionweb.serialization.data.SerializationChunk; import io.lionweb.serialization.data.SerializedClassifierInstance; import io.lionweb.utils.ValidationResult; + +import java.lang.ref.WeakReference; import java.util.*; import java.util.stream.Collectors; import org.jetbrains.annotations.NotNull; @@ -81,6 +99,18 @@ public void deleteRepository(@NotNull String repositoryName) { return repositoryData.bumpVersion(); } + public @NotNull RepositoryVersionToken createPartition( @NotNull String repositoryName, @NotNull Node partition, @NotNull AbstractSerialization serialization ) { + Objects.requireNonNull(repositoryName, "RepositoryName should not be null"); + Objects.requireNonNull(partition, "Partition should not be null"); + Objects.requireNonNull(serialization, "Serialization should not be null"); + if (partition.getParent() != null) { + throw new IllegalArgumentException("Partition should not have a parent"); + } + + SerializationChunk serializationChunk = serialization.serializeNodesToSerializationChunk(partition); + return createPartitionFromChunk(repositoryName, serializationChunk.getClassifierInstances()); + } + public @NotNull RepositoryVersionToken deletePartitions( @NotNull String repositoryName, @NotNull List partitionIds) { Objects.requireNonNull(partitionIds); @@ -99,6 +129,19 @@ public List retrieve( return retrieved; } + public @Nullable ClassifierInstance retrieveAsClassifierInstance(@NotNull String repositoryName, @NotNull String nodeId, @NotNull AbstractSerialization serialization) { + Objects.requireNonNull(repositoryName, "RepositoryName should not be null"); + Objects.requireNonNull(nodeId, "NodeId should not be null"); + Objects.requireNonNull(serialization, "Serialization should not be null"); + List serializedNodes = retrieve(repositoryName, Arrays.asList(nodeId), 1); + if (serializedNodes.isEmpty()) { + return null; + } + LionWebVersion lionWebVersion = repositories.get(repositoryName).configuration.getLionWebVersion(); + List> nodes = serialization.deserializeSerializationChunk(SerializationChunk.fromNodes(lionWebVersion, serializedNodes)); + return nodes.stream().filter(n -> Objects.equals(n.getID(), nodeId)).findFirst().orElse(null); + } + public RepositoryVersionToken store( @NotNull String repositoryName, @NotNull List nodes) { Objects.requireNonNull(repositoryName, "RepositoryName should not be null"); @@ -183,6 +226,65 @@ public Map nodesByLanguage( } // + // Delta methods + // + + public void monitorDeltaChannel(String repositoryName, @NotNull DeltaChannel channel) { + Objects.requireNonNull(channel, "Channel should not be null"); + channel.registerCommandReceiver(new DeltaCommandReceiverImpl(repositoryName, channel)); + } + + private class DeltaCommandReceiverImpl implements DeltaCommandReceiver { + private String repositoryName; + private DeltaChannel channel; + private DeltaCommandReceiverImpl(String repositoryName, DeltaChannel channel) { + this.repositoryName = repositoryName; + this.channel = channel; + } + + @Override + public DeltaCommandResponse receiveCommand(DeltaCommand command) { + if (command instanceof ChangeProperty) { + ChangeProperty changeProperty = (ChangeProperty) command; + RepositoryData repositoryData = getRepository(repositoryName); + List retrieved = new ArrayList<>(); + repositoryData.retrieve(changeProperty.node, 0, retrieved); + if (retrieved.isEmpty()) { + throw new UnsupportedOperationException("Node with id " + changeProperty.node + " cannot be found. We should return an error"); + } + SerializedClassifierInstance node = retrieved.get(0); + String oldValue = node.getPropertyValue(((ChangeProperty) command).property); + retrieved.get(0); + node.setPropertyValue(((ChangeProperty) command).property, changeProperty.newValue); + String newValue = node.getPropertyValue(((ChangeProperty) command).property); + channel.sendEvent(sequenceNumber -> new PropertyChanged(sequenceNumber, node.getID(), changeProperty.property, newValue, oldValue)); + return new DeltaCommandResponse(); + } + + throw new UnsupportedOperationException("Unsupported command type: " + command.getClass().getName()); + + // The server only cares about commands +// if (event instanceof PropertyChanged) { +// PropertyChanged propertyChanged = (PropertyChanged) event; +// event. +// for (WeakReference> classifierInstanceRef : +// nodes.get(propertyChanged.node)) { +// ClassifierInstance classifierInstance = classifierInstanceRef.get(); +// if (classifierInstance != null) { +// ClassifierInstanceUtils.setPropertyValueByMetaPointer( +// classifierInstance, propertyChanged.property, propertyChanged.newValue); +// } +// } +// } else { +// throw new UnsupportedOperationException( +// "Unsupported event type: " + event.getClass().getName()); +// } + } + } + + + + // // Private methods // @@ -194,4 +296,5 @@ public Map nodesByLanguage( } return repositoryData; } + } diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index 41e0f242b..6ed84a78d 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -1,25 +1,41 @@ package io.lionweb.client.delta; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import io.lionweb.LionWebVersion; +import io.lionweb.client.api.HistorySupport; +import io.lionweb.client.api.RepositoryConfiguration; +import io.lionweb.client.inmemory.InMemoryServer; import io.lionweb.language.Language; +import io.lionweb.serialization.JsonSerialization; +import io.lionweb.serialization.SerializationProvider; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class DeltaClientAndServerTest { @Test public void simpleSynchronizationOfNodesInstances() { - Language language1 = new Language("Language A", "lang-a", "lang-a-key"); - Language language2 = new Language("Language A", "lang-a", "lang-a-key"); + InMemoryServer server = new InMemoryServer(); + server.createRepository(new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); + + JsonSerialization serialization = SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); + Language language1 = new Language("Language A", "lang-a", "lang-a-key"); + server.createPartition("MyRepo", language1, serialization); + + Language language2 = (Language) server.retrieveAsClassifierInstance("MyRepo", "lang-a", serialization); + Assertions.assertNotNull(language2); + + assertEquals(language1, language2); DeltaChannel channel = new InMemoryDeltaChannel(); DeltaClient client = new DeltaClient(channel); - DeltaServer server = new DeltaServer(channel); - // TODO should we first create the nodes on the server and then check them out? + server.monitorDeltaChannel("MyRepo", channel); - client.synchronize(language1); - client.synchronize(language2); + client.monitor(language1); + client.monitor(language2); assertEquals("Language A", language1.getName()); assertEquals("Language A", language2.getName()); @@ -31,5 +47,9 @@ public void simpleSynchronizationOfNodesInstances() { language2.setName("Language C"); assertEquals("Language C", language1.getName()); assertEquals("Language C", language2.getName()); + + language1.setName("Language A"); + assertEquals("Language A", language1.getName()); + assertEquals("Language A", language2.getName()); } } From 318465734cbc65d4e1b3531cf802aa70710e3f56 Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Fri, 24 Oct 2025 12:07:13 +0200 Subject: [PATCH 10/30] Refactor `InMemoryServer` and `DeltaChannel` to enhance readability and consistency; optimize formatting and remove unused imports. --- .../io/lionweb/client/delta/DeltaChannel.java | 4 +- .../io/lionweb/client/delta/DeltaClient.java | 65 ++++--- .../client/delta/DeltaCommandReceiver.java | 1 - .../client/delta/DeltaInMemoryServer.java | 59 +++--- .../client/delta/InMemoryDeltaChannel.java | 33 ++-- .../client/inmemory/InMemoryServer.java | 170 +++++++++--------- .../delta/DeltaClientAndServerTest.java | 22 +-- 7 files changed, 181 insertions(+), 173 deletions(-) diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java index 0e286e24e..3c153c320 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java @@ -31,7 +31,7 @@ public interface DeltaChannel { void unregisterEventReceiver(DeltaEventReceiver deltaEventReceiver); - void registerCommandReceiver(DeltaCommandReceiver deltaCommandReceiver); + void registerCommandReceiver(DeltaCommandReceiver deltaCommandReceiver); - void unregisterCommandReceiver(DeltaCommandReceiver deltaCommandReceiver); + void unregisterCommandReceiver(DeltaCommandReceiver deltaCommandReceiver); } diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index 6adb774d4..c74d17159 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -31,49 +31,48 @@ public DeltaClient(DeltaChannel channel) { public DeltaClient(LionWebVersion lionWebVersion, DeltaChannel channel) { this.lionWebVersion = lionWebVersion; this.channel = channel; - this.channel.registerEventReceiver(this); + this.channel.registerEventReceiver(this); this.primitiveValuesSerialization.registerLionBuiltinsPrimitiveSerializersAndDeserializers( lionWebVersion); } - /** - * It is responsibility of the caller to ensure that the partition is initially - * in sync with the server. - */ + /** + * It is responsibility of the caller to ensure that the partition is initially in sync with the + * server. + */ public void monitor(@NotNull Node partition) { Objects.requireNonNull(partition, "partition should not be null"); - synchronized (partition) { - partition - .thisAndAllDescendants() - .forEach( - n -> - nodes - .computeIfAbsent(n.getID(), id -> new HashSet<>()) - .add(new WeakReference<>(n))); - partition.registerPartitionObserver(observer); - } + synchronized (partition) { + partition + .thisAndAllDescendants() + .forEach( + n -> + nodes + .computeIfAbsent(n.getID(), id -> new HashSet<>()) + .add(new WeakReference<>(n))); + partition.registerPartitionObserver(observer); + } } - @Override - public void receiveEvent(DeltaEvent event) { - if (event instanceof PropertyChanged) { - PropertyChanged propertyChanged = (PropertyChanged) event; - for (WeakReference> classifierInstanceRef : - nodes.get(propertyChanged.node)) { - ClassifierInstance classifierInstance = classifierInstanceRef.get(); - if (classifierInstance != null) { - ClassifierInstanceUtils.setPropertyValueByMetaPointer( - classifierInstance, propertyChanged.property, propertyChanged.newValue); - } - } - } else { - throw new UnsupportedOperationException( - "Unsupported event type: " + event.getClass().getName()); + @Override + public void receiveEvent(DeltaEvent event) { + if (event instanceof PropertyChanged) { + PropertyChanged propertyChanged = (PropertyChanged) event; + for (WeakReference> classifierInstanceRef : + nodes.get(propertyChanged.node)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + ClassifierInstanceUtils.setPropertyValueByMetaPointer( + classifierInstance, propertyChanged.property, propertyChanged.newValue); } + } + } else { + throw new UnsupportedOperationException( + "Unsupported event type: " + event.getClass().getName()); } + } - - private class MonitoringObserver implements PartitionObserver { + private class MonitoringObserver implements PartitionObserver { @Override public void propertyChanged( @@ -84,7 +83,7 @@ public void propertyChanged( channel.sendCommand( commandId -> new ChangeProperty( - commandId, + commandId, classifierInstance.getID(), MetaPointer.from(property), primitiveValuesSerialization.serialize(property.getType().getID(), newValue))); diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java b/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java index 6ab2f2b10..bdeda798c 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java @@ -2,7 +2,6 @@ import io.lionweb.client.delta.messages.DeltaCommand; import io.lionweb.client.delta.messages.DeltaCommandResponse; -import io.lionweb.client.delta.messages.DeltaEvent; public interface DeltaCommandReceiver { diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java b/client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java index 8abbe59cb..a5078bb4b 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java @@ -4,7 +4,6 @@ import io.lionweb.client.delta.messages.events.properties.PropertyChanged; import io.lionweb.model.ClassifierInstance; import io.lionweb.model.ClassifierInstanceUtils; - import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Iterator; @@ -12,39 +11,39 @@ import java.util.Set; public class DeltaInMemoryServer implements DeltaEventReceiver { - private DeltaChannel channel; - private HashMap>>> nodes = new HashMap<>(); + private DeltaChannel channel; + private HashMap>>> nodes = new HashMap<>(); - public DeltaInMemoryServer(DeltaChannel channel) { - this.channel = channel; - } + public DeltaInMemoryServer(DeltaChannel channel) { + this.channel = channel; + } - @Override - public void receiveEvent(DeltaEvent event) { - if (event instanceof PropertyChanged) { - PropertyChanged propertyChanged = (PropertyChanged) event; - for (WeakReference> classifierInstanceRef : - nodes.get(propertyChanged.node)) { - ClassifierInstance classifierInstance = classifierInstanceRef.get(); - if (classifierInstance != null) { - ClassifierInstanceUtils.setPropertyValueByMetaPointer( - classifierInstance, propertyChanged.property, propertyChanged.newValue); - } - } - } else { - throw new UnsupportedOperationException( - "Unsupported event type: " + event.getClass().getName()); + @Override + public void receiveEvent(DeltaEvent event) { + if (event instanceof PropertyChanged) { + PropertyChanged propertyChanged = (PropertyChanged) event; + for (WeakReference> classifierInstanceRef : + nodes.get(propertyChanged.node)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + ClassifierInstanceUtils.setPropertyValueByMetaPointer( + classifierInstance, propertyChanged.property, propertyChanged.newValue); } + } + } else { + throw new UnsupportedOperationException( + "Unsupported event type: " + event.getClass().getName()); } + } - public void cleanUp() { - // optional: call periodically to remove dead refs globally - Iterator>>>> it = - nodes.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry>>> e = it.next(); - e.getValue().removeIf(ref -> ref.get() == null); - if (e.getValue().isEmpty()) it.remove(); - } + public void cleanUp() { + // optional: call periodically to remove dead refs globally + Iterator>>>> it = + nodes.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry>>> e = it.next(); + e.getValue().removeIf(ref -> ref.get() == null); + if (e.getValue().isEmpty()) it.remove(); } + } } diff --git a/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java index c642d3721..af3c80c57 100644 --- a/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java +++ b/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java @@ -1,17 +1,16 @@ package io.lionweb.client.delta; import io.lionweb.client.delta.messages.*; -import org.jetbrains.annotations.Nullable; - import java.util.HashSet; import java.util.Set; import java.util.function.Function; +import org.jetbrains.annotations.Nullable; public class InMemoryDeltaChannel implements DeltaChannel { private final Set eventReceivers = new HashSet<>(); private @Nullable DeltaCommandReceiver commandReceiver; private int nextEventId = 1; - private int nextCommandId = 1; + private int nextCommandId = 1; @Override public DeltaQueryResponse sendQuery(DeltaQuery query) { @@ -20,11 +19,11 @@ public DeltaQueryResponse sendQuery(DeltaQuery query) { @Override public DeltaCommandResponse sendCommand(Function commandProducer) { - if (commandReceiver != null) { - return commandReceiver.receiveCommand(commandProducer.apply("cmd-"+nextCommandId++)); - } else { - return null; - } + if (commandReceiver != null) { + return commandReceiver.receiveCommand(commandProducer.apply("cmd-" + nextCommandId++)); + } else { + return null; + } } @Override @@ -37,17 +36,17 @@ public void unregisterEventReceiver(DeltaEventReceiver deltaEventReceiver) { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public void registerCommandReceiver(DeltaCommandReceiver commandReceiver) { - this.commandReceiver = commandReceiver; - } + @Override + public void registerCommandReceiver(DeltaCommandReceiver commandReceiver) { + this.commandReceiver = commandReceiver; + } - @Override - public void unregisterCommandReceiver(DeltaCommandReceiver deltaCommandReceiver) { - throw new UnsupportedOperationException("Not supported yet."); - } + @Override + public void unregisterCommandReceiver(DeltaCommandReceiver deltaCommandReceiver) { + throw new UnsupportedOperationException("Not supported yet."); + } - @Override + @Override public void sendEvent(Function eventProducer) { eventReceivers.forEach(receiver -> receiver.receiveEvent(eventProducer.apply(nextEventId++))); } diff --git a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java index 8a38d607d..4c8978740 100644 --- a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java @@ -4,24 +4,17 @@ import io.lionweb.client.api.*; import io.lionweb.client.delta.DeltaChannel; import io.lionweb.client.delta.DeltaCommandReceiver; -import io.lionweb.client.delta.DeltaEventReceiver; import io.lionweb.client.delta.messages.DeltaCommand; import io.lionweb.client.delta.messages.DeltaCommandResponse; -import io.lionweb.client.delta.messages.DeltaEvent; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; import io.lionweb.model.ClassifierInstance; import io.lionweb.model.Node; import io.lionweb.serialization.AbstractSerialization; -import io.lionweb.serialization.JsonSerialization; -import io.lionweb.serialization.LowLevelJsonSerialization; -import io.lionweb.serialization.SerializationProvider; import io.lionweb.serialization.data.MetaPointer; import io.lionweb.serialization.data.SerializationChunk; import io.lionweb.serialization.data.SerializedClassifierInstance; import io.lionweb.utils.ValidationResult; - -import java.lang.ref.WeakReference; import java.util.*; import java.util.stream.Collectors; import org.jetbrains.annotations.NotNull; @@ -99,16 +92,20 @@ public void deleteRepository(@NotNull String repositoryName) { return repositoryData.bumpVersion(); } - public @NotNull RepositoryVersionToken createPartition( @NotNull String repositoryName, @NotNull Node partition, @NotNull AbstractSerialization serialization ) { - Objects.requireNonNull(repositoryName, "RepositoryName should not be null"); - Objects.requireNonNull(partition, "Partition should not be null"); - Objects.requireNonNull(serialization, "Serialization should not be null"); - if (partition.getParent() != null) { - throw new IllegalArgumentException("Partition should not have a parent"); - } + public @NotNull RepositoryVersionToken createPartition( + @NotNull String repositoryName, + @NotNull Node partition, + @NotNull AbstractSerialization serialization) { + Objects.requireNonNull(repositoryName, "RepositoryName should not be null"); + Objects.requireNonNull(partition, "Partition should not be null"); + Objects.requireNonNull(serialization, "Serialization should not be null"); + if (partition.getParent() != null) { + throw new IllegalArgumentException("Partition should not have a parent"); + } - SerializationChunk serializationChunk = serialization.serializeNodesToSerializationChunk(partition); - return createPartitionFromChunk(repositoryName, serializationChunk.getClassifierInstances()); + SerializationChunk serializationChunk = + serialization.serializeNodesToSerializationChunk(partition); + return createPartitionFromChunk(repositoryName, serializationChunk.getClassifierInstances()); } public @NotNull RepositoryVersionToken deletePartitions( @@ -129,17 +126,24 @@ public List retrieve( return retrieved; } - public @Nullable ClassifierInstance retrieveAsClassifierInstance(@NotNull String repositoryName, @NotNull String nodeId, @NotNull AbstractSerialization serialization) { - Objects.requireNonNull(repositoryName, "RepositoryName should not be null"); - Objects.requireNonNull(nodeId, "NodeId should not be null"); - Objects.requireNonNull(serialization, "Serialization should not be null"); - List serializedNodes = retrieve(repositoryName, Arrays.asList(nodeId), 1); - if (serializedNodes.isEmpty()) { - return null; - } - LionWebVersion lionWebVersion = repositories.get(repositoryName).configuration.getLionWebVersion(); - List> nodes = serialization.deserializeSerializationChunk(SerializationChunk.fromNodes(lionWebVersion, serializedNodes)); - return nodes.stream().filter(n -> Objects.equals(n.getID(), nodeId)).findFirst().orElse(null); + public @Nullable ClassifierInstance retrieveAsClassifierInstance( + @NotNull String repositoryName, + @NotNull String nodeId, + @NotNull AbstractSerialization serialization) { + Objects.requireNonNull(repositoryName, "RepositoryName should not be null"); + Objects.requireNonNull(nodeId, "NodeId should not be null"); + Objects.requireNonNull(serialization, "Serialization should not be null"); + List serializedNodes = + retrieve(repositoryName, Arrays.asList(nodeId), 1); + if (serializedNodes.isEmpty()) { + return null; + } + LionWebVersion lionWebVersion = + repositories.get(repositoryName).configuration.getLionWebVersion(); + List> nodes = + serialization.deserializeSerializationChunk( + SerializationChunk.fromNodes(lionWebVersion, serializedNodes)); + return nodes.stream().filter(n -> Objects.equals(n.getID(), nodeId)).findFirst().orElse(null); } public RepositoryVersionToken store( @@ -226,65 +230,72 @@ public Map nodesByLanguage( } // - // Delta methods - // - - public void monitorDeltaChannel(String repositoryName, @NotNull DeltaChannel channel) { - Objects.requireNonNull(channel, "Channel should not be null"); - channel.registerCommandReceiver(new DeltaCommandReceiverImpl(repositoryName, channel)); - } - - private class DeltaCommandReceiverImpl implements DeltaCommandReceiver { - private String repositoryName; - private DeltaChannel channel; - private DeltaCommandReceiverImpl(String repositoryName, DeltaChannel channel) { - this.repositoryName = repositoryName; - this.channel = channel; - } + // Delta methods + // - @Override - public DeltaCommandResponse receiveCommand(DeltaCommand command) { - if (command instanceof ChangeProperty) { - ChangeProperty changeProperty = (ChangeProperty) command; - RepositoryData repositoryData = getRepository(repositoryName); - List retrieved = new ArrayList<>(); - repositoryData.retrieve(changeProperty.node, 0, retrieved); - if (retrieved.isEmpty()) { - throw new UnsupportedOperationException("Node with id " + changeProperty.node + " cannot be found. We should return an error"); - } - SerializedClassifierInstance node = retrieved.get(0); - String oldValue = node.getPropertyValue(((ChangeProperty) command).property); - retrieved.get(0); - node.setPropertyValue(((ChangeProperty) command).property, changeProperty.newValue); - String newValue = node.getPropertyValue(((ChangeProperty) command).property); - channel.sendEvent(sequenceNumber -> new PropertyChanged(sequenceNumber, node.getID(), changeProperty.property, newValue, oldValue)); - return new DeltaCommandResponse(); - } + public void monitorDeltaChannel(String repositoryName, @NotNull DeltaChannel channel) { + Objects.requireNonNull(channel, "Channel should not be null"); + channel.registerCommandReceiver(new DeltaCommandReceiverImpl(repositoryName, channel)); + } - throw new UnsupportedOperationException("Unsupported command type: " + command.getClass().getName()); + private class DeltaCommandReceiverImpl implements DeltaCommandReceiver { + private String repositoryName; + private DeltaChannel channel; - // The server only cares about commands -// if (event instanceof PropertyChanged) { -// PropertyChanged propertyChanged = (PropertyChanged) event; -// event. -// for (WeakReference> classifierInstanceRef : -// nodes.get(propertyChanged.node)) { -// ClassifierInstance classifierInstance = classifierInstanceRef.get(); -// if (classifierInstance != null) { -// ClassifierInstanceUtils.setPropertyValueByMetaPointer( -// classifierInstance, propertyChanged.property, propertyChanged.newValue); -// } -// } -// } else { -// throw new UnsupportedOperationException( -// "Unsupported event type: " + event.getClass().getName()); -// } - } + private DeltaCommandReceiverImpl(String repositoryName, DeltaChannel channel) { + this.repositoryName = repositoryName; + this.channel = channel; } + @Override + public DeltaCommandResponse receiveCommand(DeltaCommand command) { + if (command instanceof ChangeProperty) { + ChangeProperty changeProperty = (ChangeProperty) command; + RepositoryData repositoryData = getRepository(repositoryName); + List retrieved = new ArrayList<>(); + repositoryData.retrieve(changeProperty.node, 0, retrieved); + if (retrieved.isEmpty()) { + throw new UnsupportedOperationException( + "Node with id " + + changeProperty.node + + " cannot be found. We should return an error"); + } + SerializedClassifierInstance node = retrieved.get(0); + String oldValue = node.getPropertyValue(((ChangeProperty) command).property); + retrieved.get(0); + node.setPropertyValue(((ChangeProperty) command).property, changeProperty.newValue); + String newValue = node.getPropertyValue(((ChangeProperty) command).property); + channel.sendEvent( + sequenceNumber -> + new PropertyChanged( + sequenceNumber, node.getID(), changeProperty.property, newValue, oldValue)); + return new DeltaCommandResponse(); + } + throw new UnsupportedOperationException( + "Unsupported command type: " + command.getClass().getName()); + + // The server only cares about commands + // if (event instanceof PropertyChanged) { + // PropertyChanged propertyChanged = (PropertyChanged) event; + // event. + // for (WeakReference> classifierInstanceRef : + // nodes.get(propertyChanged.node)) { + // ClassifierInstance classifierInstance = classifierInstanceRef.get(); + // if (classifierInstance != null) { + // ClassifierInstanceUtils.setPropertyValueByMetaPointer( + // classifierInstance, propertyChanged.property, + // propertyChanged.newValue); + // } + // } + // } else { + // throw new UnsupportedOperationException( + // "Unsupported event type: " + event.getClass().getName()); + // } + } + } - // + // // Private methods // @@ -296,5 +307,4 @@ public DeltaCommandResponse receiveCommand(DeltaCommand command) { } return repositoryData; } - } diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index 6ed84a78d..85d157cc2 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -1,7 +1,6 @@ package io.lionweb.client.delta; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import io.lionweb.LionWebVersion; import io.lionweb.client.api.HistorySupport; @@ -17,14 +16,17 @@ public class DeltaClientAndServerTest { @Test public void simpleSynchronizationOfNodesInstances() { - InMemoryServer server = new InMemoryServer(); - server.createRepository(new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); + InMemoryServer server = new InMemoryServer(); + server.createRepository( + new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); - JsonSerialization serialization = SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); - Language language1 = new Language("Language A", "lang-a", "lang-a-key"); - server.createPartition("MyRepo", language1, serialization); + JsonSerialization serialization = + SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); + Language language1 = new Language("Language A", "lang-a", "lang-a-key"); + server.createPartition("MyRepo", language1, serialization); - Language language2 = (Language) server.retrieveAsClassifierInstance("MyRepo", "lang-a", serialization); + Language language2 = + (Language) server.retrieveAsClassifierInstance("MyRepo", "lang-a", serialization); Assertions.assertNotNull(language2); assertEquals(language1, language2); @@ -48,8 +50,8 @@ public void simpleSynchronizationOfNodesInstances() { assertEquals("Language C", language1.getName()); assertEquals("Language C", language2.getName()); - language1.setName("Language A"); - assertEquals("Language A", language1.getName()); - assertEquals("Language A", language2.getName()); + language1.setName("Language A"); + assertEquals("Language A", language1.getName()); + assertEquals("Language A", language2.getName()); } } From dc6eceb692d47442420a81d84fdef2f6d20ed942 Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Fri, 24 Oct 2025 12:16:46 +0200 Subject: [PATCH 11/30] Introduce error handling for invalid node operations and enhance `DeltaCommandResponse` with acceptance and rejection support. --- .../client/delta/CommandRejectException.java | 7 +++++ .../io/lionweb/client/delta/DeltaClient.java | 20 +++++++++----- .../delta/messages/DeltaCommandResponse.java | 20 +++++++++++++- .../client/inmemory/InMemoryServer.java | 13 +++++---- .../delta/DeltaClientAndServerTest.java | 27 +++++++++++++++++++ 5 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 client/src/main/java/io/lionweb/client/delta/CommandRejectException.java diff --git a/client/src/main/java/io/lionweb/client/delta/CommandRejectException.java b/client/src/main/java/io/lionweb/client/delta/CommandRejectException.java new file mode 100644 index 000000000..5a1e1dcfa --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/CommandRejectException.java @@ -0,0 +1,7 @@ +package io.lionweb.client.delta; + +public class CommandRejectException extends RuntimeException { + public CommandRejectException(String message) { + super(message); + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index c74d17159..140d4362d 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -1,6 +1,7 @@ package io.lionweb.client.delta; import io.lionweb.LionWebVersion; +import io.lionweb.client.delta.messages.DeltaCommandResponse; import io.lionweb.client.delta.messages.DeltaEvent; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; @@ -80,13 +81,18 @@ public void propertyChanged( Property property, Object oldValue, Object newValue) { - channel.sendCommand( - commandId -> - new ChangeProperty( - commandId, - classifierInstance.getID(), - MetaPointer.from(property), - primitiveValuesSerialization.serialize(property.getType().getID(), newValue))); + DeltaCommandResponse response = + channel.sendCommand( + commandId -> + new ChangeProperty( + commandId, + classifierInstance.getID(), + MetaPointer.from(property), + primitiveValuesSerialization.serialize( + property.getType().getID(), newValue))); + if (!response.accepted) { + throw new CommandRejectException(response.errorMessage); + } } @Override diff --git a/client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java b/client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java index 6263ad522..610747e68 100644 --- a/client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java +++ b/client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java @@ -1,3 +1,21 @@ package io.lionweb.client.delta.messages; -public class DeltaCommandResponse {} +import org.jetbrains.annotations.Nullable; + +public class DeltaCommandResponse { + public final boolean accepted; + public final @Nullable String errorMessage; + + private DeltaCommandResponse(boolean accepted, @Nullable String errorMessage) { + this.accepted = accepted; + this.errorMessage = errorMessage; + } + + public static DeltaCommandResponse accepted() { + return new DeltaCommandResponse(true, null); + } + + public static DeltaCommandResponse rejected(String errorMessage) { + return new DeltaCommandResponse(false, errorMessage); + } +} diff --git a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java index 4c8978740..0317c7719 100644 --- a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java @@ -253,12 +253,11 @@ public DeltaCommandResponse receiveCommand(DeltaCommand command) { ChangeProperty changeProperty = (ChangeProperty) command; RepositoryData repositoryData = getRepository(repositoryName); List retrieved = new ArrayList<>(); - repositoryData.retrieve(changeProperty.node, 0, retrieved); - if (retrieved.isEmpty()) { - throw new UnsupportedOperationException( - "Node with id " - + changeProperty.node - + " cannot be found. We should return an error"); + try { + repositoryData.retrieve(changeProperty.node, 0, retrieved); + } catch (IllegalArgumentException e) { + return DeltaCommandResponse.rejected( + "Node with id " + changeProperty.node + " not found"); } SerializedClassifierInstance node = retrieved.get(0); String oldValue = node.getPropertyValue(((ChangeProperty) command).property); @@ -269,7 +268,7 @@ public DeltaCommandResponse receiveCommand(DeltaCommand command) { sequenceNumber -> new PropertyChanged( sequenceNumber, node.getID(), changeProperty.property, newValue, oldValue)); - return new DeltaCommandResponse(); + return DeltaCommandResponse.accepted(); } throw new UnsupportedOperationException( diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index 85d157cc2..19b15d4db 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -1,6 +1,7 @@ package io.lionweb.client.delta; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import io.lionweb.LionWebVersion; import io.lionweb.client.api.HistorySupport; @@ -54,4 +55,30 @@ public void simpleSynchronizationOfNodesInstances() { assertEquals("Language A", language1.getName()); assertEquals("Language A", language2.getName()); } + + @Test + public void changingUnexistingNodeCauseError() { + InMemoryServer server = new InMemoryServer(); + server.createRepository( + new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); + + JsonSerialization serialization = + SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); + Language language1 = new Language("Language A", "lang-a", "lang-a-key"); + // We do NOT create the partition on the repository + + DeltaChannel channel = new InMemoryDeltaChannel(); + DeltaClient client = new DeltaClient(channel); + + server.monitorDeltaChannel("MyRepo", channel); + + client.monitor(language1); + try { + language1.setName("Language B"); + } catch (CommandRejectException e) { + assertEquals("Node with id lang-a not found", e.getMessage()); + return; + } + fail("Expected exception not thrown"); + } } From 6890e014b761756697bfc203f8821a08821433cb Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Fri, 24 Oct 2025 12:20:30 +0200 Subject: [PATCH 12/30] Remove `DeltaInMemoryServer` and redundant event handling code from `InMemoryServer` for simplification and cleanup. --- .../client/delta/DeltaInMemoryServer.java | 49 ------------------- .../client/inmemory/InMemoryServer.java | 18 ------- 2 files changed, 67 deletions(-) delete mode 100644 client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java b/client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java deleted file mode 100644 index a5078bb4b..000000000 --- a/client/src/main/java/io/lionweb/client/delta/DeltaInMemoryServer.java +++ /dev/null @@ -1,49 +0,0 @@ -package io.lionweb.client.delta; - -import io.lionweb.client.delta.messages.DeltaEvent; -import io.lionweb.client.delta.messages.events.properties.PropertyChanged; -import io.lionweb.model.ClassifierInstance; -import io.lionweb.model.ClassifierInstanceUtils; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -public class DeltaInMemoryServer implements DeltaEventReceiver { - private DeltaChannel channel; - private HashMap>>> nodes = new HashMap<>(); - - public DeltaInMemoryServer(DeltaChannel channel) { - this.channel = channel; - } - - @Override - public void receiveEvent(DeltaEvent event) { - if (event instanceof PropertyChanged) { - PropertyChanged propertyChanged = (PropertyChanged) event; - for (WeakReference> classifierInstanceRef : - nodes.get(propertyChanged.node)) { - ClassifierInstance classifierInstance = classifierInstanceRef.get(); - if (classifierInstance != null) { - ClassifierInstanceUtils.setPropertyValueByMetaPointer( - classifierInstance, propertyChanged.property, propertyChanged.newValue); - } - } - } else { - throw new UnsupportedOperationException( - "Unsupported event type: " + event.getClass().getName()); - } - } - - public void cleanUp() { - // optional: call periodically to remove dead refs globally - Iterator>>>> it = - nodes.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry>>> e = it.next(); - e.getValue().removeIf(ref -> ref.get() == null); - if (e.getValue().isEmpty()) it.remove(); - } - } -} diff --git a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java index 0317c7719..e0f1e6b95 100644 --- a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java @@ -273,24 +273,6 @@ public DeltaCommandResponse receiveCommand(DeltaCommand command) { throw new UnsupportedOperationException( "Unsupported command type: " + command.getClass().getName()); - - // The server only cares about commands - // if (event instanceof PropertyChanged) { - // PropertyChanged propertyChanged = (PropertyChanged) event; - // event. - // for (WeakReference> classifierInstanceRef : - // nodes.get(propertyChanged.node)) { - // ClassifierInstance classifierInstance = classifierInstanceRef.get(); - // if (classifierInstance != null) { - // ClassifierInstanceUtils.setPropertyValueByMetaPointer( - // classifierInstance, propertyChanged.property, - // propertyChanged.newValue); - // } - // } - // } else { - // throw new UnsupportedOperationException( - // "Unsupported event type: " + event.getClass().getName()); - // } } } From 2324b09c388d6e3a4856becd74cfa620cebda7fd Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sat, 25 Oct 2025 20:05:41 +0200 Subject: [PATCH 13/30] Rename DeltaQuery classes to follow consistent `Request` suffix naming convention and add corresponding `Response` classes with null safety improvements and validations. --- .../messages/queries/GetAvailableIds.java | 13 --------- .../messages/queries/ListPartitions.java | 11 -------- .../queries/partitcipations/Reconnect.java | 16 ----------- .../queries/partitcipations/SignOff.java | 11 -------- .../queries/partitcipations/SignOn.java | 19 ------------- .../SubscribeToChangingPartitions.java | 28 ------------------- .../SubscribeToPartitionContents.java | 15 ---------- .../UnsubscribeFromPartitionContents.java | 13 --------- 8 files changed, 126 deletions(-) delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/GetAvailableIds.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/ListPartitions.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/Reconnect.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOff.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOn.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToChangingPartitions.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToPartitionContents.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/UnsubscribeFromPartitionContents.java diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/GetAvailableIds.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/GetAvailableIds.java deleted file mode 100644 index b181b2e92..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/GetAvailableIds.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.lionweb.client.delta.messages.queries; - -import io.lionweb.client.delta.messages.DeltaQuery; -import org.jetbrains.annotations.NotNull; - -public class GetAvailableIds extends DeltaQuery { - public int count; - - public GetAvailableIds(@NotNull String queryId, int count) { - super(queryId); - this.count = count; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/ListPartitions.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/ListPartitions.java deleted file mode 100644 index 8aba32c33..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/ListPartitions.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.lionweb.client.delta.messages.queries; - -import io.lionweb.client.delta.messages.DeltaQuery; -import org.jetbrains.annotations.NotNull; - -public class ListPartitions extends DeltaQuery { - - public ListPartitions(@NotNull String queryId) { - super(queryId); - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/Reconnect.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/Reconnect.java deleted file mode 100644 index c0f94dda5..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/Reconnect.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.lionweb.client.delta.messages.queries.partitcipations; - -import io.lionweb.client.delta.messages.DeltaQuery; -import org.jetbrains.annotations.NotNull; - -public class Reconnect extends DeltaQuery { - public final String participationId; - public final String lastReceivedSequenceNumber; - - public Reconnect( - @NotNull String queryId, String participationId, String lastReceivedSequenceNumber) { - super(queryId); - this.participationId = participationId; - this.lastReceivedSequenceNumber = lastReceivedSequenceNumber; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOff.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOff.java deleted file mode 100644 index 7e4899365..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOff.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.lionweb.client.delta.messages.queries.partitcipations; - -import io.lionweb.client.delta.messages.DeltaQuery; -import org.jetbrains.annotations.NotNull; - -public class SignOff extends DeltaQuery { - - public SignOff(@NotNull String queryId) { - super(queryId); - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOn.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOn.java deleted file mode 100644 index 57aa70240..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/partitcipations/SignOn.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.lionweb.client.delta.messages.queries.partitcipations; - -import io.lionweb.client.delta.DeltaProtocolVersion; -import io.lionweb.client.delta.messages.DeltaQuery; -import org.jetbrains.annotations.NotNull; - -public class SignOn extends DeltaQuery { - public final @NotNull DeltaProtocolVersion deltaProtocolVersion; - public final @NotNull String clientId; - - public SignOn( - @NotNull String queryId, - @NotNull DeltaProtocolVersion deltaProtocolVersion, - @NotNull String clientId) { - super(queryId); - this.deltaProtocolVersion = deltaProtocolVersion; - this.clientId = clientId; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToChangingPartitions.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToChangingPartitions.java deleted file mode 100644 index 982ca7622..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToChangingPartitions.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.lionweb.client.delta.messages.queries.subscriptions; - -import io.lionweb.client.delta.messages.DeltaQuery; -import org.jetbrains.annotations.NotNull; - -public class SubscribeToChangingPartitions extends DeltaQuery { - /** - * Whether this client wants to receive events on newly created partitions (true), or not (false) - */ - private boolean creation; - - /** Whether this client wants to receive events on deleted partitions (true), or not (false). */ - private boolean deletion; - - /** - * Whether this client wants to automatically subscribe to newly created partitions (true), or not - * (false). - */ - private boolean partitions; - - public SubscribeToChangingPartitions( - @NotNull String queryId, boolean creation, boolean deletion, boolean partitions) { - super(queryId); - this.creation = creation; - this.deletion = deletion; - this.partitions = partitions; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToPartitionContents.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToPartitionContents.java deleted file mode 100644 index ecfc9c77a..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/SubscribeToPartitionContents.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.lionweb.client.delta.messages.queries.subscriptions; - -import io.lionweb.client.delta.messages.DeltaQuery; -import org.jetbrains.annotations.NotNull; - -public class SubscribeToPartitionContents extends DeltaQuery { - - /** TargetNode Node id of the partition this client wants to receive events of. */ - private String partition; - - public SubscribeToPartitionContents(@NotNull String queryId, String partition) { - super(queryId); - this.partition = partition; - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/UnsubscribeFromPartitionContents.java b/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/UnsubscribeFromPartitionContents.java deleted file mode 100644 index 2cba431ae..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/queries/subscriptions/UnsubscribeFromPartitionContents.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.lionweb.client.delta.messages.queries.subscriptions; - -import io.lionweb.client.delta.messages.DeltaQuery; - -public class UnsubscribeFromPartitionContents extends DeltaQuery { - - public final String partition; - - public UnsubscribeFromPartitionContents(String queryId, String partition) { - super(queryId); - this.partition = partition; - } -} From 2c644e601635a648dbbad0b46386c125381f086a Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sat, 25 Oct 2025 20:08:28 +0200 Subject: [PATCH 14/30] Refactor `CommonDeltaEvent` to `BaseDeltaEvent`, updating all dependent event classes for consistency and introducing abstract enforcement for standardized behavior. --- .../delta/messages/CommonDeltaEvent.java | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/CommonDeltaEvent.java diff --git a/client/src/main/java/io/lionweb/client/delta/messages/CommonDeltaEvent.java b/client/src/main/java/io/lionweb/client/delta/messages/CommonDeltaEvent.java deleted file mode 100644 index 849b0f709..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/CommonDeltaEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.lionweb.client.delta.messages; - -import io.lionweb.client.delta.CommandSource; -import java.util.LinkedList; -import java.util.List; - -public class CommonDeltaEvent extends DeltaEvent { - public final int sequenceNumber; - public final List originCommands = new LinkedList<>(); - - public CommonDeltaEvent(int sequenceNumber) { - this.sequenceNumber = sequenceNumber; - } - - public void addSource(CommandSource source) { - originCommands.add(source); - } -} From 7fc2d66c89a67171bfdcbc535a5527fab9813557 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sat, 25 Oct 2025 20:19:52 +0200 Subject: [PATCH 15/30] Replace `DeltaCommandResponse` architecture with `ErrorEvent` handling, removing classes and methods related to command responses and adding standardized error codes for improved error propagation and diagnostics. --- .../client/delta/CommandRejectException.java | 7 ---- .../io/lionweb/client/delta/DeltaChannel.java | 2 +- .../io/lionweb/client/delta/DeltaClient.java | 24 ++++++------- .../client/delta/DeltaCommandReceiver.java | 3 +- .../delta/ErrorEventReceivedException.java | 34 +++++++++++++++++++ .../client/delta/InMemoryDeltaChannel.java | 6 ++-- .../delta/messages/DeltaCommandResponse.java | 21 ------------ .../client/inmemory/InMemoryServer.java | 16 ++++++--- .../delta/DeltaClientAndServerTest.java | 6 ++-- 9 files changed, 64 insertions(+), 55 deletions(-) delete mode 100644 client/src/main/java/io/lionweb/client/delta/CommandRejectException.java create mode 100644 client/src/main/java/io/lionweb/client/delta/ErrorEventReceivedException.java delete mode 100644 client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java diff --git a/client/src/main/java/io/lionweb/client/delta/CommandRejectException.java b/client/src/main/java/io/lionweb/client/delta/CommandRejectException.java deleted file mode 100644 index 5a1e1dcfa..000000000 --- a/client/src/main/java/io/lionweb/client/delta/CommandRejectException.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.lionweb.client.delta; - -public class CommandRejectException extends RuntimeException { - public CommandRejectException(String message) { - super(message); - } -} diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java index 3c153c320..4d330d7d1 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java @@ -23,7 +23,7 @@ public interface DeltaChannel { * the command, or rejects a failed command.[5] However, the repository processes the command * asynchronously, and eventually broadcasts the effect(s) as event. */ - DeltaCommandResponse sendCommand(Function commandProducer); + void sendCommand(Function commandProducer); void sendEvent(Function eventProducer); diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index 140d4362d..8c118fe13 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -1,9 +1,9 @@ package io.lionweb.client.delta; import io.lionweb.LionWebVersion; -import io.lionweb.client.delta.messages.DeltaCommandResponse; import io.lionweb.client.delta.messages.DeltaEvent; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; +import io.lionweb.client.delta.messages.events.ErrorEvent; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; import io.lionweb.language.Containment; import io.lionweb.language.Property; @@ -67,6 +67,9 @@ public void receiveEvent(DeltaEvent event) { classifierInstance, propertyChanged.property, propertyChanged.newValue); } } + } else if (event instanceof ErrorEvent) { + ErrorEvent errorEvent = (ErrorEvent) event; + throw new ErrorEventReceivedException(errorEvent.errorCode, errorEvent.message); } else { throw new UnsupportedOperationException( "Unsupported event type: " + event.getClass().getName()); @@ -81,18 +84,13 @@ public void propertyChanged( Property property, Object oldValue, Object newValue) { - DeltaCommandResponse response = - channel.sendCommand( - commandId -> - new ChangeProperty( - commandId, - classifierInstance.getID(), - MetaPointer.from(property), - primitiveValuesSerialization.serialize( - property.getType().getID(), newValue))); - if (!response.accepted) { - throw new CommandRejectException(response.errorMessage); - } + channel.sendCommand( + commandId -> + new ChangeProperty( + commandId, + classifierInstance.getID(), + MetaPointer.from(property), + primitiveValuesSerialization.serialize(property.getType().getID(), newValue))); } @Override diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java b/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java index bdeda798c..8ee57768a 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java @@ -1,9 +1,8 @@ package io.lionweb.client.delta; import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.client.delta.messages.DeltaCommandResponse; public interface DeltaCommandReceiver { - DeltaCommandResponse receiveCommand(DeltaCommand command); + void receiveCommand(DeltaCommand command); } diff --git a/client/src/main/java/io/lionweb/client/delta/ErrorEventReceivedException.java b/client/src/main/java/io/lionweb/client/delta/ErrorEventReceivedException.java new file mode 100644 index 000000000..2c115d17d --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/ErrorEventReceivedException.java @@ -0,0 +1,34 @@ +package io.lionweb.client.delta; + +import java.util.Objects; + +public class ErrorEventReceivedException extends RuntimeException { + private String code; + private String errorMessage; + + public ErrorEventReceivedException(String code, String errorMessage) { + super("code=" + code + " message=" + errorMessage); + this.code = code; + this.errorMessage = errorMessage; + } + + public String getCode() { + return code; + } + + public String getErrorMessage() { + return errorMessage; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + ErrorEventReceivedException that = (ErrorEventReceivedException) o; + return Objects.equals(code, that.code) && Objects.equals(errorMessage, that.errorMessage); + } + + @Override + public int hashCode() { + return Objects.hash(code, errorMessage); + } +} diff --git a/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java index af3c80c57..718d40764 100644 --- a/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java +++ b/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java @@ -18,11 +18,9 @@ public DeltaQueryResponse sendQuery(DeltaQuery query) { } @Override - public DeltaCommandResponse sendCommand(Function commandProducer) { + public void sendCommand(Function commandProducer) { if (commandReceiver != null) { - return commandReceiver.receiveCommand(commandProducer.apply("cmd-" + nextCommandId++)); - } else { - return null; + commandReceiver.receiveCommand(commandProducer.apply("cmd-" + nextCommandId++)); } } diff --git a/client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java b/client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java deleted file mode 100644 index 610747e68..000000000 --- a/client/src/main/java/io/lionweb/client/delta/messages/DeltaCommandResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.lionweb.client.delta.messages; - -import org.jetbrains.annotations.Nullable; - -public class DeltaCommandResponse { - public final boolean accepted; - public final @Nullable String errorMessage; - - private DeltaCommandResponse(boolean accepted, @Nullable String errorMessage) { - this.accepted = accepted; - this.errorMessage = errorMessage; - } - - public static DeltaCommandResponse accepted() { - return new DeltaCommandResponse(true, null); - } - - public static DeltaCommandResponse rejected(String errorMessage) { - return new DeltaCommandResponse(false, errorMessage); - } -} diff --git a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java index e0f1e6b95..5966f59e9 100644 --- a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java @@ -5,8 +5,9 @@ import io.lionweb.client.delta.DeltaChannel; import io.lionweb.client.delta.DeltaCommandReceiver; import io.lionweb.client.delta.messages.DeltaCommand; -import io.lionweb.client.delta.messages.DeltaCommandResponse; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; +import io.lionweb.client.delta.messages.events.ErrorEvent; +import io.lionweb.client.delta.messages.events.StandardErrorCode; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; import io.lionweb.model.ClassifierInstance; import io.lionweb.model.Node; @@ -248,7 +249,7 @@ private DeltaCommandReceiverImpl(String repositoryName, DeltaChannel channel) { } @Override - public DeltaCommandResponse receiveCommand(DeltaCommand command) { + public void receiveCommand(DeltaCommand command) { if (command instanceof ChangeProperty) { ChangeProperty changeProperty = (ChangeProperty) command; RepositoryData repositoryData = getRepository(repositoryName); @@ -256,8 +257,13 @@ public DeltaCommandResponse receiveCommand(DeltaCommand command) { try { repositoryData.retrieve(changeProperty.node, 0, retrieved); } catch (IllegalArgumentException e) { - return DeltaCommandResponse.rejected( - "Node with id " + changeProperty.node + " not found"); + channel.sendEvent( + sequenceNumber -> + new ErrorEvent( + sequenceNumber, + StandardErrorCode.UNKNOWN_NODE, + "Node with id " + changeProperty.node + " not found")); + return; } SerializedClassifierInstance node = retrieved.get(0); String oldValue = node.getPropertyValue(((ChangeProperty) command).property); @@ -268,7 +274,7 @@ public DeltaCommandResponse receiveCommand(DeltaCommand command) { sequenceNumber -> new PropertyChanged( sequenceNumber, node.getID(), changeProperty.property, newValue, oldValue)); - return DeltaCommandResponse.accepted(); + return; } throw new UnsupportedOperationException( diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index 19b15d4db..7e23ef788 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -6,6 +6,7 @@ import io.lionweb.LionWebVersion; import io.lionweb.client.api.HistorySupport; import io.lionweb.client.api.RepositoryConfiguration; +import io.lionweb.client.delta.messages.events.StandardErrorCode; import io.lionweb.client.inmemory.InMemoryServer; import io.lionweb.language.Language; import io.lionweb.serialization.JsonSerialization; @@ -75,8 +76,9 @@ public void changingUnexistingNodeCauseError() { client.monitor(language1); try { language1.setName("Language B"); - } catch (CommandRejectException e) { - assertEquals("Node with id lang-a not found", e.getMessage()); + } catch (ErrorEventReceivedException e) { + assertEquals(StandardErrorCode.UNKNOWN_NODE.code, e.getCode()); + assertEquals("Node with id lang-a not found", e.getErrorMessage()); return; } fail("Expected exception not thrown"); From 14782e9dfbde157413de54a070f1376bf4f13e3e Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sun, 26 Oct 2025 17:28:57 +0100 Subject: [PATCH 16/30] Add support for `AddChild` DeltaCommand and `ChildAdded` DeltaEvent across server, client, and model layers, introducing indexed child insertion functionality and associated validations. --- .../io/lionweb/client/delta/DeltaClient.java | 51 ++++++++++++++----- .../client/inmemory/InMemoryServer.java | 24 +++++++++ .../delta/DeltaClientAndServerTest.java | 37 ++++++++++++++ .../io/lionweb/model/HasFeatureValues.java | 4 ++ 4 files changed, 104 insertions(+), 12 deletions(-) diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index 8c118fe13..2854d5086 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -2,17 +2,21 @@ import io.lionweb.LionWebVersion; import io.lionweb.client.delta.messages.DeltaEvent; +import io.lionweb.client.delta.messages.commands.children.AddChild; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; import io.lionweb.client.delta.messages.events.ErrorEvent; +import io.lionweb.client.delta.messages.events.children.ChildAdded; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; import io.lionweb.language.Containment; import io.lionweb.language.Property; import io.lionweb.language.Reference; import io.lionweb.model.*; -import io.lionweb.serialization.PrimitiveValuesSerialization; +import io.lionweb.serialization.*; import io.lionweb.serialization.data.MetaPointer; import java.lang.ref.WeakReference; import java.util.*; + +import io.lionweb.serialization.data.SerializationChunk; import org.jetbrains.annotations.NotNull; public class DeltaClient implements DeltaEventReceiver { @@ -22,11 +26,10 @@ public class DeltaClient implements DeltaEventReceiver { private HashMap>>> nodes = new HashMap<>(); private PrimitiveValuesSerialization primitiveValuesSerialization = new PrimitiveValuesSerialization(); + private AbstractSerialization serialization; public DeltaClient(DeltaChannel channel) { this(LionWebVersion.currentVersion, channel); - this.channel = channel; - this.channel.registerEventReceiver(this); } public DeltaClient(LionWebVersion lionWebVersion, DeltaChannel channel) { @@ -35,6 +38,8 @@ public DeltaClient(LionWebVersion lionWebVersion, DeltaChannel channel) { this.channel.registerEventReceiver(this); this.primitiveValuesSerialization.registerLionBuiltinsPrimitiveSerializersAndDeserializers( lionWebVersion); + this.serialization = SerializationProvider.getStandardJsonSerialization(lionWebVersion); + this.serialization.setUnavailableParentPolicy(UnavailableNodePolicy.PROXY_NODES); } /** @@ -58,15 +63,29 @@ public void monitor(@NotNull Node partition) { @Override public void receiveEvent(DeltaEvent event) { if (event instanceof PropertyChanged) { - PropertyChanged propertyChanged = (PropertyChanged) event; - for (WeakReference> classifierInstanceRef : - nodes.get(propertyChanged.node)) { - ClassifierInstance classifierInstance = classifierInstanceRef.get(); - if (classifierInstance != null) { - ClassifierInstanceUtils.setPropertyValueByMetaPointer( - classifierInstance, propertyChanged.property, propertyChanged.newValue); + PropertyChanged propertyChanged = (PropertyChanged) event; + for (WeakReference> classifierInstanceRef : + nodes.get(propertyChanged.node)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + ClassifierInstanceUtils.setPropertyValueByMetaPointer( + classifierInstance, propertyChanged.property, propertyChanged.newValue); + } + } + } else if (event instanceof ChildAdded) { + ChildAdded childAdded = (ChildAdded) event; + for (WeakReference> classifierInstanceRef : + nodes.get(childAdded.parent)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + Node child = (Node)serialization.deserializeSerializationChunk(childAdded.newChild).get(0); + Containment containment = classifierInstance.getClassifier().getContainmentByMetaPointer(childAdded.containment); + if (containment == null) { + throw new IllegalStateException("Containment not found for " + classifierInstance + " using metapointer "+ childAdded.containment); + } + classifierInstance.addChild(containment, child, childAdded.index); + } } - } } else if (event instanceof ErrorEvent) { ErrorEvent errorEvent = (ErrorEvent) event; throw new ErrorEventReceivedException(errorEvent.errorCode, errorEvent.message); @@ -99,7 +118,15 @@ public void childAdded( Containment containment, int index, Node newChild) { - throw new UnsupportedOperationException("Not supported yet."); + SerializationChunk chunk = serialization.serializeNodesToSerializationChunk(newChild); + channel.sendCommand( + commandId -> + new AddChild( + commandId, + classifierInstance.getID(), + chunk, + MetaPointer.from(containment), + index)); } @Override diff --git a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java index 5966f59e9..5ce223fdb 100644 --- a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java @@ -5,9 +5,11 @@ import io.lionweb.client.delta.DeltaChannel; import io.lionweb.client.delta.DeltaCommandReceiver; import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.client.delta.messages.commands.children.AddChild; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; import io.lionweb.client.delta.messages.events.ErrorEvent; import io.lionweb.client.delta.messages.events.StandardErrorCode; +import io.lionweb.client.delta.messages.events.children.ChildAdded; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; import io.lionweb.model.ClassifierInstance; import io.lionweb.model.Node; @@ -275,6 +277,28 @@ public void receiveCommand(DeltaCommand command) { new PropertyChanged( sequenceNumber, node.getID(), changeProperty.property, newValue, oldValue)); return; + } else if (command instanceof AddChild) { + AddChild addChild = (AddChild) command; + RepositoryData repositoryData = getRepository(repositoryName); + List retrieved = new ArrayList<>(); + try { + repositoryData.retrieve(addChild.parent, 0, retrieved); + } catch (IllegalArgumentException e) { + channel.sendEvent( + sequenceNumber -> + new ErrorEvent( + sequenceNumber, + StandardErrorCode.UNKNOWN_NODE, + "Node with id " + addChild.parent + " not found")); + return; + } + SerializedClassifierInstance node = retrieved.get(0); + repositoryData.store(addChild.newChild.getClassifierInstances()); + String childId = addChild.newChild.getClassifierInstances().stream().filter(n -> n.getParentNodeID().equals(addChild.parent)).findFirst().get().getID(); + node.addChild(addChild.containment, childId, addChild.index); + channel.sendEvent(sequenceNumber -> new ChildAdded(sequenceNumber, + addChild.parent, addChild.newChild, addChild.containment, addChild.index)); + return; } throw new UnsupportedOperationException( diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index 7e23ef788..3cbc350e3 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -8,12 +8,15 @@ import io.lionweb.client.api.RepositoryConfiguration; import io.lionweb.client.delta.messages.events.StandardErrorCode; import io.lionweb.client.inmemory.InMemoryServer; +import io.lionweb.language.Concept; import io.lionweb.language.Language; import io.lionweb.serialization.JsonSerialization; import io.lionweb.serialization.SerializationProvider; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.util.Collections; + public class DeltaClientAndServerTest { @Test @@ -83,4 +86,38 @@ public void changingUnexistingNodeCauseError() { } fail("Expected exception not thrown"); } + + @Test + public void addingChildren() { + InMemoryServer server = new InMemoryServer(); + server.createRepository( + new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); + + JsonSerialization serialization = + SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); + Language language1 = new Language("Language A", "lang-a", "lang-a-key"); + server.createPartition("MyRepo", language1, serialization); + + Language language2 = + (Language) server.retrieveAsClassifierInstance("MyRepo", "lang-a", serialization); + Assertions.assertNotNull(language2); + + assertEquals(language1, language2); + + DeltaChannel channel = new InMemoryDeltaChannel(); + DeltaClient client = new DeltaClient(channel); + + server.monitorDeltaChannel("MyRepo", channel); + + client.monitor(language1); + client.monitor(language2); + + assertEquals(Collections.emptyList(), language1.getElements()); + assertEquals(Collections.emptyList(), language2.getElements()); + + Concept concept1 = new Concept(language1, "Concept A", "concept-a", "a"); + language1.addElement(concept1); + assertEquals(Collections.singletonList(concept1), language1.getElements()); + assertEquals(Collections.singletonList(concept1), language2.getElements()); + } } diff --git a/core/src/main/java/io/lionweb/model/HasFeatureValues.java b/core/src/main/java/io/lionweb/model/HasFeatureValues.java index 072d6c52c..43a34a1f6 100644 --- a/core/src/main/java/io/lionweb/model/HasFeatureValues.java +++ b/core/src/main/java/io/lionweb/model/HasFeatureValues.java @@ -35,6 +35,10 @@ void setPropertyValue(@Nonnull Property property, @Nullable Object value) */ void addChild(@Nonnull Containment containment, @Nonnull Node child); + default void addChild(@Nonnull Containment containment, @Nonnull Node child, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + /** * Add a child to the specified list of children associated with the given Containment relation, * at the given index. If the specified Containment does not allow for multiple values, and if a From 2f324a3566db1df7b1308598f4fc95f3d946df82 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 27 Oct 2025 20:35:14 +0100 Subject: [PATCH 17/30] Add participation management with `SignOnRequest` and `SignOnResponse`, introduce `DeltaQueryReceiver` and query response flow, and enhance `DeltaClient` and `InMemoryDeltaChannel` for synchronized command and query handling. --- .../io/lionweb/client/delta/DeltaChannel.java | 12 +- .../io/lionweb/client/delta/DeltaClient.java | 135 +++++++++++++----- .../client/delta/DeltaCommandReceiver.java | 2 +- .../client/delta/DeltaQueryReceiver.java | 9 ++ .../delta/DeltaQueryResponseReceiver.java | 8 ++ .../client/delta/InMemoryDeltaChannel.java | 46 +++++- .../client/inmemory/InMemoryServer.java | 87 ++++++++--- .../delta/DeltaClientAndServerTest.java | 80 ++++++----- .../io/lionweb/model/HasFeatureValues.java | 6 +- 9 files changed, 280 insertions(+), 105 deletions(-) create mode 100644 client/src/main/java/io/lionweb/client/delta/DeltaQueryReceiver.java create mode 100644 client/src/main/java/io/lionweb/client/delta/DeltaQueryResponseReceiver.java diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java index 4d330d7d1..4e58158d5 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaChannel.java @@ -15,7 +15,7 @@ public interface DeltaChannel { * The repository might reply invalid queries with a failure message. We also use queries for * managing participations. */ - DeltaQueryResponse sendQuery(DeltaQuery query); + DeltaQueryResponse sendQuery(Function queryProducer); /** * Commands initiated/requested by the client, with synchronous response by the repository. A @@ -23,7 +23,7 @@ public interface DeltaChannel { * the command, or rejects a failed command.[5] However, the repository processes the command * asynchronously, and eventually broadcasts the effect(s) as event. */ - void sendCommand(Function commandProducer); + void sendCommand(String participationId, Function commandProducer); void sendEvent(Function eventProducer); @@ -34,4 +34,12 @@ public interface DeltaChannel { void registerCommandReceiver(DeltaCommandReceiver deltaCommandReceiver); void unregisterCommandReceiver(DeltaCommandReceiver deltaCommandReceiver); + + void registerQueryReceiver(DeltaQueryReceiver deltaQueryReceiver); + + void unregisterQueryReceiver(DeltaQueryReceiver deltaQueryReceiver); + + void registerQueryResponseReceiver(DeltaQueryResponseReceiver deltaQueryResponseReceiver); + + void unregisterQueryResponseReceiver(DeltaQueryResponseReceiver deltaQueryResponseReceiver); } diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index 2854d5086..910247276 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -1,44 +1,52 @@ package io.lionweb.client.delta; import io.lionweb.LionWebVersion; +import io.lionweb.client.delta.messages.BaseDeltaEvent; import io.lionweb.client.delta.messages.DeltaEvent; +import io.lionweb.client.delta.messages.DeltaQueryResponse; import io.lionweb.client.delta.messages.commands.children.AddChild; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; import io.lionweb.client.delta.messages.events.ErrorEvent; import io.lionweb.client.delta.messages.events.children.ChildAdded; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; +import io.lionweb.client.delta.messages.queries.partitcipations.SignOnRequest; +import io.lionweb.client.delta.messages.queries.partitcipations.SignOnResponse; import io.lionweb.language.Containment; import io.lionweb.language.Property; import io.lionweb.language.Reference; import io.lionweb.model.*; import io.lionweb.serialization.*; import io.lionweb.serialization.data.MetaPointer; +import io.lionweb.serialization.data.SerializationChunk; import java.lang.ref.WeakReference; import java.util.*; - -import io.lionweb.serialization.data.SerializationChunk; import org.jetbrains.annotations.NotNull; -public class DeltaClient implements DeltaEventReceiver { +public class DeltaClient implements DeltaEventReceiver, DeltaQueryResponseReceiver { private LionWebVersion lionWebVersion; private DeltaChannel channel; private MonitoringObserver observer = new MonitoringObserver(); + private String participationId; private HashMap>>> nodes = new HashMap<>(); private PrimitiveValuesSerialization primitiveValuesSerialization = new PrimitiveValuesSerialization(); private AbstractSerialization serialization; + private Set queriesSent = new HashSet<>(); + private String clientId; - public DeltaClient(DeltaChannel channel) { - this(LionWebVersion.currentVersion, channel); + public DeltaClient(DeltaChannel channel, String clientId) { + this(LionWebVersion.currentVersion, channel, clientId); } - public DeltaClient(LionWebVersion lionWebVersion, DeltaChannel channel) { + public DeltaClient(LionWebVersion lionWebVersion, DeltaChannel channel, String clientId) { + this.clientId = clientId; this.lionWebVersion = lionWebVersion; this.channel = channel; this.channel.registerEventReceiver(this); + this.channel.registerQueryResponseReceiver(this); this.primitiveValuesSerialization.registerLionBuiltinsPrimitiveSerializersAndDeserializers( lionWebVersion); - this.serialization = SerializationProvider.getStandardJsonSerialization(lionWebVersion); + this.serialization = SerializationProvider.getStandardJsonSerialization(lionWebVersion); this.serialization.setUnavailableParentPolicy(UnavailableNodePolicy.PROXY_NODES); } @@ -60,50 +68,84 @@ public void monitor(@NotNull Node partition) { } } + protected void monitorNode(Node node) { + nodes.computeIfAbsent(node.getID(), id -> new HashSet<>()).add(new WeakReference<>(node)); + } + @Override public void receiveEvent(DeltaEvent event) { + if (event instanceof BaseDeltaEvent) { + BaseDeltaEvent baseDeltaEvent = (BaseDeltaEvent) event; + + if (baseDeltaEvent.originCommands.stream() + .anyMatch( + (CommandSource originCommand) -> + originCommand.participationId.equals(this.participationId))) { + return; + } + } + observer.paused = true; if (event instanceof PropertyChanged) { - PropertyChanged propertyChanged = (PropertyChanged) event; - for (WeakReference> classifierInstanceRef : - nodes.get(propertyChanged.node)) { - ClassifierInstance classifierInstance = classifierInstanceRef.get(); - if (classifierInstance != null) { - ClassifierInstanceUtils.setPropertyValueByMetaPointer( - classifierInstance, propertyChanged.property, propertyChanged.newValue); - } + PropertyChanged propertyChanged = (PropertyChanged) event; + Set>> matchingNodes = + this.nodes.get(propertyChanged.node); + if (matchingNodes != null) { + for (WeakReference> classifierInstanceRef : matchingNodes) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + ClassifierInstanceUtils.setPropertyValueByMetaPointer( + classifierInstance, propertyChanged.property, propertyChanged.newValue); + } } + } } else if (event instanceof ChildAdded) { - ChildAdded childAdded = (ChildAdded) event; - for (WeakReference> classifierInstanceRef : - nodes.get(childAdded.parent)) { - ClassifierInstance classifierInstance = classifierInstanceRef.get(); - if (classifierInstance != null) { - Node child = (Node)serialization.deserializeSerializationChunk(childAdded.newChild).get(0); - Containment containment = classifierInstance.getClassifier().getContainmentByMetaPointer(childAdded.containment); - if (containment == null) { - throw new IllegalStateException("Containment not found for " + classifierInstance + " using metapointer "+ childAdded.containment); - } - classifierInstance.addChild(containment, child, childAdded.index); - } + ChildAdded childAdded = (ChildAdded) event; + for (WeakReference> classifierInstanceRef : + nodes.get(childAdded.parent)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + Node child = + (Node) serialization.deserializeSerializationChunk(childAdded.newChild).get(0); + monitorNode(child); + Containment containment = + classifierInstance + .getClassifier() + .getContainmentByMetaPointer(childAdded.containment); + if (containment == null) { + throw new IllegalStateException( + "Containment not found for " + + classifierInstance + + " using metapointer " + + childAdded.containment); + } + classifierInstance.addChild(containment, child, childAdded.index); } + } } else if (event instanceof ErrorEvent) { ErrorEvent errorEvent = (ErrorEvent) event; + observer.paused = false; throw new ErrorEventReceivedException(errorEvent.errorCode, errorEvent.message); } else { + observer.paused = false; throw new UnsupportedOperationException( "Unsupported event type: " + event.getClass().getName()); } + observer.paused = false; } private class MonitoringObserver implements PartitionObserver { + public boolean paused = false; + @Override public void propertyChanged( ClassifierInstance classifierInstance, Property property, Object oldValue, Object newValue) { + if (paused) return; channel.sendCommand( + participationId, commandId -> new ChangeProperty( commandId, @@ -118,15 +160,17 @@ public void childAdded( Containment containment, int index, Node newChild) { - SerializationChunk chunk = serialization.serializeNodesToSerializationChunk(newChild); - channel.sendCommand( - commandId -> - new AddChild( - commandId, - classifierInstance.getID(), - chunk, - MetaPointer.from(containment), - index)); + if (paused) return; + SerializationChunk chunk = serialization.serializeNodesToSerializationChunk(newChild); + channel.sendCommand( + participationId, + commandId -> + new AddChild( + commandId, + classifierInstance.getID(), + chunk, + MetaPointer.from(containment), + index)); } @Override @@ -179,4 +223,23 @@ public void referenceValueRemoved( throw new UnsupportedOperationException("Not supported yet."); } } + + @Override + public void receiveQueryResponse(DeltaQueryResponse queryResponse) { + if (!queriesSent.contains(queryResponse.queryId)) return; + if (queryResponse instanceof SignOnResponse) { + SignOnResponse signOnResponse = (SignOnResponse) queryResponse; + this.participationId = signOnResponse.participationId; + return; + } + throw new UnsupportedOperationException("Not supported yet."); + } + + public void sendSignOnRequest() { + channel.sendQuery( + queryId -> { + queriesSent.add(queryId); + return new SignOnRequest(queryId, DeltaProtocolVersion.v2025_1, clientId); + }); + } } diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java b/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java index 8ee57768a..aff65f977 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaCommandReceiver.java @@ -4,5 +4,5 @@ public interface DeltaCommandReceiver { - void receiveCommand(DeltaCommand command); + void receiveCommand(String participationId, DeltaCommand command); } diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaQueryReceiver.java b/client/src/main/java/io/lionweb/client/delta/DeltaQueryReceiver.java new file mode 100644 index 000000000..47e8585fa --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/DeltaQueryReceiver.java @@ -0,0 +1,9 @@ +package io.lionweb.client.delta; + +import io.lionweb.client.delta.messages.DeltaQuery; +import io.lionweb.client.delta.messages.DeltaQueryResponse; + +public interface DeltaQueryReceiver { + + DeltaQueryResponse receiveQuery(DeltaQuery query); +} diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaQueryResponseReceiver.java b/client/src/main/java/io/lionweb/client/delta/DeltaQueryResponseReceiver.java new file mode 100644 index 000000000..510026af7 --- /dev/null +++ b/client/src/main/java/io/lionweb/client/delta/DeltaQueryResponseReceiver.java @@ -0,0 +1,8 @@ +package io.lionweb.client.delta; + +import io.lionweb.client.delta.messages.DeltaQueryResponse; + +public interface DeltaQueryResponseReceiver { + + void receiveQueryResponse(DeltaQueryResponse queryResponse); +} diff --git a/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java b/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java index 718d40764..e2b105a70 100644 --- a/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java +++ b/client/src/main/java/io/lionweb/client/delta/InMemoryDeltaChannel.java @@ -1,26 +1,39 @@ package io.lionweb.client.delta; import io.lionweb.client.delta.messages.*; -import java.util.HashSet; -import java.util.Set; +import java.util.*; import java.util.function.Function; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class InMemoryDeltaChannel implements DeltaChannel { private final Set eventReceivers = new HashSet<>(); private @Nullable DeltaCommandReceiver commandReceiver; + private @Nullable DeltaQueryReceiver queryReceiver; + private @Nullable List queryResponseReceivers = new ArrayList<>(); private int nextEventId = 1; private int nextCommandId = 1; + private int nextQueryId = 1; @Override - public DeltaQueryResponse sendQuery(DeltaQuery query) { - throw new UnsupportedOperationException("Not supported yet."); + public DeltaQueryResponse sendQuery(Function queryProducer) { + if (queryReceiver != null) { + DeltaQueryResponse response = + queryReceiver.receiveQuery(queryProducer.apply("query-" + nextQueryId++)); + queryResponseReceivers.forEach(receiver -> receiver.receiveQueryResponse(response)); + return response; + } + + return null; } @Override - public void sendCommand(Function commandProducer) { + public void sendCommand( + @NotNull String participationId, Function commandProducer) { + Objects.requireNonNull(participationId, "participationId must not be null"); if (commandReceiver != null) { - commandReceiver.receiveCommand(commandProducer.apply("cmd-" + nextCommandId++)); + commandReceiver.receiveCommand( + participationId, commandProducer.apply("cmd-" + nextCommandId++)); } } @@ -48,4 +61,25 @@ public void unregisterCommandReceiver(DeltaCommandReceiver deltaCommandReceiver) public void sendEvent(Function eventProducer) { eventReceivers.forEach(receiver -> receiver.receiveEvent(eventProducer.apply(nextEventId++))); } + + @Override + public void registerQueryReceiver(DeltaQueryReceiver deltaQueryReceiver) { + this.queryReceiver = deltaQueryReceiver; + } + + @Override + public void unregisterQueryReceiver(DeltaQueryReceiver deltaQueryReceiver) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void registerQueryResponseReceiver(DeltaQueryResponseReceiver deltaQueryResponseReceiver) { + this.queryResponseReceivers.add(deltaQueryResponseReceiver); + } + + @Override + public void unregisterQueryResponseReceiver( + DeltaQueryResponseReceiver deltaQueryResponseReceiver) { + throw new UnsupportedOperationException("Not supported yet."); + } } diff --git a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java index 5ce223fdb..b37de8ce1 100644 --- a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java @@ -2,15 +2,21 @@ import io.lionweb.LionWebVersion; import io.lionweb.client.api.*; +import io.lionweb.client.delta.CommandSource; import io.lionweb.client.delta.DeltaChannel; import io.lionweb.client.delta.DeltaCommandReceiver; +import io.lionweb.client.delta.DeltaQueryReceiver; import io.lionweb.client.delta.messages.DeltaCommand; +import io.lionweb.client.delta.messages.DeltaQuery; +import io.lionweb.client.delta.messages.DeltaQueryResponse; import io.lionweb.client.delta.messages.commands.children.AddChild; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; import io.lionweb.client.delta.messages.events.ErrorEvent; import io.lionweb.client.delta.messages.events.StandardErrorCode; import io.lionweb.client.delta.messages.events.children.ChildAdded; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; +import io.lionweb.client.delta.messages.queries.partitcipations.SignOnRequest; +import io.lionweb.client.delta.messages.queries.partitcipations.SignOnResponse; import io.lionweb.model.ClassifierInstance; import io.lionweb.model.Node; import io.lionweb.serialization.AbstractSerialization; @@ -38,6 +44,8 @@ public class InMemoryServer { /** Internally we store the data separately for each repository. */ private final Map repositories = new LinkedHashMap<>(); + private int nextParticipationId = 1; + public @NotNull RepositoryConfiguration getRepositoryConfiguration( @NotNull String repositoryName) { return getRepository(repositoryName).configuration; @@ -239,6 +247,27 @@ public Map nodesByLanguage( public void monitorDeltaChannel(String repositoryName, @NotNull DeltaChannel channel) { Objects.requireNonNull(channel, "Channel should not be null"); channel.registerCommandReceiver(new DeltaCommandReceiverImpl(repositoryName, channel)); + channel.registerQueryReceiver(new DeltaQueryReceiverImpl(repositoryName, channel)); + } + + private class DeltaQueryReceiverImpl implements DeltaQueryReceiver { + + private String repositoryName; + private DeltaChannel channel; + + private DeltaQueryReceiverImpl(String repositoryName, DeltaChannel channel) { + this.repositoryName = repositoryName; + this.channel = channel; + } + + @Override + public DeltaQueryResponse receiveQuery(DeltaQuery query) { + if (query instanceof SignOnRequest) { + SignOnRequest signOnRequest = (SignOnRequest) query; + return new SignOnResponse(signOnRequest.queryId, "participation-" + nextParticipationId++); + } + throw new UnsupportedOperationException("Not supported yet."); + } } private class DeltaCommandReceiverImpl implements DeltaCommandReceiver { @@ -251,7 +280,8 @@ private DeltaCommandReceiverImpl(String repositoryName, DeltaChannel channel) { } @Override - public void receiveCommand(DeltaCommand command) { + public void receiveCommand(String participationId, DeltaCommand command) { + CommandSource source = new CommandSource(participationId, command.commandId); if (command instanceof ChangeProperty) { ChangeProperty changeProperty = (ChangeProperty) command; RepositoryData repositoryData = getRepository(repositoryName); @@ -275,30 +305,43 @@ public void receiveCommand(DeltaCommand command) { channel.sendEvent( sequenceNumber -> new PropertyChanged( - sequenceNumber, node.getID(), changeProperty.property, newValue, oldValue)); + sequenceNumber, node.getID(), changeProperty.property, newValue, oldValue) + .addSource(source)); return; } else if (command instanceof AddChild) { - AddChild addChild = (AddChild) command; - RepositoryData repositoryData = getRepository(repositoryName); - List retrieved = new ArrayList<>(); - try { - repositoryData.retrieve(addChild.parent, 0, retrieved); - } catch (IllegalArgumentException e) { - channel.sendEvent( - sequenceNumber -> - new ErrorEvent( - sequenceNumber, - StandardErrorCode.UNKNOWN_NODE, - "Node with id " + addChild.parent + " not found")); - return; - } - SerializedClassifierInstance node = retrieved.get(0); - repositoryData.store(addChild.newChild.getClassifierInstances()); - String childId = addChild.newChild.getClassifierInstances().stream().filter(n -> n.getParentNodeID().equals(addChild.parent)).findFirst().get().getID(); - node.addChild(addChild.containment, childId, addChild.index); - channel.sendEvent(sequenceNumber -> new ChildAdded(sequenceNumber, - addChild.parent, addChild.newChild, addChild.containment, addChild.index)); + AddChild addChild = (AddChild) command; + RepositoryData repositoryData = getRepository(repositoryName); + List retrieved = new ArrayList<>(); + try { + repositoryData.retrieve(addChild.parent, 0, retrieved); + } catch (IllegalArgumentException e) { + channel.sendEvent( + sequenceNumber -> + new ErrorEvent( + sequenceNumber, + StandardErrorCode.UNKNOWN_NODE, + "Node with id " + addChild.parent + " not found")); return; + } + SerializedClassifierInstance node = retrieved.get(0); + repositoryData.store(addChild.newChild.getClassifierInstances()); + String childId = + addChild.newChild.getClassifierInstances().stream() + .filter(n -> n.getParentNodeID().equals(addChild.parent)) + .findFirst() + .get() + .getID(); + node.addChild(addChild.containment, childId, addChild.index); + channel.sendEvent( + sequenceNumber -> + new ChildAdded( + sequenceNumber, + addChild.parent, + addChild.newChild, + addChild.containment, + addChild.index) + .addSource(source)); + return; } throw new UnsupportedOperationException( diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index 3cbc350e3..f2f71b9ad 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -1,7 +1,6 @@ package io.lionweb.client.delta; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import io.lionweb.LionWebVersion; import io.lionweb.client.api.HistorySupport; @@ -12,11 +11,11 @@ import io.lionweb.language.Language; import io.lionweb.serialization.JsonSerialization; import io.lionweb.serialization.SerializationProvider; +import io.lionweb.utils.ModelComparator; +import java.util.Collections; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.Collections; - public class DeltaClientAndServerTest { @Test @@ -37,12 +36,14 @@ public void simpleSynchronizationOfNodesInstances() { assertEquals(language1, language2); DeltaChannel channel = new InMemoryDeltaChannel(); - DeltaClient client = new DeltaClient(channel); - server.monitorDeltaChannel("MyRepo", channel); - client.monitor(language1); - client.monitor(language2); + DeltaClient client1 = new DeltaClient(channel, "my-client-1"); + client1.sendSignOnRequest(); + client1.monitor(language1); + DeltaClient client2 = new DeltaClient(channel, "my-client-2"); + client2.sendSignOnRequest(); + client2.monitor(language2); assertEquals("Language A", language1.getName()); assertEquals("Language A", language2.getName()); @@ -72,10 +73,11 @@ public void changingUnexistingNodeCauseError() { // We do NOT create the partition on the repository DeltaChannel channel = new InMemoryDeltaChannel(); - DeltaClient client = new DeltaClient(channel); - server.monitorDeltaChannel("MyRepo", channel); + DeltaClient client = new DeltaClient(channel, "my-client-1"); + client.sendSignOnRequest(); + client.monitor(language1); try { language1.setName("Language B"); @@ -87,37 +89,45 @@ public void changingUnexistingNodeCauseError() { fail("Expected exception not thrown"); } - @Test - public void addingChildren() { - InMemoryServer server = new InMemoryServer(); - server.createRepository( - new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); + @Test + public void addingChildren() { + InMemoryServer server = new InMemoryServer(); + server.createRepository( + new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); + + JsonSerialization serialization = + SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); + Language language1 = new Language("Language A", "lang-a", "lang-a-key"); + server.createPartition("MyRepo", language1, serialization); - JsonSerialization serialization = - SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); - Language language1 = new Language("Language A", "lang-a", "lang-a-key"); - server.createPartition("MyRepo", language1, serialization); + Language language2 = + (Language) server.retrieveAsClassifierInstance("MyRepo", "lang-a", serialization); + Assertions.assertNotNull(language2); - Language language2 = - (Language) server.retrieveAsClassifierInstance("MyRepo", "lang-a", serialization); - Assertions.assertNotNull(language2); + assertEquals(language1, language2); - assertEquals(language1, language2); + DeltaChannel channel = new InMemoryDeltaChannel(); + server.monitorDeltaChannel("MyRepo", channel); - DeltaChannel channel = new InMemoryDeltaChannel(); - DeltaClient client = new DeltaClient(channel); + DeltaClient client1 = new DeltaClient(channel, "my-client-1"); + client1.sendSignOnRequest(); - server.monitorDeltaChannel("MyRepo", channel); + DeltaClient client2 = new DeltaClient(channel, "my-client-2"); + client2.sendSignOnRequest(); - client.monitor(language1); - client.monitor(language2); + client1.monitor(language1); + client2.monitor(language2); - assertEquals(Collections.emptyList(), language1.getElements()); - assertEquals(Collections.emptyList(), language2.getElements()); + assertEquals(Collections.emptyList(), language1.getElements()); + assertEquals(Collections.emptyList(), language2.getElements()); - Concept concept1 = new Concept(language1, "Concept A", "concept-a", "a"); - language1.addElement(concept1); - assertEquals(Collections.singletonList(concept1), language1.getElements()); - assertEquals(Collections.singletonList(concept1), language2.getElements()); - } + Concept concept1 = new Concept(language1, "Concept A", "concept-a", "a"); + language1.addElement(concept1); + assertTrue( + ModelComparator.areEquivalent( + Collections.singletonList(concept1), language1.getElements())); + assertTrue( + ModelComparator.areEquivalent( + Collections.singletonList(concept1), language2.getElements())); + } } diff --git a/core/src/main/java/io/lionweb/model/HasFeatureValues.java b/core/src/main/java/io/lionweb/model/HasFeatureValues.java index 43a34a1f6..ef8c382de 100644 --- a/core/src/main/java/io/lionweb/model/HasFeatureValues.java +++ b/core/src/main/java/io/lionweb/model/HasFeatureValues.java @@ -35,9 +35,9 @@ void setPropertyValue(@Nonnull Property property, @Nullable Object value) */ void addChild(@Nonnull Containment containment, @Nonnull Node child); - default void addChild(@Nonnull Containment containment, @Nonnull Node child, int index) { - throw new UnsupportedOperationException("Not supported yet."); - } + default void addChild(@Nonnull Containment containment, @Nonnull Node child, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } /** * Add a child to the specified list of children associated with the given Containment relation, From 25c75a2e42e222580f555693ef516d67e1a077e6 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 3 Nov 2025 19:51:58 +0100 Subject: [PATCH 18/30] Add support for `DeleteChild` DeltaCommand and `ChildDeleted` DeltaEvent, enabling child removal across server, client, and model layers, with accompanying tests and validations. --- .../io/lionweb/client/delta/DeltaClient.java | 38 ++++++++++++- .../client/inmemory/InMemoryServer.java | 28 +++++++++ .../delta/DeltaClientAndServerTest.java | 57 +++++++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index 910247276..d88f29033 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -5,9 +5,11 @@ import io.lionweb.client.delta.messages.DeltaEvent; import io.lionweb.client.delta.messages.DeltaQueryResponse; import io.lionweb.client.delta.messages.commands.children.AddChild; +import io.lionweb.client.delta.messages.commands.children.DeleteChild; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; import io.lionweb.client.delta.messages.events.ErrorEvent; import io.lionweb.client.delta.messages.events.children.ChildAdded; +import io.lionweb.client.delta.messages.events.children.ChildDeleted; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; import io.lionweb.client.delta.messages.queries.partitcipations.SignOnRequest; import io.lionweb.client.delta.messages.queries.partitcipations.SignOnResponse; @@ -121,6 +123,26 @@ public void receiveEvent(DeltaEvent event) { classifierInstance.addChild(containment, child, childAdded.index); } } + } else if (event instanceof ChildDeleted) { + ChildDeleted childDeleted = (ChildDeleted) event; + for (WeakReference> classifierInstanceRef : + nodes.get(childDeleted.parent)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + Containment containment = + classifierInstance + .getClassifier() + .getContainmentByMetaPointer(childDeleted.containment); + if (containment == null) { + throw new IllegalStateException( + "Containment not found for " + + classifierInstance + + " using metapointer " + + childDeleted.containment); + } + classifierInstance.removeChild(containment, childDeleted.index); + } + } } else if (event instanceof ErrorEvent) { ErrorEvent errorEvent = (ErrorEvent) event; observer.paused = false; @@ -178,8 +200,20 @@ public void childRemoved( ClassifierInstance classifierInstance, Containment containment, int index, - Node removedChild) { - throw new UnsupportedOperationException("Not supported yet."); + @NotNull Node removedChild) { + if (paused) return; + Objects.requireNonNull(removedChild, "removedChild must not be null"); + String removedChildId = removedChild.getID(); + Objects.requireNonNull(removedChildId, "removedChildId must not be null"); + channel.sendCommand( + participationId, + commandId -> + new DeleteChild( + commandId, + classifierInstance.getID(), + MetaPointer.from(containment), + index, + removedChildId)); } @Override diff --git a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java index b37de8ce1..6b45f11e0 100644 --- a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java @@ -10,10 +10,12 @@ import io.lionweb.client.delta.messages.DeltaQuery; import io.lionweb.client.delta.messages.DeltaQueryResponse; import io.lionweb.client.delta.messages.commands.children.AddChild; +import io.lionweb.client.delta.messages.commands.children.DeleteChild; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; import io.lionweb.client.delta.messages.events.ErrorEvent; import io.lionweb.client.delta.messages.events.StandardErrorCode; import io.lionweb.client.delta.messages.events.children.ChildAdded; +import io.lionweb.client.delta.messages.events.children.ChildDeleted; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; import io.lionweb.client.delta.messages.queries.partitcipations.SignOnRequest; import io.lionweb.client.delta.messages.queries.partitcipations.SignOnResponse; @@ -342,6 +344,32 @@ public void receiveCommand(String participationId, DeltaCommand command) { addChild.index) .addSource(source)); return; + } else if (command instanceof DeleteChild) { + DeleteChild deleteChild = (DeleteChild) command; + RepositoryData repositoryData = getRepository(repositoryName); + List retrieved = new ArrayList<>(); + try { + repositoryData.retrieve(deleteChild.parent, 0, retrieved); + } catch (IllegalArgumentException e) { + channel.sendEvent( + sequenceNumber -> + new ErrorEvent( + sequenceNumber, + StandardErrorCode.UNKNOWN_NODE, + "Node with id " + deleteChild.parent + " not found")); + return; + } + SerializedClassifierInstance node = retrieved.get(0); + channel.sendEvent( + sequenceNumber -> + new ChildDeleted( + sequenceNumber, + deleteChild.parent, + deleteChild.containment, + deleteChild.index, + deleteChild.deletedChild) + .addSource(source)); + return; } throw new UnsupportedOperationException( diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index f2f71b9ad..ed5683d5e 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -12,6 +12,8 @@ import io.lionweb.serialization.JsonSerialization; import io.lionweb.serialization.SerializationProvider; import io.lionweb.utils.ModelComparator; + +import java.util.Arrays; import java.util.Collections; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -130,4 +132,59 @@ public void addingChildren() { ModelComparator.areEquivalent( Collections.singletonList(concept1), language2.getElements())); } + + @Test + public void removingChildren() { + InMemoryServer server = new InMemoryServer(); + server.createRepository( + new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); + + JsonSerialization serialization = + SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); + Language language1 = new Language("Language A", "lang-a", "lang-a-key"); + server.createPartition("MyRepo", language1, serialization); + + Language language2 = + (Language) server.retrieveAsClassifierInstance("MyRepo", "lang-a", serialization); + Assertions.assertNotNull(language2); + + assertEquals(language1, language2); + + DeltaChannel channel = new InMemoryDeltaChannel(); + server.monitorDeltaChannel("MyRepo", channel); + + DeltaClient client1 = new DeltaClient(channel, "my-client-1"); + client1.sendSignOnRequest(); + + DeltaClient client2 = new DeltaClient(channel, "my-client-2"); + client2.sendSignOnRequest(); + + client1.monitor(language1); + client2.monitor(language2); + + Concept concept1 = new Concept(language1, "Concept A", "concept-a", "a"); + language1.addElement(concept1); + Concept concept2 = new Concept(language1, "Concept B", "concept-b", "b"); + language1.addElement(concept2); + Concept concept3 = new Concept(language1, "Concept C", "concept-c", "c"); + language1.addElement(concept3); + + assertEquals(Arrays.asList(concept1, concept2, concept3), language1.getElements()); + assertEquals(Arrays.asList(concept1, concept2, concept3), language2.getElements()); + + language1.removeChild(concept2); + + assertEquals(Arrays.asList(concept1, concept3), language1.getElements()); + assertEquals(Arrays.asList(concept1, concept3), language2.getElements()); + + language1.removeChild(concept3); + + assertEquals(Arrays.asList(concept1), language1.getElements()); + assertEquals(Arrays.asList(concept1), language2.getElements()); + + language1.removeChild(concept1); + + assertEquals(Arrays.asList(), language1.getElements()); + assertEquals(Arrays.asList(), language2.getElements()); + } } From 786f6861aae0a12fd3da57d319b36568ab866bb1 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 3 Nov 2025 20:04:26 +0100 Subject: [PATCH 19/30] Add constructor overloads with `id` parameter to language model entities (`Enumeration`, `DataType`, `EnumerationLiteral`, etc.), refactor initialization logic for improved safety and consistency, and update related tests for validation. --- .../io/lionweb/client/delta/DeltaClient.java | 65 +-- .../client/inmemory/InMemoryServer.java | 46 +-- .../delta/DeltaClientAndServerTest.java | 387 ++++++++++++++++-- .../java/io/lionweb/language/DataType.java | 4 + .../lionweb/language/EnumerationLiteral.java | 8 + 5 files changed, 416 insertions(+), 94 deletions(-) diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index d88f29033..1475ffdf1 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -124,25 +124,25 @@ public void receiveEvent(DeltaEvent event) { } } } else if (event instanceof ChildDeleted) { - ChildDeleted childDeleted = (ChildDeleted) event; - for (WeakReference> classifierInstanceRef : - nodes.get(childDeleted.parent)) { - ClassifierInstance classifierInstance = classifierInstanceRef.get(); - if (classifierInstance != null) { - Containment containment = - classifierInstance - .getClassifier() - .getContainmentByMetaPointer(childDeleted.containment); - if (containment == null) { - throw new IllegalStateException( - "Containment not found for " - + classifierInstance - + " using metapointer " - + childDeleted.containment); - } - classifierInstance.removeChild(containment, childDeleted.index); - } + ChildDeleted childDeleted = (ChildDeleted) event; + for (WeakReference> classifierInstanceRef : + nodes.get(childDeleted.parent)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + Containment containment = + classifierInstance + .getClassifier() + .getContainmentByMetaPointer(childDeleted.containment); + if (containment == null) { + throw new IllegalStateException( + "Containment not found for " + + classifierInstance + + " using metapointer " + + childDeleted.containment); + } + classifierInstance.removeChild(containment, childDeleted.index); } + } } else if (event instanceof ErrorEvent) { ErrorEvent errorEvent = (ErrorEvent) event; observer.paused = false; @@ -184,6 +184,9 @@ public void childAdded( Node newChild) { if (paused) return; SerializationChunk chunk = serialization.serializeNodesToSerializationChunk(newChild); + if (newChild.getID() == null) { + throw new IllegalStateException("Child id must not be null"); + } channel.sendCommand( participationId, commandId -> @@ -201,19 +204,19 @@ public void childRemoved( Containment containment, int index, @NotNull Node removedChild) { - if (paused) return; - Objects.requireNonNull(removedChild, "removedChild must not be null"); - String removedChildId = removedChild.getID(); - Objects.requireNonNull(removedChildId, "removedChildId must not be null"); - channel.sendCommand( - participationId, - commandId -> - new DeleteChild( - commandId, - classifierInstance.getID(), - MetaPointer.from(containment), - index, - removedChildId)); + if (paused) return; + Objects.requireNonNull(removedChild, "removedChild must not be null"); + String removedChildId = removedChild.getID(); + Objects.requireNonNull(removedChildId, "removedChildId must not be null"); + channel.sendCommand( + participationId, + commandId -> + new DeleteChild( + commandId, + classifierInstance.getID(), + MetaPointer.from(containment), + index, + removedChildId)); } @Override diff --git a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java index 6b45f11e0..d5197559c 100644 --- a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java @@ -345,31 +345,31 @@ public void receiveCommand(String participationId, DeltaCommand command) { .addSource(source)); return; } else if (command instanceof DeleteChild) { - DeleteChild deleteChild = (DeleteChild) command; - RepositoryData repositoryData = getRepository(repositoryName); - List retrieved = new ArrayList<>(); - try { - repositoryData.retrieve(deleteChild.parent, 0, retrieved); - } catch (IllegalArgumentException e) { - channel.sendEvent( - sequenceNumber -> - new ErrorEvent( - sequenceNumber, - StandardErrorCode.UNKNOWN_NODE, - "Node with id " + deleteChild.parent + " not found")); - return; - } - SerializedClassifierInstance node = retrieved.get(0); + DeleteChild deleteChild = (DeleteChild) command; + RepositoryData repositoryData = getRepository(repositoryName); + List retrieved = new ArrayList<>(); + try { + repositoryData.retrieve(deleteChild.parent, 0, retrieved); + } catch (IllegalArgumentException e) { channel.sendEvent( - sequenceNumber -> - new ChildDeleted( - sequenceNumber, - deleteChild.parent, - deleteChild.containment, - deleteChild.index, - deleteChild.deletedChild) - .addSource(source)); + sequenceNumber -> + new ErrorEvent( + sequenceNumber, + StandardErrorCode.UNKNOWN_NODE, + "Node with id " + deleteChild.parent + " not found")); return; + } + SerializedClassifierInstance node = retrieved.get(0); + channel.sendEvent( + sequenceNumber -> + new ChildDeleted( + sequenceNumber, + deleteChild.parent, + deleteChild.containment, + deleteChild.index, + deleteChild.deletedChild) + .addSource(source)); + return; } throw new UnsupportedOperationException( diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index ed5683d5e..e35529aff 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -8,11 +8,12 @@ import io.lionweb.client.delta.messages.events.StandardErrorCode; import io.lionweb.client.inmemory.InMemoryServer; import io.lionweb.language.Concept; +import io.lionweb.language.Enumeration; +import io.lionweb.language.EnumerationLiteral; import io.lionweb.language.Language; import io.lionweb.serialization.JsonSerialization; import io.lionweb.serialization.SerializationProvider; import io.lionweb.utils.ModelComparator; - import java.util.Arrays; import java.util.Collections; import org.junit.jupiter.api.Assertions; @@ -133,58 +134,364 @@ public void addingChildren() { Collections.singletonList(concept1), language2.getElements())); } - @Test - public void removingChildren() { - InMemoryServer server = new InMemoryServer(); - server.createRepository( - new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); + @Test + public void removingChildren() { + InMemoryServer server = new InMemoryServer(); + server.createRepository( + new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); - JsonSerialization serialization = - SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); - Language language1 = new Language("Language A", "lang-a", "lang-a-key"); - server.createPartition("MyRepo", language1, serialization); + JsonSerialization serialization = + SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); + Language language1 = new Language("Language A", "lang-a", "lang-a-key"); + server.createPartition("MyRepo", language1, serialization); - Language language2 = - (Language) server.retrieveAsClassifierInstance("MyRepo", "lang-a", serialization); - Assertions.assertNotNull(language2); + Language language2 = + (Language) server.retrieveAsClassifierInstance("MyRepo", "lang-a", serialization); + Assertions.assertNotNull(language2); - assertEquals(language1, language2); + assertEquals(language1, language2); - DeltaChannel channel = new InMemoryDeltaChannel(); - server.monitorDeltaChannel("MyRepo", channel); + DeltaChannel channel = new InMemoryDeltaChannel(); + server.monitorDeltaChannel("MyRepo", channel); - DeltaClient client1 = new DeltaClient(channel, "my-client-1"); - client1.sendSignOnRequest(); + DeltaClient client1 = new DeltaClient(channel, "my-client-1"); + client1.sendSignOnRequest(); - DeltaClient client2 = new DeltaClient(channel, "my-client-2"); - client2.sendSignOnRequest(); + DeltaClient client2 = new DeltaClient(channel, "my-client-2"); + client2.sendSignOnRequest(); + + client1.monitor(language1); + client2.monitor(language2); - client1.monitor(language1); - client2.monitor(language2); + Concept concept1 = new Concept(language1, "Concept A", "concept-a", "a"); + language1.addElement(concept1); + Concept concept2 = new Concept(language1, "Concept B", "concept-b", "b"); + language1.addElement(concept2); + Concept concept3 = new Concept(language1, "Concept C", "concept-c", "c"); + language1.addElement(concept3); - Concept concept1 = new Concept(language1, "Concept A", "concept-a", "a"); - language1.addElement(concept1); - Concept concept2 = new Concept(language1, "Concept B", "concept-b", "b"); - language1.addElement(concept2); - Concept concept3 = new Concept(language1, "Concept C", "concept-c", "c"); - language1.addElement(concept3); + assertEquals(Arrays.asList(concept1, concept2, concept3), language1.getElements()); + assertEquals(Arrays.asList(concept1, concept2, concept3), language2.getElements()); - assertEquals(Arrays.asList(concept1, concept2, concept3), language1.getElements()); - assertEquals(Arrays.asList(concept1, concept2, concept3), language2.getElements()); + language1.removeChild(concept2); - language1.removeChild(concept2); + assertEquals(Arrays.asList(concept1, concept3), language1.getElements()); + assertEquals(Arrays.asList(concept1, concept3), language2.getElements()); - assertEquals(Arrays.asList(concept1, concept3), language1.getElements()); - assertEquals(Arrays.asList(concept1, concept3), language2.getElements()); + language1.removeChild(concept3); - language1.removeChild(concept3); + assertEquals(Arrays.asList(concept1), language1.getElements()); + assertEquals(Arrays.asList(concept1), language2.getElements()); - assertEquals(Arrays.asList(concept1), language1.getElements()); - assertEquals(Arrays.asList(concept1), language2.getElements()); + language1.removeChild(concept1); - language1.removeChild(concept1); + assertEquals(Arrays.asList(), language1.getElements()); + assertEquals(Arrays.asList(), language2.getElements()); + } - assertEquals(Arrays.asList(), language1.getElements()); - assertEquals(Arrays.asList(), language2.getElements()); - } + @Test + public void variousOperations() { + InMemoryServer server = new InMemoryServer(); + server.createRepository( + new RepositoryConfiguration("MyRepo", LionWebVersion.v2024_1, HistorySupport.DISABLED)); + + JsonSerialization serialization = + SerializationProvider.getStandardJsonSerialization(LionWebVersion.v2024_1); + Language language1 = new Language("Language A", "lang-a", "lang-a-key"); + server.createPartition("MyRepo", language1, serialization); + + Language language2 = + (Language) server.retrieveAsClassifierInstance("MyRepo", "lang-a", serialization); + Assertions.assertNotNull(language2); + + assertEquals(language1, language2); + + DeltaChannel channel = new InMemoryDeltaChannel(); + server.monitorDeltaChannel("MyRepo", channel); + + DeltaClient client1 = new DeltaClient(channel, "my-client-1"); + client1.sendSignOnRequest(); + + DeltaClient client2 = new DeltaClient(channel, "my-client-2"); + client2.sendSignOnRequest(); + + client1.monitor(language1); + client2.monitor(language2); + + // HERE DO A LOT OF OPERATIONS CREATING A LANGUAGE AND CHANGING IT + + // 1. Change language name multiple times + language1.setName("Language Modified"); + language1.setName("Business Domain Language"); + language1.setName("Enterprise Modeling Language"); + + // 2. Create enumerations + Enumeration statusEnum = + new Enumeration(language1, "Status", "status-enum").setKey("status"); + language1.addElement(statusEnum); + + EnumerationLiteral activeStatus = + new EnumerationLiteral(statusEnum, "Active", "active-literal").setKey("active"); + statusEnum.addLiteral(activeStatus); + EnumerationLiteral inactiveStatus = + new EnumerationLiteral(statusEnum, "Inactive", "inactive-literal").setKey("inactive"); + statusEnum.addLiteral(inactiveStatus); + EnumerationLiteral pendingStatus = + new EnumerationLiteral(statusEnum, "Pending", "pending-literal").setKey("pending"); + statusEnum.addLiteral(pendingStatus); + + // Add another enumeration + Enumeration priorityEnum = + new Enumeration(language1, "Priority", "priority-enum").setKey("priority"); + language1.addElement(priorityEnum); + + EnumerationLiteral highPriority = + new EnumerationLiteral(priorityEnum, "High", "high-literal").setKey("high"); + priorityEnum.addLiteral(highPriority); + EnumerationLiteral mediumPriority = + new EnumerationLiteral(priorityEnum, "Medium", "medium-literal").setKey("medium"); + priorityEnum.addLiteral(mediumPriority); + EnumerationLiteral lowPriority = + new EnumerationLiteral(priorityEnum, "Low", "low-literal").setKey("low"); + priorityEnum.addLiteral(lowPriority); + + // // 3. Create interfaces + // Interface namedInterface = new Interface(language1, "Named", "named-interface", + // "named"); + // language1.addElement(namedInterface); + // + // Interface identifiableInterface = new Interface(language1, "Identifiable", + // "identifiable-interface", "identifiable"); + // language1.addElement(identifiableInterface); + // + // Interface auditableInterface = new Interface(language1, "Auditable", + // "auditable-interface", "auditable"); + // language1.addElement(auditableInterface); + // + // Interface timestampedInterface = new Interface(language1, "Timestamped", + // "timestamped-interface", "timestamped"); + // language1.addElement(timestampedInterface); + // + // // 4. Make interfaces extend other interfaces + // auditableInterface.addExtendedInterface(timestampedInterface); + // namedInterface.addExtendedInterface(identifiableInterface); + // + // // 5. Add features to interfaces + // Property nameProperty = new Property(namedInterface, "name", "name-property", "name"); + // nameProperty.setType(PrimitiveType.STRING); + // namedInterface.addFeature(nameProperty); + // + // Property idProperty = new Property(identifiableInterface, "id", "id-property", "id"); + // idProperty.setType(PrimitiveType.STRING); + // identifiableInterface.addFeature(idProperty); + // + // Property createdAtProperty = new Property(timestampedInterface, "createdAt", + // "created-at-property", "createdAt"); + // createdAtProperty.setType(PrimitiveType.STRING); + // timestampedInterface.addFeature(createdAtProperty); + // + // Property modifiedAtProperty = new Property(timestampedInterface, "modifiedAt", + // "modified-at-property", "modifiedAt"); + // modifiedAtProperty.setType(PrimitiveType.STRING); + // timestampedInterface.addFeature(modifiedAtProperty); + // + // // 6. Create concepts + // Concept personConcept = new Concept(language1, "Person", "person-concept", "person"); + // language1.addElement(personConcept); + // + // Concept companyConcept = new Concept(language1, "Company", "company-concept", + // "company"); + // language1.addElement(companyConcept); + // + // Concept addressConcept = new Concept(language1, "Address", "address-concept", + // "address"); + // language1.addElement(addressConcept); + // + // Concept baseConcept = new Concept(language1, "BaseEntity", "base-entity-concept", + // "baseEntity"); + // language1.addElement(baseConcept); + // + // // 7. Make concepts implement interfaces + // personConcept.addImplementedInterface(namedInterface); + // personConcept.addImplementedInterface(auditableInterface); + // + // companyConcept.addImplementedInterface(namedInterface); + // companyConcept.addImplementedInterface(identifiableInterface); + // + // addressConcept.addImplementedInterface(timestampedInterface); + // + // baseConcept.addImplementedInterface(identifiableInterface); + // baseConcept.addImplementedInterface(auditableInterface); + // + // // 8. Set up concept inheritance + // personConcept.setExtendedConcept(baseConcept); + // companyConcept.setExtendedConcept(baseConcept); + // + // // 9. Add features to concepts + // Property ageProperty = new Property(personConcept, "age", "age-property", "age"); + // ageProperty.setType(PrimitiveType.INTEGER); + // personConcept.addFeature(ageProperty); + // + // Property emailProperty = new Property(personConcept, "email", "email-property", + // "email"); + // emailProperty.setType(PrimitiveType.STRING); + // personConcept.addFeature(emailProperty); + // + // Property statusProperty = new Property(personConcept, "status", "status-property", + // "status"); + // statusProperty.setType(statusEnum); + // personConcept.addFeature(statusProperty); + // + // Property employeeCountProperty = new Property(companyConcept, "employeeCount", + // "employee-count-property", "employeeCount"); + // employeeCountProperty.setType(PrimitiveType.INTEGER); + // companyConcept.addFeature(employeeCountProperty); + // + // Property streetProperty = new Property(addressConcept, "street", "street-property", + // "street"); + // streetProperty.setType(PrimitiveType.STRING); + // addressConcept.addFeature(streetProperty); + // + // Property cityProperty = new Property(addressConcept, "city", "city-property", "city"); + // cityProperty.setType(PrimitiveType.STRING); + // addressConcept.addFeature(cityProperty); + // + // // 10. Add containment references + // Containment addressesContainment = new Containment(personConcept, "addresses", + // "addresses-containment", "addresses"); + // addressesContainment.setType(addressConcept); + // addressesContainment.setMultiple(true); + // personConcept.addFeature(addressesContainment); + // + // Containment employeesContainment = new Containment(companyConcept, "employees", + // "employees-containment", "employees"); + // employeesContainment.setType(personConcept); + // employeesContainment.setMultiple(true); + // companyConcept.addFeature(employeesContainment); + // + // // 11. Add regular references + // Reference companyReference = new Reference(personConcept, "employer", + // "employer-reference", "employer"); + // companyReference.setType(companyConcept); + // companyReference.setOptional(true); + // personConcept.addFeature(companyReference); + // + // // 12. Move features between concepts + // personConcept.removeFeature(emailProperty); + // baseConcept.addFeature(emailProperty); + // + // // 13. Modify feature properties + // ageProperty.setOptional(true); + // statusProperty.setOptional(false); + // employeeCountProperty.setOptional(true); + // + // // 14. Add more enumeration literals + // EnumerationLiteral archivedStatus = new EnumerationLiteral(statusEnum, "Archived", + // "archived-literal", "archived"); + // statusEnum.addLiteral(archivedStatus); + // + // // Remove and re-add enumeration literal + // statusEnum.removeLiteral(pendingStatus); + // EnumerationLiteral reviewingStatus = new EnumerationLiteral(statusEnum, "Reviewing", + // "reviewing-literal", "reviewing"); + // statusEnum.addLiteral(reviewingStatus); + // + // // 15. Modify interface hierarchy + // Interface versionedInterface = new Interface(language1, "Versioned", + // "versioned-interface", "versioned"); + // language1.addElement(versionedInterface); + // + // Property versionProperty = new Property(versionedInterface, "version", + // "version-property", "version"); + // versionProperty.setType(PrimitiveType.INTEGER); + // versionedInterface.addFeature(versionProperty); + // + // auditableInterface.addExtendedInterface(versionedInterface); + // + // // 16. Create abstract concepts + // Concept documentConcept = new Concept(language1, "Document", "document-concept", + // "document"); + // documentConcept.setAbstract(true); + // language1.addElement(documentConcept); + // + // documentConcept.addImplementedInterface(namedInterface); + // documentConcept.addImplementedInterface(versionedInterface); + // + // Concept reportConcept = new Concept(language1, "Report", "report-concept", "report"); + // language1.addElement(reportConcept); + // reportConcept.setExtendedConcept(documentConcept); + // + // Concept contractConcept = new Concept(language1, "Contract", "contract-concept", + // "contract"); + // language1.addElement(contractConcept); + // contractConcept.setExtendedConcept(documentConcept); + // + // // 17. Add features with different cardinalities + // Property tagsProperty = new Property(documentConcept, "tags", "tags-property", + // "tags"); + // tagsProperty.setType(PrimitiveType.STRING); + // tagsProperty.setMultiple(true); + // documentConcept.addFeature(tagsProperty); + // + // Property priorityProperty = new Property(reportConcept, "priority", + // "priority-property", "priority"); + // priorityProperty.setType(priorityEnum); + // reportConcept.addFeature(priorityProperty); + // + // // 18. Move features within the same concept (change order) + // personConcept.removeFeature(ageProperty); + // personConcept.removeFeature(statusProperty); + // personConcept.addFeature(statusProperty); + // personConcept.addFeature(ageProperty); + // + // // 19. Create complex reference relationships + // Reference authorReference = new Reference(documentConcept, "author", + // "author-reference", "author"); + // authorReference.setType(personConcept); + // documentConcept.addFeature(authorReference); + // + // Reference clientReference = new Reference(contractConcept, "client", + // "client-reference", "client"); + // clientReference.setType(companyConcept); + // contractConcept.addFeature(clientReference); + // + // // 20. Modify existing elements + // statusEnum.setName("EntityStatus"); + // priorityEnum.setName("TaskPriority"); + // + // activeStatus.setName("ACTIVE"); + // inactiveStatus.setName("INACTIVE"); + // + // namedInterface.setName("NamedEntity"); + // identifiableInterface.setName("UniqueEntity"); + // + // // 21. Remove and re-add features with modifications + // companyConcept.removeFeature(employeeCountProperty); + // Property staffSizeProperty = new Property(companyConcept, "staffSize", + // "staff-size-property", "staffSize"); + // staffSizeProperty.setType(PrimitiveType.INTEGER); + // staffSizeProperty.setOptional(false); + // companyConcept.addFeature(staffSizeProperty); + // + // // 22. Change concept inheritance + // Concept organizationConcept = new Concept(language1, "Organization", + // "organization-concept", "organization"); + // language1.addElement(organizationConcept); + // organizationConcept.setExtendedConcept(baseConcept); + // organizationConcept.addImplementedInterface(namedInterface); + // + // companyConcept.setExtendedConcept(organizationConcept); + // + // // 23. Add final modifications + // Property descriptionProperty = new Property(organizationConcept, "description", + // "description-property", "description"); + // descriptionProperty.setType(PrimitiveType.STRING); + // descriptionProperty.setOptional(true); + // organizationConcept.addFeature(descriptionProperty); + // + // // 24. Final language name change + // language1.setName("Complete Enterprise Domain Language"); + + assertEquals(language1, language2); + } } diff --git a/core/src/main/java/io/lionweb/language/DataType.java b/core/src/main/java/io/lionweb/language/DataType.java index 040676b31..1290912b6 100644 --- a/core/src/main/java/io/lionweb/language/DataType.java +++ b/core/src/main/java/io/lionweb/language/DataType.java @@ -38,4 +38,8 @@ public DataType(@Nonnull String id) { public DataType(@Nullable Language language, @Nullable String name, @Nonnull String id) { super(language, name, id); } + + public DataType(@Nullable Language language, @Nullable String name, @Nonnull String id) { + super(language, name, id); + } } diff --git a/core/src/main/java/io/lionweb/language/EnumerationLiteral.java b/core/src/main/java/io/lionweb/language/EnumerationLiteral.java index 6e506c822..bd5536d5e 100644 --- a/core/src/main/java/io/lionweb/language/EnumerationLiteral.java +++ b/core/src/main/java/io/lionweb/language/EnumerationLiteral.java @@ -33,6 +33,14 @@ public EnumerationLiteral( enumeration.addLiteral(this); } + public EnumerationLiteral(@Nonnull Enumeration enumeration, @Nullable String name, @Nonnull String id) { + this(enumeration.getLionWebVersion()); + setID(id); + enumeration.addLiteral(this); + setParent(enumeration); + setName(name); + } + @Override public @Nullable String getName() { return getPropertyValue("name", String.class); From 8dfc3b9af80699c20f930c678750a75813174dfa Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 3 Nov 2025 20:30:25 +0100 Subject: [PATCH 20/30] Add indexed reference value support to model layers, implement `AddReference` DeltaCommand and `ReferenceAdded` DeltaEvent, update partition observers for index handling, and enhance `Enumeration` initialization with `id` constructor overloads. --- .../io/lionweb/client/delta/DeltaClient.java | 42 ++++++++- .../client/inmemory/InMemoryServer.java | 35 ++++++++ .../delta/DeltaClientAndServerTest.java | 87 +++++++++---------- .../lionweb/language/EnumerationLiteral.java | 15 ++-- .../io/lionweb/language/LanguageEntity.java | 1 + .../io/lionweb/model/HasFeatureValues.java | 3 + .../java/io/lionweb/model/impl/ProxyNode.java | 6 ++ .../io/lionweb/emf/EMFMetamodelImporter.java | 3 +- .../lionweb/emf/EMFMetamodelExporterTest.java | 10 +-- 9 files changed, 142 insertions(+), 60 deletions(-) diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index 1475ffdf1..409470b0e 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -7,16 +7,19 @@ import io.lionweb.client.delta.messages.commands.children.AddChild; import io.lionweb.client.delta.messages.commands.children.DeleteChild; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; +import io.lionweb.client.delta.messages.commands.references.AddReference; import io.lionweb.client.delta.messages.events.ErrorEvent; import io.lionweb.client.delta.messages.events.children.ChildAdded; import io.lionweb.client.delta.messages.events.children.ChildDeleted; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; +import io.lionweb.client.delta.messages.events.references.ReferenceAdded; import io.lionweb.client.delta.messages.queries.partitcipations.SignOnRequest; import io.lionweb.client.delta.messages.queries.partitcipations.SignOnResponse; import io.lionweb.language.Containment; import io.lionweb.language.Property; import io.lionweb.language.Reference; import io.lionweb.model.*; +import io.lionweb.model.impl.ProxyNode; import io.lionweb.serialization.*; import io.lionweb.serialization.data.MetaPointer; import io.lionweb.serialization.data.SerializationChunk; @@ -147,6 +150,30 @@ public void receiveEvent(DeltaEvent event) { ErrorEvent errorEvent = (ErrorEvent) event; observer.paused = false; throw new ErrorEventReceivedException(errorEvent.errorCode, errorEvent.message); + } else if (event instanceof ReferenceAdded) { + ReferenceAdded referenceAdded = (ReferenceAdded) event; + for (WeakReference> classifierInstanceRef : + nodes.get(referenceAdded.parent)) { + ClassifierInstance classifierInstance = classifierInstanceRef.get(); + if (classifierInstance != null) { + Reference reference = + classifierInstance + .getClassifier() + .getReferenceByMetaPointer(referenceAdded.reference); + if (reference == null) { + throw new IllegalStateException( + "Reference not found for " + + classifierInstance + + " using metapointer " + + referenceAdded.reference); + } + classifierInstance.addReferenceValue( + reference, + referenceAdded.index, + new ReferenceValue( + new ProxyNode(referenceAdded.newTarget), referenceAdded.newResolveInfo)); + } + } } else { observer.paused = false; throw new UnsupportedOperationException( @@ -185,7 +212,7 @@ public void childAdded( if (paused) return; SerializationChunk chunk = serialization.serializeNodesToSerializationChunk(newChild); if (newChild.getID() == null) { - throw new IllegalStateException("Child id must not be null"); + throw new IllegalStateException("Child id must not be null"); } channel.sendCommand( participationId, @@ -235,8 +262,19 @@ public void annotationRemoved( public void referenceValueAdded( ClassifierInstance classifierInstance, Reference reference, + int index, ReferenceValue referenceValue) { - throw new UnsupportedOperationException("Not supported yet."); + if (paused) return; + channel.sendCommand( + participationId, + commandId -> + new AddReference( + commandId, + classifierInstance.getID(), + MetaPointer.from(reference), + index, + referenceValue.getReferredID(), + referenceValue.getResolveInfo())); } @Override diff --git a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java index d5197559c..c1aee213c 100644 --- a/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java +++ b/client/src/main/java/io/lionweb/client/inmemory/InMemoryServer.java @@ -12,11 +12,13 @@ import io.lionweb.client.delta.messages.commands.children.AddChild; import io.lionweb.client.delta.messages.commands.children.DeleteChild; import io.lionweb.client.delta.messages.commands.properties.ChangeProperty; +import io.lionweb.client.delta.messages.commands.references.AddReference; import io.lionweb.client.delta.messages.events.ErrorEvent; import io.lionweb.client.delta.messages.events.StandardErrorCode; import io.lionweb.client.delta.messages.events.children.ChildAdded; import io.lionweb.client.delta.messages.events.children.ChildDeleted; import io.lionweb.client.delta.messages.events.properties.PropertyChanged; +import io.lionweb.client.delta.messages.events.references.ReferenceAdded; import io.lionweb.client.delta.messages.queries.partitcipations.SignOnRequest; import io.lionweb.client.delta.messages.queries.partitcipations.SignOnResponse; import io.lionweb.model.ClassifierInstance; @@ -25,6 +27,7 @@ import io.lionweb.serialization.data.MetaPointer; import io.lionweb.serialization.data.SerializationChunk; import io.lionweb.serialization.data.SerializedClassifierInstance; +import io.lionweb.serialization.data.SerializedReferenceValue; import io.lionweb.utils.ValidationResult; import java.util.*; import java.util.stream.Collectors; @@ -370,6 +373,38 @@ public void receiveCommand(String participationId, DeltaCommand command) { deleteChild.deletedChild) .addSource(source)); return; + } else if (command instanceof AddReference) { + AddReference addReference = (AddReference) command; + RepositoryData repositoryData = getRepository(repositoryName); + List retrieved = new ArrayList<>(); + try { + repositoryData.retrieve(addReference.parent, 0, retrieved); + } catch (IllegalArgumentException e) { + channel.sendEvent( + sequenceNumber -> + new ErrorEvent( + sequenceNumber, + StandardErrorCode.UNKNOWN_NODE, + "Node with id " + addReference.parent + " not found")); + return; + } + SerializedClassifierInstance node = retrieved.get(0); + node.addReferenceValue( + addReference.reference, + addReference.index, + new SerializedReferenceValue.Entry( + addReference.newTarget, addReference.newResolveInfo)); + channel.sendEvent( + sequenceNumber -> + new ReferenceAdded( + sequenceNumber, + addReference.parent, + addReference.reference, + addReference.index, + addReference.newTarget, + addReference.newResolveInfo) + .addSource(source)); + return; } throw new UnsupportedOperationException( diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index e35529aff..fb13d54e9 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -7,10 +7,7 @@ import io.lionweb.client.api.RepositoryConfiguration; import io.lionweb.client.delta.messages.events.StandardErrorCode; import io.lionweb.client.inmemory.InMemoryServer; -import io.lionweb.language.Concept; -import io.lionweb.language.Enumeration; -import io.lionweb.language.EnumerationLiteral; -import io.lionweb.language.Language; +import io.lionweb.language.*; import io.lionweb.serialization.JsonSerialization; import io.lionweb.serialization.SerializationProvider; import io.lionweb.utils.ModelComparator; @@ -226,8 +223,7 @@ public void variousOperations() { language1.setName("Enterprise Modeling Language"); // 2. Create enumerations - Enumeration statusEnum = - new Enumeration(language1, "Status", "status-enum").setKey("status"); + Enumeration statusEnum = new Enumeration(language1, "Status", "status-enum").setKey("status"); language1.addElement(statusEnum); EnumerationLiteral activeStatus = @@ -255,45 +251,46 @@ public void variousOperations() { new EnumerationLiteral(priorityEnum, "Low", "low-literal").setKey("low"); priorityEnum.addLiteral(lowPriority); - // // 3. Create interfaces - // Interface namedInterface = new Interface(language1, "Named", "named-interface", - // "named"); - // language1.addElement(namedInterface); - // - // Interface identifiableInterface = new Interface(language1, "Identifiable", - // "identifiable-interface", "identifiable"); - // language1.addElement(identifiableInterface); - // - // Interface auditableInterface = new Interface(language1, "Auditable", - // "auditable-interface", "auditable"); - // language1.addElement(auditableInterface); - // - // Interface timestampedInterface = new Interface(language1, "Timestamped", - // "timestamped-interface", "timestamped"); - // language1.addElement(timestampedInterface); - // - // // 4. Make interfaces extend other interfaces - // auditableInterface.addExtendedInterface(timestampedInterface); - // namedInterface.addExtendedInterface(identifiableInterface); - // - // // 5. Add features to interfaces - // Property nameProperty = new Property(namedInterface, "name", "name-property", "name"); - // nameProperty.setType(PrimitiveType.STRING); - // namedInterface.addFeature(nameProperty); - // - // Property idProperty = new Property(identifiableInterface, "id", "id-property", "id"); - // idProperty.setType(PrimitiveType.STRING); - // identifiableInterface.addFeature(idProperty); - // - // Property createdAtProperty = new Property(timestampedInterface, "createdAt", - // "created-at-property", "createdAt"); - // createdAtProperty.setType(PrimitiveType.STRING); - // timestampedInterface.addFeature(createdAtProperty); - // - // Property modifiedAtProperty = new Property(timestampedInterface, "modifiedAt", - // "modified-at-property", "modifiedAt"); - // modifiedAtProperty.setType(PrimitiveType.STRING); - // timestampedInterface.addFeature(modifiedAtProperty); + // 3. Create interfaces + Interface namedInterface = new Interface(language1, "Named", "named-interface", "named"); + language1.addElement(namedInterface); + + Interface identifiableInterface = + new Interface(language1, "Identifiable", "identifiable-interface", "identifiable"); + language1.addElement(identifiableInterface); + + Interface auditableInterface = + new Interface(language1, "Auditable", "auditable-interface", "auditable"); + language1.addElement(auditableInterface); + + Interface timestampedInterface = + new Interface(language1, "Timestamped", "timestamped-interface", "timestamped"); + language1.addElement(timestampedInterface); + + // 4. Make interfaces extend other interfaces + auditableInterface.addExtendedInterface(timestampedInterface); + namedInterface.addExtendedInterface(identifiableInterface); + + // // 5. Add features to interfaces + // Property nameProperty = new Property(namedInterface, "name", "name-property", + // "name"); + // nameProperty.setType(PrimitiveType.STRING); + // namedInterface.addFeature(nameProperty); + // + // Property idProperty = new Property(identifiableInterface, "id", "id-property", + // "id"); + // idProperty.setType(PrimitiveType.STRING); + // identifiableInterface.addFeature(idProperty); + // + // Property createdAtProperty = new Property(timestampedInterface, "createdAt", + // "created-at-property", "createdAt"); + // createdAtProperty.setType(PrimitiveType.STRING); + // timestampedInterface.addFeature(createdAtProperty); + // + // Property modifiedAtProperty = new Property(timestampedInterface, "modifiedAt", + // "modified-at-property", "modifiedAt"); + // modifiedAtProperty.setType(PrimitiveType.STRING); + // timestampedInterface.addFeature(modifiedAtProperty); // // // 6. Create concepts // Concept personConcept = new Concept(language1, "Person", "person-concept", "person"); diff --git a/core/src/main/java/io/lionweb/language/EnumerationLiteral.java b/core/src/main/java/io/lionweb/language/EnumerationLiteral.java index bd5536d5e..7e67d465b 100644 --- a/core/src/main/java/io/lionweb/language/EnumerationLiteral.java +++ b/core/src/main/java/io/lionweb/language/EnumerationLiteral.java @@ -33,13 +33,14 @@ public EnumerationLiteral( enumeration.addLiteral(this); } - public EnumerationLiteral(@Nonnull Enumeration enumeration, @Nullable String name, @Nonnull String id) { - this(enumeration.getLionWebVersion()); - setID(id); - enumeration.addLiteral(this); - setParent(enumeration); - setName(name); - } + public EnumerationLiteral( + @Nonnull Enumeration enumeration, @Nullable String name, @Nonnull String id) { + this(enumeration.getLionWebVersion()); + setID(id); + enumeration.addLiteral(this); + setParent(enumeration); + setName(name); + } @Override public @Nullable String getName() { diff --git a/core/src/main/java/io/lionweb/language/LanguageEntity.java b/core/src/main/java/io/lionweb/language/LanguageEntity.java index 5fce6fb40..31244df83 100644 --- a/core/src/main/java/io/lionweb/language/LanguageEntity.java +++ b/core/src/main/java/io/lionweb/language/LanguageEntity.java @@ -30,6 +30,7 @@ public LanguageEntity() { public LanguageEntity(@Nullable Language language, @Nullable String name, @Nonnull String id) { this(language == null ? LionWebVersion.currentVersion : language.getLionWebVersion()); this.setID(id); + // TODO enforce uniqueness of the name within the Language this.setName(name); if (language != null) { diff --git a/core/src/main/java/io/lionweb/model/HasFeatureValues.java b/core/src/main/java/io/lionweb/model/HasFeatureValues.java index ef8c382de..a579e5b19 100644 --- a/core/src/main/java/io/lionweb/model/HasFeatureValues.java +++ b/core/src/main/java/io/lionweb/model/HasFeatureValues.java @@ -83,6 +83,9 @@ default void addChild(@Nonnull Containment containment, @Nonnull Node child, int */ int addReferenceValue(@Nonnull Reference reference, @Nullable ReferenceValue referredNode); + int addReferenceValue( + @Nonnull Reference reference, int index, @Nullable ReferenceValue referredNode); + /** * Add the Node to the list of Nodes referred to from this Node under the given Reference, at the * given index. diff --git a/core/src/main/java/io/lionweb/model/impl/ProxyNode.java b/core/src/main/java/io/lionweb/model/impl/ProxyNode.java index c9f556ec7..54261483f 100644 --- a/core/src/main/java/io/lionweb/model/impl/ProxyNode.java +++ b/core/src/main/java/io/lionweb/model/impl/ProxyNode.java @@ -63,6 +63,12 @@ public int addReferenceValue( throw cannotDoBecauseProxy(); } + @Override + public int addReferenceValue( + @Nonnull Reference reference, int index, @Nullable ReferenceValue referredNode) { + throw cannotDoBecauseProxy(); + } + @Nonnull @Override public String getID() { diff --git a/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java b/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java index b5c4a3277..9917fef17 100644 --- a/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java +++ b/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java @@ -60,7 +60,8 @@ public Language importEPackage(EPackage ePackage) { } } else if (eClassifier.eClass().getName().equals(EcorePackage.Literals.EENUM.getName())) { EEnum eEnum = (EEnum) eClassifier; - Enumeration enumeration = new Enumeration(getLionWebVersion(), eEnum.getName()); + Enumeration enumeration = + new Enumeration(getLionWebVersion(), eEnum.getName(), ePackage.getName() + "-" + eEnum.getName()); setIDAndKey(enumeration, ePackage.getName() + "-" + eEnum.getName()); metamodel.addElement(enumeration); entitiesToEElementsMapping.registerMapping(enumeration, eEnum); diff --git a/emf/src/test/java/io/lionweb/emf/EMFMetamodelExporterTest.java b/emf/src/test/java/io/lionweb/emf/EMFMetamodelExporterTest.java index ae21d4bda..d3d82d59d 100644 --- a/emf/src/test/java/io/lionweb/emf/EMFMetamodelExporterTest.java +++ b/emf/src/test/java/io/lionweb/emf/EMFMetamodelExporterTest.java @@ -103,11 +103,11 @@ public void exportLibraryLanguage() { @Test public void exportInterfaceAndEnumeration() { Language simpleLang = new Language("SimpleMM").setKey("simkey").setID("simid"); - Enumeration color = new Enumeration(simpleLang, "Color", "id-1"); - new EnumerationLiteral(color, "red", "id-2"); - new EnumerationLiteral(color, "white", "id-3"); - new EnumerationLiteral(color, "green", "id-4"); - Interface coloredCI = new Interface(simpleLang, "Colored", "id-5"); + Enumeration color = new Enumeration(simpleLang, "Color", "color-id"); + new EnumerationLiteral(color, "red"); + new EnumerationLiteral(color, "white"); + new EnumerationLiteral(color, "green"); + Interface coloredCI = new Interface(simpleLang, "Colored"); coloredCI.addFeature(Property.createRequired("color", color)); EMFMetamodelExporter ecoreExporter = new EMFMetamodelExporter(); From 7c86af4653120a912909952160832055e853d349 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 3 Nov 2025 20:34:48 +0100 Subject: [PATCH 21/30] Restore and update property initialization in `DeltaClientAndServerTest`, reintroducing features with consistent `Property` constructors and modern `LionCoreBuiltins` string type assignment. --- .../delta/DeltaClientAndServerTest.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index fb13d54e9..5bf043c18 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -271,26 +271,25 @@ public void variousOperations() { auditableInterface.addExtendedInterface(timestampedInterface); namedInterface.addExtendedInterface(identifiableInterface); - // // 5. Add features to interfaces - // Property nameProperty = new Property(namedInterface, "name", "name-property", - // "name"); - // nameProperty.setType(PrimitiveType.STRING); - // namedInterface.addFeature(nameProperty); - // - // Property idProperty = new Property(identifiableInterface, "id", "id-property", - // "id"); - // idProperty.setType(PrimitiveType.STRING); - // identifiableInterface.addFeature(idProperty); - // - // Property createdAtProperty = new Property(timestampedInterface, "createdAt", - // "created-at-property", "createdAt"); - // createdAtProperty.setType(PrimitiveType.STRING); - // timestampedInterface.addFeature(createdAtProperty); - // - // Property modifiedAtProperty = new Property(timestampedInterface, "modifiedAt", - // "modified-at-property", "modifiedAt"); - // modifiedAtProperty.setType(PrimitiveType.STRING); - // timestampedInterface.addFeature(modifiedAtProperty); + // 5. Add features to interfaces + Property nameProperty = new Property("name", namedInterface, "name-id"); + nameProperty.setType(LionCoreBuiltins.getString()); + namedInterface.addFeature(nameProperty); + + Property idProperty = new Property("id", identifiableInterface, + "id0d"); + idProperty.setType(LionCoreBuiltins.getString()); + identifiableInterface.addFeature(idProperty); + + Property createdAtProperty = new Property("createdAt", timestampedInterface, + "createdAt-id"); + createdAtProperty.setType(LionCoreBuiltins.getString()); + timestampedInterface.addFeature(createdAtProperty); + + Property modifiedAtProperty = new Property("modifiedAt", timestampedInterface, + "modifiedAt-id"); + modifiedAtProperty.setType(LionCoreBuiltins.getString()); + timestampedInterface.addFeature(modifiedAtProperty); // // // 6. Create concepts // Concept personConcept = new Concept(language1, "Person", "person-concept", "person"); From a18f12263de460343e00eee1699b1dc5813c112d Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 3 Nov 2025 20:41:30 +0100 Subject: [PATCH 22/30] Add constructor overloads with `id` parameter to `Containment` and `Link` classes, refactor containments and properties initialization in `DeltaClientAndServerTest` for consistency and modern type usage. --- .../delta/DeltaClientAndServerTest.java | 145 +++++++++--------- .../main/java/io/lionweb/language/Link.java | 5 + 2 files changed, 76 insertions(+), 74 deletions(-) diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index 5bf043c18..9d6000a3f 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -290,80 +290,77 @@ public void variousOperations() { "modifiedAt-id"); modifiedAtProperty.setType(LionCoreBuiltins.getString()); timestampedInterface.addFeature(modifiedAtProperty); - // - // // 6. Create concepts - // Concept personConcept = new Concept(language1, "Person", "person-concept", "person"); - // language1.addElement(personConcept); - // - // Concept companyConcept = new Concept(language1, "Company", "company-concept", - // "company"); - // language1.addElement(companyConcept); - // - // Concept addressConcept = new Concept(language1, "Address", "address-concept", - // "address"); - // language1.addElement(addressConcept); - // - // Concept baseConcept = new Concept(language1, "BaseEntity", "base-entity-concept", - // "baseEntity"); - // language1.addElement(baseConcept); - // - // // 7. Make concepts implement interfaces - // personConcept.addImplementedInterface(namedInterface); - // personConcept.addImplementedInterface(auditableInterface); - // - // companyConcept.addImplementedInterface(namedInterface); - // companyConcept.addImplementedInterface(identifiableInterface); - // - // addressConcept.addImplementedInterface(timestampedInterface); - // - // baseConcept.addImplementedInterface(identifiableInterface); - // baseConcept.addImplementedInterface(auditableInterface); - // - // // 8. Set up concept inheritance - // personConcept.setExtendedConcept(baseConcept); - // companyConcept.setExtendedConcept(baseConcept); - // - // // 9. Add features to concepts - // Property ageProperty = new Property(personConcept, "age", "age-property", "age"); - // ageProperty.setType(PrimitiveType.INTEGER); - // personConcept.addFeature(ageProperty); - // - // Property emailProperty = new Property(personConcept, "email", "email-property", - // "email"); - // emailProperty.setType(PrimitiveType.STRING); - // personConcept.addFeature(emailProperty); - // - // Property statusProperty = new Property(personConcept, "status", "status-property", - // "status"); - // statusProperty.setType(statusEnum); - // personConcept.addFeature(statusProperty); - // - // Property employeeCountProperty = new Property(companyConcept, "employeeCount", - // "employee-count-property", "employeeCount"); - // employeeCountProperty.setType(PrimitiveType.INTEGER); - // companyConcept.addFeature(employeeCountProperty); - // - // Property streetProperty = new Property(addressConcept, "street", "street-property", - // "street"); - // streetProperty.setType(PrimitiveType.STRING); - // addressConcept.addFeature(streetProperty); - // - // Property cityProperty = new Property(addressConcept, "city", "city-property", "city"); - // cityProperty.setType(PrimitiveType.STRING); - // addressConcept.addFeature(cityProperty); - // - // // 10. Add containment references - // Containment addressesContainment = new Containment(personConcept, "addresses", - // "addresses-containment", "addresses"); - // addressesContainment.setType(addressConcept); - // addressesContainment.setMultiple(true); - // personConcept.addFeature(addressesContainment); - // - // Containment employeesContainment = new Containment(companyConcept, "employees", - // "employees-containment", "employees"); - // employeesContainment.setType(personConcept); - // employeesContainment.setMultiple(true); - // companyConcept.addFeature(employeesContainment); + + // 6. Create concepts + Concept personConcept = new Concept(language1, "Person", "person-concept", "person"); + language1.addElement(personConcept); + + Concept companyConcept = new Concept(language1, "Company", "company-concept", + "company"); + language1.addElement(companyConcept); + + Concept addressConcept = new Concept(language1, "Address", "address-concept", + "address"); + language1.addElement(addressConcept); + + Concept baseConcept = new Concept(language1, "BaseEntity", "base-entity-concept", + "baseEntity"); + language1.addElement(baseConcept); + + // 7. Make concepts implement interfaces + personConcept.addImplementedInterface(namedInterface); + personConcept.addImplementedInterface(auditableInterface); + + companyConcept.addImplementedInterface(namedInterface); + companyConcept.addImplementedInterface(identifiableInterface); + + addressConcept.addImplementedInterface(timestampedInterface); + + baseConcept.addImplementedInterface(identifiableInterface); + baseConcept.addImplementedInterface(auditableInterface); + + // 8. Set up concept inheritance + personConcept.setExtendedConcept(baseConcept); + companyConcept.setExtendedConcept(baseConcept); + + // 9. Add features to concepts + Property ageProperty = new Property( "age", personConcept, "age-id"); + ageProperty.setType(LionCoreBuiltins.getInteger()); + personConcept.addFeature(ageProperty); + + Property emailProperty = new Property( "email", personConcept, "email-id"); + emailProperty.setType(LionCoreBuiltins.getString()); + personConcept.addFeature(emailProperty); + + Property statusProperty = new Property( "status", personConcept, "status-id"); + statusProperty.setType(statusEnum); + personConcept.addFeature(statusProperty); + + Property employeeCountProperty = new Property( "employeeCount", companyConcept, + "employeeCount-id"); + employeeCountProperty.setType(LionCoreBuiltins.getInteger()); + companyConcept.addFeature(employeeCountProperty); + + Property streetProperty = new Property( "street", addressConcept, "street-id"); + streetProperty.setType(LionCoreBuiltins.getString()); + addressConcept.addFeature(streetProperty); + + Property cityProperty = new Property( "city", addressConcept, "city-id"); + cityProperty.setType(LionCoreBuiltins.getString()); + addressConcept.addFeature(cityProperty); + + // 10. Add containment references + Containment addressesContainment = new Containment( "addresses", personConcept, + "addresses-id"); + addressesContainment.setType(addressConcept); + addressesContainment.setMultiple(true); + personConcept.addFeature(addressesContainment); + + Containment employeesContainment = new Containment("employees", companyConcept, + "employees-id"); + employeesContainment.setType(personConcept); + employeesContainment.setMultiple(true); + companyConcept.addFeature(employeesContainment); // // // 11. Add regular references // Reference companyReference = new Reference(personConcept, "employer", diff --git a/core/src/main/java/io/lionweb/language/Link.java b/core/src/main/java/io/lionweb/language/Link.java index 121792514..d0a8c19e6 100644 --- a/core/src/main/java/io/lionweb/language/Link.java +++ b/core/src/main/java/io/lionweb/language/Link.java @@ -44,6 +44,11 @@ public Link(@Nullable String name, @Nullable Classifier container, @Nonnull S setMultiple(false); } + public Link(@Nullable String name, @Nullable Classifier container, @Nonnull String id) { + super(name, container, id); + setMultiple(false); + } + public boolean isMultiple() { return getPropertyValue("multiple", Boolean.class, false); } From 55ade3ece24c8588ccca064563c7df6f84a3d921 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 3 Nov 2025 20:42:25 +0100 Subject: [PATCH 23/30] Add constructor overloads with `id` parameter to `Reference`, refactor tests for consistent property and containment initialization, and reintroduce regular references in `DeltaClientAndServerTest`. --- .../delta/DeltaClientAndServerTest.java | 185 +++++++++--------- .../main/java/io/lionweb/language/Link.java | 8 +- .../java/io/lionweb/language/Reference.java | 4 + 3 files changed, 96 insertions(+), 101 deletions(-) diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index 9d6000a3f..ff74713f8 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -271,103 +271,94 @@ public void variousOperations() { auditableInterface.addExtendedInterface(timestampedInterface); namedInterface.addExtendedInterface(identifiableInterface); - // 5. Add features to interfaces - Property nameProperty = new Property("name", namedInterface, "name-id"); - nameProperty.setType(LionCoreBuiltins.getString()); - namedInterface.addFeature(nameProperty); - - Property idProperty = new Property("id", identifiableInterface, - "id0d"); - idProperty.setType(LionCoreBuiltins.getString()); - identifiableInterface.addFeature(idProperty); - - Property createdAtProperty = new Property("createdAt", timestampedInterface, - "createdAt-id"); - createdAtProperty.setType(LionCoreBuiltins.getString()); - timestampedInterface.addFeature(createdAtProperty); - - Property modifiedAtProperty = new Property("modifiedAt", timestampedInterface, - "modifiedAt-id"); - modifiedAtProperty.setType(LionCoreBuiltins.getString()); - timestampedInterface.addFeature(modifiedAtProperty); - - // 6. Create concepts - Concept personConcept = new Concept(language1, "Person", "person-concept", "person"); - language1.addElement(personConcept); - - Concept companyConcept = new Concept(language1, "Company", "company-concept", - "company"); - language1.addElement(companyConcept); - - Concept addressConcept = new Concept(language1, "Address", "address-concept", - "address"); - language1.addElement(addressConcept); - - Concept baseConcept = new Concept(language1, "BaseEntity", "base-entity-concept", - "baseEntity"); - language1.addElement(baseConcept); - - // 7. Make concepts implement interfaces - personConcept.addImplementedInterface(namedInterface); - personConcept.addImplementedInterface(auditableInterface); - - companyConcept.addImplementedInterface(namedInterface); - companyConcept.addImplementedInterface(identifiableInterface); - - addressConcept.addImplementedInterface(timestampedInterface); - - baseConcept.addImplementedInterface(identifiableInterface); - baseConcept.addImplementedInterface(auditableInterface); - - // 8. Set up concept inheritance - personConcept.setExtendedConcept(baseConcept); - companyConcept.setExtendedConcept(baseConcept); - - // 9. Add features to concepts - Property ageProperty = new Property( "age", personConcept, "age-id"); - ageProperty.setType(LionCoreBuiltins.getInteger()); - personConcept.addFeature(ageProperty); - - Property emailProperty = new Property( "email", personConcept, "email-id"); - emailProperty.setType(LionCoreBuiltins.getString()); - personConcept.addFeature(emailProperty); - - Property statusProperty = new Property( "status", personConcept, "status-id"); - statusProperty.setType(statusEnum); - personConcept.addFeature(statusProperty); - - Property employeeCountProperty = new Property( "employeeCount", companyConcept, - "employeeCount-id"); - employeeCountProperty.setType(LionCoreBuiltins.getInteger()); - companyConcept.addFeature(employeeCountProperty); - - Property streetProperty = new Property( "street", addressConcept, "street-id"); - streetProperty.setType(LionCoreBuiltins.getString()); - addressConcept.addFeature(streetProperty); - - Property cityProperty = new Property( "city", addressConcept, "city-id"); - cityProperty.setType(LionCoreBuiltins.getString()); - addressConcept.addFeature(cityProperty); - - // 10. Add containment references - Containment addressesContainment = new Containment( "addresses", personConcept, - "addresses-id"); - addressesContainment.setType(addressConcept); - addressesContainment.setMultiple(true); - personConcept.addFeature(addressesContainment); - - Containment employeesContainment = new Containment("employees", companyConcept, - "employees-id"); - employeesContainment.setType(personConcept); - employeesContainment.setMultiple(true); - companyConcept.addFeature(employeesContainment); - // - // // 11. Add regular references - // Reference companyReference = new Reference(personConcept, "employer", - // "employer-reference", "employer"); - // companyReference.setType(companyConcept); - // companyReference.setOptional(true); - // personConcept.addFeature(companyReference); + // 5. Add features to interfaces + Property nameProperty = new Property("name", namedInterface, "name-id"); + nameProperty.setType(LionCoreBuiltins.getString()); + namedInterface.addFeature(nameProperty); + + Property idProperty = new Property("id", identifiableInterface, "id0d"); + idProperty.setType(LionCoreBuiltins.getString()); + identifiableInterface.addFeature(idProperty); + + Property createdAtProperty = new Property("createdAt", timestampedInterface, "createdAt-id"); + createdAtProperty.setType(LionCoreBuiltins.getString()); + timestampedInterface.addFeature(createdAtProperty); + + Property modifiedAtProperty = new Property("modifiedAt", timestampedInterface, "modifiedAt-id"); + modifiedAtProperty.setType(LionCoreBuiltins.getString()); + timestampedInterface.addFeature(modifiedAtProperty); + + // 6. Create concepts + Concept personConcept = new Concept(language1, "Person", "person-concept", "person"); + language1.addElement(personConcept); + + Concept companyConcept = new Concept(language1, "Company", "company-concept", "company"); + language1.addElement(companyConcept); + + Concept addressConcept = new Concept(language1, "Address", "address-concept", "address"); + language1.addElement(addressConcept); + + Concept baseConcept = new Concept(language1, "BaseEntity", "base-entity-concept", "baseEntity"); + language1.addElement(baseConcept); + + // 7. Make concepts implement interfaces + personConcept.addImplementedInterface(namedInterface); + personConcept.addImplementedInterface(auditableInterface); + + companyConcept.addImplementedInterface(namedInterface); + companyConcept.addImplementedInterface(identifiableInterface); + + addressConcept.addImplementedInterface(timestampedInterface); + + baseConcept.addImplementedInterface(identifiableInterface); + baseConcept.addImplementedInterface(auditableInterface); + + // 8. Set up concept inheritance + personConcept.setExtendedConcept(baseConcept); + companyConcept.setExtendedConcept(baseConcept); + + // 9. Add features to concepts + Property ageProperty = new Property("age", personConcept, "age-id"); + ageProperty.setType(LionCoreBuiltins.getInteger()); + personConcept.addFeature(ageProperty); + + Property emailProperty = new Property("email", personConcept, "email-id"); + emailProperty.setType(LionCoreBuiltins.getString()); + personConcept.addFeature(emailProperty); + + Property statusProperty = new Property("status", personConcept, "status-id"); + statusProperty.setType(statusEnum); + personConcept.addFeature(statusProperty); + + Property employeeCountProperty = + new Property("employeeCount", companyConcept, "employeeCount-id"); + employeeCountProperty.setType(LionCoreBuiltins.getInteger()); + companyConcept.addFeature(employeeCountProperty); + + Property streetProperty = new Property("street", addressConcept, "street-id"); + streetProperty.setType(LionCoreBuiltins.getString()); + addressConcept.addFeature(streetProperty); + + Property cityProperty = new Property("city", addressConcept, "city-id"); + cityProperty.setType(LionCoreBuiltins.getString()); + addressConcept.addFeature(cityProperty); + + // 10. Add containment references + Containment addressesContainment = new Containment("addresses", personConcept, "addresses-id"); + addressesContainment.setType(addressConcept); + addressesContainment.setMultiple(true); + personConcept.addFeature(addressesContainment); + + Containment employeesContainment = new Containment("employees", companyConcept, "employees-id"); + employeesContainment.setType(personConcept); + employeesContainment.setMultiple(true); + companyConcept.addFeature(employeesContainment); + + // 11. Add regular references + Reference companyReference = new Reference("employer", personConcept, "employer-id"); + companyReference.setType(companyConcept); + companyReference.setOptional(true); + personConcept.addFeature(companyReference); // // // 12. Move features between concepts // personConcept.removeFeature(emailProperty); diff --git a/core/src/main/java/io/lionweb/language/Link.java b/core/src/main/java/io/lionweb/language/Link.java index d0a8c19e6..891495342 100644 --- a/core/src/main/java/io/lionweb/language/Link.java +++ b/core/src/main/java/io/lionweb/language/Link.java @@ -44,10 +44,10 @@ public Link(@Nullable String name, @Nullable Classifier container, @Nonnull S setMultiple(false); } - public Link(@Nullable String name, @Nullable Classifier container, @Nonnull String id) { - super(name, container, id); - setMultiple(false); - } + public Link(@Nullable String name, @Nullable Classifier container, @Nonnull String id) { + super(name, container, id); + setMultiple(false); + } public boolean isMultiple() { return getPropertyValue("multiple", Boolean.class, false); diff --git a/core/src/main/java/io/lionweb/language/Reference.java b/core/src/main/java/io/lionweb/language/Reference.java index 303c8dcf3..984eb2a8a 100644 --- a/core/src/main/java/io/lionweb/language/Reference.java +++ b/core/src/main/java/io/lionweb/language/Reference.java @@ -161,6 +161,10 @@ public Reference(@Nullable String name, @Nullable Classifier container, @Nonn super(name, container, id); } + public Reference(@Nullable String name, @Nullable Classifier container, @Nonnull String id) { + super(name, container, id); + } + public Reference(@Nonnull LionWebVersion lionWebVersion, @Nullable String name) { super(lionWebVersion); setName(name); From df29be661852ce48ceb61e1f5cdc10f173d519b9 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 3 Nov 2025 20:46:22 +0100 Subject: [PATCH 24/30] Refactor tests to streamline `Property` and `Feature` initialization, reintroduce test case comments in `DeltaClientAndServerTest`, and modernize enumeration literal handling with `id` constructor overloads. --- .../delta/DeltaClientAndServerTest.java | 118 +++++++++--------- 1 file changed, 56 insertions(+), 62 deletions(-) diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index ff74713f8..e51fbd0d3 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -359,68 +359,62 @@ public void variousOperations() { companyReference.setType(companyConcept); companyReference.setOptional(true); personConcept.addFeature(companyReference); - // - // // 12. Move features between concepts - // personConcept.removeFeature(emailProperty); - // baseConcept.addFeature(emailProperty); - // - // // 13. Modify feature properties - // ageProperty.setOptional(true); - // statusProperty.setOptional(false); - // employeeCountProperty.setOptional(true); - // - // // 14. Add more enumeration literals - // EnumerationLiteral archivedStatus = new EnumerationLiteral(statusEnum, "Archived", - // "archived-literal", "archived"); - // statusEnum.addLiteral(archivedStatus); - // - // // Remove and re-add enumeration literal - // statusEnum.removeLiteral(pendingStatus); - // EnumerationLiteral reviewingStatus = new EnumerationLiteral(statusEnum, "Reviewing", - // "reviewing-literal", "reviewing"); - // statusEnum.addLiteral(reviewingStatus); - // - // // 15. Modify interface hierarchy - // Interface versionedInterface = new Interface(language1, "Versioned", - // "versioned-interface", "versioned"); - // language1.addElement(versionedInterface); - // - // Property versionProperty = new Property(versionedInterface, "version", - // "version-property", "version"); - // versionProperty.setType(PrimitiveType.INTEGER); - // versionedInterface.addFeature(versionProperty); - // - // auditableInterface.addExtendedInterface(versionedInterface); - // - // // 16. Create abstract concepts - // Concept documentConcept = new Concept(language1, "Document", "document-concept", - // "document"); - // documentConcept.setAbstract(true); - // language1.addElement(documentConcept); - // - // documentConcept.addImplementedInterface(namedInterface); - // documentConcept.addImplementedInterface(versionedInterface); - // - // Concept reportConcept = new Concept(language1, "Report", "report-concept", "report"); - // language1.addElement(reportConcept); - // reportConcept.setExtendedConcept(documentConcept); - // - // Concept contractConcept = new Concept(language1, "Contract", "contract-concept", - // "contract"); - // language1.addElement(contractConcept); - // contractConcept.setExtendedConcept(documentConcept); - // - // // 17. Add features with different cardinalities - // Property tagsProperty = new Property(documentConcept, "tags", "tags-property", - // "tags"); - // tagsProperty.setType(PrimitiveType.STRING); - // tagsProperty.setMultiple(true); - // documentConcept.addFeature(tagsProperty); - // - // Property priorityProperty = new Property(reportConcept, "priority", - // "priority-property", "priority"); - // priorityProperty.setType(priorityEnum); - // reportConcept.addFeature(priorityProperty); + + // 12. Move features between concepts + personConcept.removeFeature(emailProperty); + baseConcept.addFeature(emailProperty); + + // 13. Modify feature properties + ageProperty.setOptional(true); + statusProperty.setOptional(false); + employeeCountProperty.setOptional(true); + + // 14. Add more enumeration literals + EnumerationLiteral archivedStatus = + new EnumerationLiteral(statusEnum, "Archived", "archived-id"); + statusEnum.addLiteral(archivedStatus); + + // Remove and re-add enumeration literal + statusEnum.removeChild(pendingStatus); + EnumerationLiteral reviewingStatus = + new EnumerationLiteral(statusEnum, "Reviewing", "reviewing-id"); + statusEnum.addLiteral(reviewingStatus); + + // 15. Modify interface hierarchy + Interface versionedInterface = + new Interface(language1, "Versioned", "versioned-interface", "versioned"); + language1.addElement(versionedInterface); + + Property versionProperty = new Property("version", versionedInterface, "version-id"); + versionProperty.setType(LionCoreBuiltins.getInteger()); + versionedInterface.addFeature(versionProperty); + + auditableInterface.addExtendedInterface(versionedInterface); + + // 16. Create abstract concepts + Concept documentConcept = new Concept(language1, "Document", "document-concept", "document"); + documentConcept.setAbstract(true); + language1.addElement(documentConcept); + + documentConcept.addImplementedInterface(namedInterface); + documentConcept.addImplementedInterface(versionedInterface); + + Concept reportConcept = new Concept(language1, "Report", "report-concept", "report"); + language1.addElement(reportConcept); + reportConcept.setExtendedConcept(documentConcept); + + Concept contractConcept = new Concept(language1, "Contract", "contract-concept", "contract"); + language1.addElement(contractConcept); + contractConcept.setExtendedConcept(documentConcept); + + // 17. Add features with different cardinalities + Property tagsProperty = new Property("tags", documentConcept, "tags-id"); + tagsProperty.setType(LionCoreBuiltins.getString()); + documentConcept.addFeature(tagsProperty); + + Property priorityProperty = new Property("priority", reportConcept, "priority-id"); + priorityProperty.setType(priorityEnum); + reportConcept.addFeature(priorityProperty); // // // 18. Move features within the same concept (change order) // personConcept.removeFeature(ageProperty); From 424cf690e967c1480bfa8f061baaec7512bf4fd1 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Mon, 3 Nov 2025 20:49:55 +0100 Subject: [PATCH 25/30] Add `setUnavailableReferenceTargetPolicy` in `DeltaClient` initialization and reintroduce commented test cases in `DeltaClientAndServerTest` after updates for improved consistency and readability. --- .../io/lionweb/client/delta/DeltaClient.java | 1 + .../delta/DeltaClientAndServerTest.java | 105 +++++++++--------- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java index 409470b0e..fe1ba9214 100644 --- a/client/src/main/java/io/lionweb/client/delta/DeltaClient.java +++ b/client/src/main/java/io/lionweb/client/delta/DeltaClient.java @@ -53,6 +53,7 @@ public DeltaClient(LionWebVersion lionWebVersion, DeltaChannel channel, String c lionWebVersion); this.serialization = SerializationProvider.getStandardJsonSerialization(lionWebVersion); this.serialization.setUnavailableParentPolicy(UnavailableNodePolicy.PROXY_NODES); + this.serialization.setUnavailableReferenceTargetPolicy(UnavailableNodePolicy.PROXY_NODES); } /** diff --git a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java index e51fbd0d3..1093a3f67 100644 --- a/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java +++ b/client/src/test/java/io/lionweb/client/delta/DeltaClientAndServerTest.java @@ -415,60 +415,57 @@ public void variousOperations() { Property priorityProperty = new Property("priority", reportConcept, "priority-id"); priorityProperty.setType(priorityEnum); reportConcept.addFeature(priorityProperty); - // - // // 18. Move features within the same concept (change order) - // personConcept.removeFeature(ageProperty); - // personConcept.removeFeature(statusProperty); - // personConcept.addFeature(statusProperty); - // personConcept.addFeature(ageProperty); - // - // // 19. Create complex reference relationships - // Reference authorReference = new Reference(documentConcept, "author", - // "author-reference", "author"); - // authorReference.setType(personConcept); - // documentConcept.addFeature(authorReference); - // - // Reference clientReference = new Reference(contractConcept, "client", - // "client-reference", "client"); - // clientReference.setType(companyConcept); - // contractConcept.addFeature(clientReference); - // - // // 20. Modify existing elements - // statusEnum.setName("EntityStatus"); - // priorityEnum.setName("TaskPriority"); - // - // activeStatus.setName("ACTIVE"); - // inactiveStatus.setName("INACTIVE"); - // - // namedInterface.setName("NamedEntity"); - // identifiableInterface.setName("UniqueEntity"); - // - // // 21. Remove and re-add features with modifications - // companyConcept.removeFeature(employeeCountProperty); - // Property staffSizeProperty = new Property(companyConcept, "staffSize", - // "staff-size-property", "staffSize"); - // staffSizeProperty.setType(PrimitiveType.INTEGER); - // staffSizeProperty.setOptional(false); - // companyConcept.addFeature(staffSizeProperty); - // - // // 22. Change concept inheritance - // Concept organizationConcept = new Concept(language1, "Organization", - // "organization-concept", "organization"); - // language1.addElement(organizationConcept); - // organizationConcept.setExtendedConcept(baseConcept); - // organizationConcept.addImplementedInterface(namedInterface); - // - // companyConcept.setExtendedConcept(organizationConcept); - // - // // 23. Add final modifications - // Property descriptionProperty = new Property(organizationConcept, "description", - // "description-property", "description"); - // descriptionProperty.setType(PrimitiveType.STRING); - // descriptionProperty.setOptional(true); - // organizationConcept.addFeature(descriptionProperty); - // - // // 24. Final language name change - // language1.setName("Complete Enterprise Domain Language"); + + // 18. Move features within the same concept (change order) + personConcept.removeFeature(ageProperty); + personConcept.removeFeature(statusProperty); + personConcept.addFeature(statusProperty); + personConcept.addFeature(ageProperty); + + // 19. Create complex reference relationships + Reference authorReference = new Reference("author", documentConcept, "author-id"); + authorReference.setType(personConcept); + documentConcept.addFeature(authorReference); + + Reference clientReference = new Reference("client", contractConcept, "client-id"); + clientReference.setType(companyConcept); + contractConcept.addFeature(clientReference); + + // 20. Modify existing elements + statusEnum.setName("EntityStatus"); + priorityEnum.setName("TaskPriority"); + + activeStatus.setName("ACTIVE"); + inactiveStatus.setName("INACTIVE"); + + namedInterface.setName("NamedEntity"); + identifiableInterface.setName("UniqueEntity"); + + // 21. Remove and re-add features with modifications + companyConcept.removeFeature(employeeCountProperty); + Property staffSizeProperty = new Property("staffSize", companyConcept, "staffSize-id"); + staffSizeProperty.setType(LionCoreBuiltins.getInteger()); + staffSizeProperty.setOptional(false); + companyConcept.addFeature(staffSizeProperty); + + // 22. Change concept inheritance + Concept organizationConcept = + new Concept(language1, "Organization", "organization-concept", "organization"); + language1.addElement(organizationConcept); + organizationConcept.setExtendedConcept(baseConcept); + organizationConcept.addImplementedInterface(namedInterface); + + companyConcept.setExtendedConcept(organizationConcept); + + // 23. Add final modifications + Property descriptionProperty = + new Property("description", organizationConcept, "description-id"); + descriptionProperty.setType(LionCoreBuiltins.getString()); + descriptionProperty.setOptional(true); + organizationConcept.addFeature(descriptionProperty); + + // 24. Final language name change + language1.setName("Complete Enterprise Domain Language"); assertEquals(language1, language2); } From 07f21d801fd118beb9569dd09e0183c56c9d651a Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sat, 8 Nov 2025 09:00:11 +0100 Subject: [PATCH 26/30] Remove unused constructor overloads in core language model classes (`Reference`, `Link`, `EnumerationLiteral`, `DataType`, etc.) and clean up related initialization logic for improved maintainability. --- core/src/main/java/io/lionweb/language/DataType.java | 4 ---- .../java/io/lionweb/language/EnumerationLiteral.java | 9 --------- .../main/java/io/lionweb/language/LanguageEntity.java | 1 - core/src/main/java/io/lionweb/language/Link.java | 5 ----- core/src/main/java/io/lionweb/language/Reference.java | 4 ---- .../main/java/io/lionweb/emf/EMFMetamodelImporter.java | 3 ++- 6 files changed, 2 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/io/lionweb/language/DataType.java b/core/src/main/java/io/lionweb/language/DataType.java index 1290912b6..040676b31 100644 --- a/core/src/main/java/io/lionweb/language/DataType.java +++ b/core/src/main/java/io/lionweb/language/DataType.java @@ -38,8 +38,4 @@ public DataType(@Nonnull String id) { public DataType(@Nullable Language language, @Nullable String name, @Nonnull String id) { super(language, name, id); } - - public DataType(@Nullable Language language, @Nullable String name, @Nonnull String id) { - super(language, name, id); - } } diff --git a/core/src/main/java/io/lionweb/language/EnumerationLiteral.java b/core/src/main/java/io/lionweb/language/EnumerationLiteral.java index 7e67d465b..6e506c822 100644 --- a/core/src/main/java/io/lionweb/language/EnumerationLiteral.java +++ b/core/src/main/java/io/lionweb/language/EnumerationLiteral.java @@ -33,15 +33,6 @@ public EnumerationLiteral( enumeration.addLiteral(this); } - public EnumerationLiteral( - @Nonnull Enumeration enumeration, @Nullable String name, @Nonnull String id) { - this(enumeration.getLionWebVersion()); - setID(id); - enumeration.addLiteral(this); - setParent(enumeration); - setName(name); - } - @Override public @Nullable String getName() { return getPropertyValue("name", String.class); diff --git a/core/src/main/java/io/lionweb/language/LanguageEntity.java b/core/src/main/java/io/lionweb/language/LanguageEntity.java index 31244df83..5fce6fb40 100644 --- a/core/src/main/java/io/lionweb/language/LanguageEntity.java +++ b/core/src/main/java/io/lionweb/language/LanguageEntity.java @@ -30,7 +30,6 @@ public LanguageEntity() { public LanguageEntity(@Nullable Language language, @Nullable String name, @Nonnull String id) { this(language == null ? LionWebVersion.currentVersion : language.getLionWebVersion()); this.setID(id); - // TODO enforce uniqueness of the name within the Language this.setName(name); if (language != null) { diff --git a/core/src/main/java/io/lionweb/language/Link.java b/core/src/main/java/io/lionweb/language/Link.java index 891495342..121792514 100644 --- a/core/src/main/java/io/lionweb/language/Link.java +++ b/core/src/main/java/io/lionweb/language/Link.java @@ -44,11 +44,6 @@ public Link(@Nullable String name, @Nullable Classifier container, @Nonnull S setMultiple(false); } - public Link(@Nullable String name, @Nullable Classifier container, @Nonnull String id) { - super(name, container, id); - setMultiple(false); - } - public boolean isMultiple() { return getPropertyValue("multiple", Boolean.class, false); } diff --git a/core/src/main/java/io/lionweb/language/Reference.java b/core/src/main/java/io/lionweb/language/Reference.java index 984eb2a8a..303c8dcf3 100644 --- a/core/src/main/java/io/lionweb/language/Reference.java +++ b/core/src/main/java/io/lionweb/language/Reference.java @@ -161,10 +161,6 @@ public Reference(@Nullable String name, @Nullable Classifier container, @Nonn super(name, container, id); } - public Reference(@Nullable String name, @Nullable Classifier container, @Nonnull String id) { - super(name, container, id); - } - public Reference(@Nonnull LionWebVersion lionWebVersion, @Nullable String name) { super(lionWebVersion); setName(name); diff --git a/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java b/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java index 9917fef17..dc18cacac 100644 --- a/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java +++ b/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java @@ -61,7 +61,8 @@ public Language importEPackage(EPackage ePackage) { } else if (eClassifier.eClass().getName().equals(EcorePackage.Literals.EENUM.getName())) { EEnum eEnum = (EEnum) eClassifier; Enumeration enumeration = - new Enumeration(getLionWebVersion(), eEnum.getName(), ePackage.getName() + "-" + eEnum.getName()); + new Enumeration( + getLionWebVersion(), eEnum.getName(), ePackage.getName() + "-" + eEnum.getName()); setIDAndKey(enumeration, ePackage.getName() + "-" + eEnum.getName()); metamodel.addElement(enumeration); entitiesToEElementsMapping.registerMapping(enumeration, eEnum); From a9cd8f00db49adc279ffa13dc3c1f2106e726b77 Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sat, 8 Nov 2025 09:00:59 +0100 Subject: [PATCH 27/30] Refactor `Enumeration` and `EnumerationLiteral` initialization to use `id` constructor overloads, streamline metamodel and test setup for improved consistency. --- .../main/java/io/lionweb/emf/EMFMetamodelImporter.java | 4 +--- .../java/io/lionweb/emf/EMFMetamodelExporterTest.java | 10 +++++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java b/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java index dc18cacac..b5c4a3277 100644 --- a/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java +++ b/emf/src/main/java/io/lionweb/emf/EMFMetamodelImporter.java @@ -60,9 +60,7 @@ public Language importEPackage(EPackage ePackage) { } } else if (eClassifier.eClass().getName().equals(EcorePackage.Literals.EENUM.getName())) { EEnum eEnum = (EEnum) eClassifier; - Enumeration enumeration = - new Enumeration( - getLionWebVersion(), eEnum.getName(), ePackage.getName() + "-" + eEnum.getName()); + Enumeration enumeration = new Enumeration(getLionWebVersion(), eEnum.getName()); setIDAndKey(enumeration, ePackage.getName() + "-" + eEnum.getName()); metamodel.addElement(enumeration); entitiesToEElementsMapping.registerMapping(enumeration, eEnum); diff --git a/emf/src/test/java/io/lionweb/emf/EMFMetamodelExporterTest.java b/emf/src/test/java/io/lionweb/emf/EMFMetamodelExporterTest.java index d3d82d59d..ae21d4bda 100644 --- a/emf/src/test/java/io/lionweb/emf/EMFMetamodelExporterTest.java +++ b/emf/src/test/java/io/lionweb/emf/EMFMetamodelExporterTest.java @@ -103,11 +103,11 @@ public void exportLibraryLanguage() { @Test public void exportInterfaceAndEnumeration() { Language simpleLang = new Language("SimpleMM").setKey("simkey").setID("simid"); - Enumeration color = new Enumeration(simpleLang, "Color", "color-id"); - new EnumerationLiteral(color, "red"); - new EnumerationLiteral(color, "white"); - new EnumerationLiteral(color, "green"); - Interface coloredCI = new Interface(simpleLang, "Colored"); + Enumeration color = new Enumeration(simpleLang, "Color", "id-1"); + new EnumerationLiteral(color, "red", "id-2"); + new EnumerationLiteral(color, "white", "id-3"); + new EnumerationLiteral(color, "green", "id-4"); + Interface coloredCI = new Interface(simpleLang, "Colored", "id-5"); coloredCI.addFeature(Property.createRequired("color", color)); EMFMetamodelExporter ecoreExporter = new EMFMetamodelExporter(); From 8ee23391142db09e23e2b32de123222660d6b44f Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sat, 8 Nov 2025 17:47:19 +0100 Subject: [PATCH 28/30] Remove unused default method `addChild` and redundant `addReferenceValue` declaration in `HasFeatureValues` to simplify interface and improve clarity. --- core/src/main/java/io/lionweb/model/HasFeatureValues.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/core/src/main/java/io/lionweb/model/HasFeatureValues.java b/core/src/main/java/io/lionweb/model/HasFeatureValues.java index a579e5b19..072d6c52c 100644 --- a/core/src/main/java/io/lionweb/model/HasFeatureValues.java +++ b/core/src/main/java/io/lionweb/model/HasFeatureValues.java @@ -35,10 +35,6 @@ void setPropertyValue(@Nonnull Property property, @Nullable Object value) */ void addChild(@Nonnull Containment containment, @Nonnull Node child); - default void addChild(@Nonnull Containment containment, @Nonnull Node child, int index) { - throw new UnsupportedOperationException("Not supported yet."); - } - /** * Add a child to the specified list of children associated with the given Containment relation, * at the given index. If the specified Containment does not allow for multiple values, and if a @@ -83,9 +79,6 @@ default void addChild(@Nonnull Containment containment, @Nonnull Node child, int */ int addReferenceValue(@Nonnull Reference reference, @Nullable ReferenceValue referredNode); - int addReferenceValue( - @Nonnull Reference reference, int index, @Nullable ReferenceValue referredNode); - /** * Add the Node to the list of Nodes referred to from this Node under the given Reference, at the * given index. From a3fbf4f52282fe82ce7013400b74645bc658c8fe Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sun, 9 Nov 2025 11:20:42 +0100 Subject: [PATCH 29/30] Formatting --- core/src/main/java/io/lionweb/model/impl/ProxyNode.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/src/main/java/io/lionweb/model/impl/ProxyNode.java b/core/src/main/java/io/lionweb/model/impl/ProxyNode.java index 54261483f..6e959abce 100644 --- a/core/src/main/java/io/lionweb/model/impl/ProxyNode.java +++ b/core/src/main/java/io/lionweb/model/impl/ProxyNode.java @@ -180,10 +180,4 @@ public void partitionObserverRegistered(@Nonnull PartitionObserver observer) { public void addChild(@Nonnull Containment containment, @Nonnull Node child, int index) { throw cannotDoBecauseProxy(); } - - @Override - public int addReferenceValue( - @Nonnull Reference reference, int index, @Nullable ReferenceValue referredNode) { - throw cannotDoBecauseProxy(); - } } From fbddd8eb729046ae6a010b108b5e459d33a2ef1f Mon Sep 17 00:00:00 2001 From: ftomassetti Date: Sun, 9 Nov 2025 11:23:59 +0100 Subject: [PATCH 30/30] Restore ProxyNode from main --- .../main/java/io/lionweb/model/impl/ProxyNode.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/io/lionweb/model/impl/ProxyNode.java b/core/src/main/java/io/lionweb/model/impl/ProxyNode.java index 6e959abce..c9f556ec7 100644 --- a/core/src/main/java/io/lionweb/model/impl/ProxyNode.java +++ b/core/src/main/java/io/lionweb/model/impl/ProxyNode.java @@ -63,12 +63,6 @@ public int addReferenceValue( throw cannotDoBecauseProxy(); } - @Override - public int addReferenceValue( - @Nonnull Reference reference, int index, @Nullable ReferenceValue referredNode) { - throw cannotDoBecauseProxy(); - } - @Nonnull @Override public String getID() { @@ -180,4 +174,10 @@ public void partitionObserverRegistered(@Nonnull PartitionObserver observer) { public void addChild(@Nonnull Containment containment, @Nonnull Node child, int index) { throw cannotDoBecauseProxy(); } + + @Override + public int addReferenceValue( + @Nonnull Reference reference, int index, @Nullable ReferenceValue referredNode) { + throw cannotDoBecauseProxy(); + } }