From 092a88e9fb2aae703816cc3004797110c32c5e11 Mon Sep 17 00:00:00 2001 From: Daniel Busche Date: Fri, 3 Jan 2025 11:32:06 +0100 Subject: [PATCH 1/2] Ticket #28304: Added test for incremental update of abstract. --- .../model/diff/TestOverrideAttributes.java | 23 ++++++++++++ .../diff/test-make-abstract-left.model.xml | 28 +++++++++++++++ .../diff/test-make-abstract-right.model.xml | 35 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/test-make-abstract-left.model.xml create mode 100644 com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/test-make-abstract-right.model.xml diff --git a/com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/TestOverrideAttributes.java b/com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/TestOverrideAttributes.java index e8888576a8..f444568db0 100644 --- a/com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/TestOverrideAttributes.java +++ b/com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/TestOverrideAttributes.java @@ -61,6 +61,29 @@ public void testOverrideAbstract() { assertFalse("Attribute override is not declared as 'abstract'.", ext2.getPartOrFail("b").isAbstract()); } + public void testMakeAttributeAbstract() { + TLModel model; + try (Transaction tx = kb().beginTransaction()) { + model = loadModel("test-make-abstract-left.model.xml"); + tx.commit(); + } + TLClass baseA = (TLClass) model.getModule("m0").getType("A"); + TLClass baseB = (TLClass) model.getModule("m0").getType("B"); + assertFalse(baseA.getPartOrFail("a").isAbstract()); + assertFalse(baseB.getPartOrFail("a").isAbstract()); + + TLModel newModel = loadModelTransient("test-make-abstract-right.model.xml"); + try (Transaction tx = kb().beginTransaction()) { + applyDiff(model, newModel); + tx.commit(); + } + + TLClass incrementedA = (TLClass) model.getModule("m0").getType("A"); + TLClass incrementedB = (TLClass) model.getModule("m0").getType("B"); + assertTrue(incrementedA.getPartOrFail("a").isAbstract()); + assertFalse(incrementedB.getPartOrFail("a").isAbstract()); + } + public static Test suite() { return KBSetup.getSingleKBTest(TestOverrideAttributes.class); } diff --git a/com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/test-make-abstract-left.model.xml b/com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/test-make-abstract-left.model.xml new file mode 100644 index 0000000000..c498767bb8 --- /dev/null +++ b/com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/test-make-abstract-left.model.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/test-make-abstract-right.model.xml b/com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/test-make-abstract-right.model.xml new file mode 100644 index 0000000000..9f530bfc41 --- /dev/null +++ b/com.top_logic.element/src/test/java/test/com/top_logic/element/model/diff/test-make-abstract-right.model.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From f564377905ff7e130a92b7551f2ff9fea34f567e Mon Sep 17 00:00:00 2001 From: Daniel Busche Date: Wed, 9 Oct 2024 15:06:21 +0200 Subject: [PATCH 2/2] Ticket #28304: Ensure that abstract property can be changed incremental. --- .../main/java/META-INF/messages_de.properties | 4 ++ .../main/java/META-INF/messages_en.properties | 4 ++ .../model/diff/apply/ApplyModelPatch.java | 46 +++++++++++++++++++ .../element/model/diff/apply/Priority.java | 5 ++ .../model/diff/compare/CreateModelPatch.java | 9 ++++ .../model/diff/config/UpdateAbstract.java | 29 ++++++++++++ .../model/diff/config/visit/DiffVisitor.java | 4 ++ 7 files changed, 101 insertions(+) create mode 100644 com.top_logic.element/src/main/java/com/top_logic/element/model/diff/config/UpdateAbstract.java diff --git a/com.top_logic.element/src/main/java/META-INF/messages_de.properties b/com.top_logic.element/src/main/java/META-INF/messages_de.properties index ef4d9deb7b..50a19ed385 100644 --- a/com.top_logic.element/src/main/java/META-INF/messages_de.properties +++ b/com.top_logic.element/src/main/java/META-INF/messages_de.properties @@ -1480,6 +1480,10 @@ com.top_logic.element.model.diff.config.RenamePart.part.tooltip = Der qualifizie com.top_logic.element.model.diff.config.RenamePart.tooltip = Umbenennung eines Modellteils. com.top_logic.element.model.diff.config.SetAnnotations = Annotationen festlegen com.top_logic.element.model.diff.config.SetAnnotations.tooltip = Beschreibt die Einstellung von Annotationen zu einem Modellteil. +com.top_logic.element.model.diff.config.UpdateAbstract = Update abstrakt +com.top_logic.element.model.diff.config.UpdateAbstract.abstract = Abstrakt +com.top_logic.element.model.diff.config.UpdateAbstract.abstract.tooltip = Der neue abstrakte Zustand. +com.top_logic.element.model.diff.config.UpdateAbstract.tooltip = Aktualisierung des Zustands abstract eines strukturierten Teils. com.top_logic.element.model.diff.config.UpdateBag = Update Tasche com.top_logic.element.model.diff.config.UpdateBag.bag = Tasche com.top_logic.element.model.diff.config.UpdateBag.bag.tooltip = Der neue Taschenzustand. diff --git a/com.top_logic.element/src/main/java/META-INF/messages_en.properties b/com.top_logic.element/src/main/java/META-INF/messages_en.properties index 27bb335322..0f8183b233 100644 --- a/com.top_logic.element/src/main/java/META-INF/messages_en.properties +++ b/com.top_logic.element/src/main/java/META-INF/messages_en.properties @@ -1480,6 +1480,10 @@ com.top_logic.element.model.diff.config.RenamePart.part.tooltip = The qualified com.top_logic.element.model.diff.config.RenamePart.tooltip = Renaming of a model part. com.top_logic.element.model.diff.config.SetAnnotations = Set annotations com.top_logic.element.model.diff.config.SetAnnotations.tooltip = Describes the setting of annotations to a model part. +com.top_logic.element.model.diff.config.UpdateAbstract = Update abstract +com.top_logic.element.model.diff.config.UpdateAbstract.abstract = Abstract +com.top_logic.element.model.diff.config.UpdateAbstract.abstract.tooltip = The new abstract state. +com.top_logic.element.model.diff.config.UpdateAbstract.tooltip = Update of the abstract state of a structured type part. com.top_logic.element.model.diff.config.UpdateBag = Update bag com.top_logic.element.model.diff.config.UpdateBag.bag = Bag com.top_logic.element.model.diff.config.UpdateBag.bag.tooltip = The new bag state. diff --git a/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/apply/ApplyModelPatch.java b/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/apply/ApplyModelPatch.java index e29e3ef0b5..604c8ad6e5 100644 --- a/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/apply/ApplyModelPatch.java +++ b/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/apply/ApplyModelPatch.java @@ -61,6 +61,7 @@ import com.top_logic.element.model.diff.config.RemoveGeneralization; import com.top_logic.element.model.diff.config.RenamePart; import com.top_logic.element.model.diff.config.SetAnnotations; +import com.top_logic.element.model.diff.config.UpdateAbstract; import com.top_logic.element.model.diff.config.UpdateBag; import com.top_logic.element.model.diff.config.UpdateMandatory; import com.top_logic.element.model.diff.config.UpdateMultiplicity; @@ -304,6 +305,11 @@ public Priority visit(UpdateOrdered diff, Void arg) throws RuntimeException { return Priority.CHANGE_TYPE_PART_ORDERED; } + @Override + public Priority visit(UpdateAbstract diff, Void arg) throws RuntimeException { + return Priority.CHANGE_TYPE_PART_ABSTRACT; + } + @Override public Priority visit(UpdateBag diff, Void arg) throws RuntimeException { return Priority.CHANGE_TYPE_PART_BAG; @@ -1488,6 +1494,46 @@ public Void visit(UpdateBag diff, Void arg) throws RuntimeException { return null; } + @Override + public Void visit(UpdateAbstract diff, Void arg) throws RuntimeException { + TLStructuredTypePart part; + try { + part = (TLStructuredTypePart) resolveQName(diff.getPart()); + } catch (TopLogicException ex) { + log().info( + "Merge conflict: Updating abstract state of '" + diff.getPart() + "' to '" + diff.isAbstract() + + "', but part does not exist.", + Log.WARN); + return null; + } + log().info("Updating abstract state of '" + diff.getPart() + "' to '" + diff.isAbstract() + "'."); + part.setAbstract(diff.isAbstract()); + + if (createProcessors()) { + if (part instanceof TLProperty) { + UpdateTLPropertyProcessor.Config config = newConfigItem(UpdateTLPropertyProcessor.Config.class); + config.setName(qTypePartName(diff.getPart())); + config.setAbstract(diff.isAbstract()); + addProcessor(config); + } else if (part instanceof TLReference) { + UpdateTLReferenceProcessor.Config config = newConfigItem(UpdateTLReferenceProcessor.Config.class); + config.setName(qTypePartName(diff.getPart())); + config.setAbstract(diff.isAbstract()); + addProcessor(config); + } else if (part instanceof TLAssociationEnd) { + UpdateTLAssociationEndProcessor.Config config = + newConfigItem(UpdateTLAssociationEndProcessor.Config.class); + config.setName(qTypePartName(diff.getPart())); + config.setAbstract(diff.isAbstract()); + addProcessor(config); + } else { + throw new UnsupportedOperationException("No update for '" + diff.getPart() + "' of type '" + + part.getClass().getName() + "' possible."); + } + } + return null; + } + @Override public Void visit(MoveClassifier diff, Void arg) throws RuntimeException { TLClassifier moved; diff --git a/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/apply/Priority.java b/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/apply/Priority.java index 09904ff614..8940c6fa70 100644 --- a/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/apply/Priority.java +++ b/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/apply/Priority.java @@ -146,6 +146,11 @@ enum Priority { */ UPDATE_TYPE_PART_TYPE, + /** + * Change of {@link TLStructuredTypePart#isAbstract()}. + */ + CHANGE_TYPE_PART_ABSTRACT, + /** * Change of {@link TLStructuredTypePart#isMandatory()}. */ diff --git a/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/compare/CreateModelPatch.java b/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/compare/CreateModelPatch.java index b12ecd9b04..28552ec619 100644 --- a/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/compare/CreateModelPatch.java +++ b/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/compare/CreateModelPatch.java @@ -46,6 +46,7 @@ import com.top_logic.element.model.diff.config.MoveStructuredTypePart; import com.top_logic.element.model.diff.config.RemoveAnnotation; import com.top_logic.element.model.diff.config.RemoveGeneralization; +import com.top_logic.element.model.diff.config.UpdateAbstract; import com.top_logic.element.model.diff.config.RenamePart; import com.top_logic.element.model.diff.config.UpdateBag; import com.top_logic.element.model.diff.config.UpdateMandatory; @@ -662,6 +663,14 @@ private void addPartChanges(TLStructuredTypePart left, TLStructuredTypePart righ update.setMandatory(newMandatory); addDiff(update); } + boolean oldAbstract = left.isAbstract(); + boolean newAbstract = right.isAbstract(); + if (oldAbstract != newAbstract) { + UpdateAbstract update = TypedConfiguration.newConfigItem(UpdateAbstract.class); + update.setPart(TLModelUtil.qualifiedName(left)); + update.setAbstract(newAbstract); + addDiff(update); + } } private boolean isEquivalent(TLType left, TLType right) { diff --git a/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/config/UpdateAbstract.java b/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/config/UpdateAbstract.java new file mode 100644 index 0000000000..d2878ed27c --- /dev/null +++ b/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/config/UpdateAbstract.java @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2024 (c) Business Operation Systems GmbH + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-BOS-TopLogic-1.0 + */ +package com.top_logic.element.model.diff.config; + +import com.top_logic.basic.config.annotation.Label; +import com.top_logic.basic.config.annotation.TagName; +import com.top_logic.model.TLStructuredTypePart; + +/** + * Update of the abstract state of a {@link TLStructuredTypePart}. + * + * @author Daniel Busche + */ +@TagName("update-abstract") +@Label("Update abstract") +public interface UpdateAbstract extends PartUpdate { + + /** + * The new {@link TLStructuredTypePart#isAbstract() abstract} state. + */ + boolean isAbstract(); + + /** @see #isAbstract() */ + void setAbstract(boolean value); + +} diff --git a/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/config/visit/DiffVisitor.java b/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/config/visit/DiffVisitor.java index 81f531d74a..2bb39f0d42 100644 --- a/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/config/visit/DiffVisitor.java +++ b/com.top_logic.element/src/main/java/com/top_logic/element/model/diff/config/visit/DiffVisitor.java @@ -26,6 +26,7 @@ import com.top_logic.element.model.diff.config.RenamePart; import com.top_logic.element.model.diff.config.SetAnnotations; import com.top_logic.element.model.diff.config.UpdateBag; +import com.top_logic.element.model.diff.config.UpdateAbstract; import com.top_logic.element.model.diff.config.UpdateMandatory; import com.top_logic.element.model.diff.config.UpdateMultiplicity; import com.top_logic.element.model.diff.config.UpdateOrdered; @@ -104,6 +105,9 @@ public interface DiffVisitor { /** Visit case for {@link UpdateBag}. */ R visit(UpdateBag diff, A arg) throws E; + /** Visit case for {@link UpdateAbstract}. */ + R visit(UpdateAbstract diff, A arg) throws E; + /** Visit case for {@link MoveClassifier}. */ R visit(MoveClassifier diff, A arg) throws E;