Rollback of automation composition migration/update 10/141110/3
authoradheli.tavares <adheli.tavares@est.tech>
Thu, 5 Jun 2025 10:49:47 +0000 (11:49 +0100)
committeradheli.tavares <adheli.tavares@est.tech>
Fri, 6 Jun 2025 09:22:55 +0000 (10:22 +0100)
- copy of ac + elements to rollback table

Issue-ID: POLICY-5362
Change-Id: I1df199d3a4daa7110b5d0b69044f1ad91797516a
Signed-off-by: adheli.tavares <adheli.tavares@est.tech>
models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationCompositionDefinition.java
models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationCompositionRollback.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionDefinition.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProvider.java
models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionRollbackTest.java
models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProviderTest.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProvider.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
runtime-acm/src/main/resources/openapi/openapi.yaml

index 57b6837..0fee98b 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022-2024 Nordix Foundation.
+ *  Copyright (C) 2022-2025 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ public class AutomationCompositionDefinition {
     private Map<String, NodeTemplateState> elementStateMap = new HashMap<>();
 
     /**
-     * Copy contructor, does a deep copy.
+     * Copy constructor, does a deep copy.
      *
      * @param otherAcmDefinition the other element to copy from
      */
index 730a08d..3d62f91 100644 (file)
@@ -27,7 +27,6 @@ import java.util.function.UnaryOperator;
 import lombok.Data;\r
 import lombok.NoArgsConstructor;\r
 import lombok.NonNull;\r
-import lombok.ToString;\r
 import org.onap.policy.models.base.PfUtils;\r
 \r
 @NoArgsConstructor\r
@@ -53,4 +52,19 @@ public class AutomationCompositionRollback {
         this.compositionId = otherAcmRollback.compositionId;\r
         this.elements = PfUtils.mapMap(otherAcmRollback.elements, UnaryOperator.identity());\r
     }\r
+\r
+    /**\r
+     * Create a copy from an automation composition.\r
+     *\r
+     * @param automationComposition the composition being migrated that needs a copy\r
+     */\r
+    public AutomationCompositionRollback(final AutomationComposition automationComposition) {\r
+        this.instanceId = automationComposition.getInstanceId();\r
+        this.compositionId = automationComposition.getCompositionId();\r
+        var originalElements = automationComposition.getElements();\r
+\r
+        this.elements = new LinkedHashMap<>();\r
+        originalElements.forEach((uuid, element) ->\r
+            this.elements.put(uuid.toString(), element));\r
+    }\r
 }\r
index 02ec19a..cbf21e6 100644 (file)
@@ -53,7 +53,7 @@ import org.onap.policy.models.base.PfKey;
 import org.onap.policy.models.base.Validated;
 
 /**
- * Class to represent a automation composition definition in the database.
+ * Class to represent an automation composition definition in the database.
  */
 @Entity
 @Table(name = "AutomationCompositionDefinition")
index 287ae51..5d2c4f2 100644 (file)
@@ -33,12 +33,15 @@ import lombok.AllArgsConstructor;
 import lombok.NonNull;
 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionRollback;
 import org.onap.policy.clamp.models.acm.concepts.DeployState;
 import org.onap.policy.clamp.models.acm.concepts.LockState;
 import org.onap.policy.clamp.models.acm.concepts.SubState;
 import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationComposition;
+import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionRollback;
 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionElementRepository;
 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRepository;
+import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRollbackRepository;
 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
 import org.onap.policy.common.parameters.BeanValidationResult;
 import org.onap.policy.common.parameters.ValidationStatus;
@@ -60,6 +63,7 @@ public class AutomationCompositionProvider {
 
     private final AutomationCompositionRepository automationCompositionRepository;
     private final AutomationCompositionElementRepository acElementRepository;
+    private final AutomationCompositionRollbackRepository acRollbackRepository;
 
     /**
      * Get automation composition.
@@ -96,23 +100,23 @@ public class AutomationCompositionProvider {
      */
     @Transactional(readOnly = true)
     public Optional<AutomationComposition> findAutomationComposition(
-            final ToscaConceptIdentifier automationCompositionId) {
+        final ToscaConceptIdentifier automationCompositionId) {
         return automationCompositionRepository
-                .findOne(createExample(null, automationCompositionId.getName(), automationCompositionId.getVersion()))
-                .map(JpaAutomationComposition::toAuthorative);
+            .findOne(createExample(null, automationCompositionId.getName(), automationCompositionId.getVersion()))
+            .map(JpaAutomationComposition::toAuthorative);
     }
 
     /**
      * Create automation composition.
      *
      * @param automationComposition the automation composition to create
-     * @return the create automation composition
+     * @return the created automation composition
      */
     public AutomationComposition createAutomationComposition(final AutomationComposition automationComposition) {
         automationComposition.setInstanceId(UUID.randomUUID());
         AcmUtils.setCascadedState(automationComposition, DeployState.UNDEPLOYED, LockState.NONE);
         var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition,
-                JpaAutomationComposition::new, "automation composition"));
+            JpaAutomationComposition::new, "automation composition"));
 
         // Return the saved automation composition
         return result.toAuthorative();
@@ -125,9 +129,9 @@ public class AutomationCompositionProvider {
      * @return the updated automation composition
      */
     public AutomationComposition updateAutomationComposition(
-            @NonNull final AutomationComposition automationComposition) {
+        @NonNull final AutomationComposition automationComposition) {
         var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition,
-                JpaAutomationComposition::new, "automation composition"));
+            JpaAutomationComposition::new, "automation composition"));
         automationCompositionRepository.flush();
         // Return the saved automation composition
         return result.toAuthorative();
@@ -142,11 +146,11 @@ public class AutomationCompositionProvider {
     @Transactional(readOnly = true)
     public List<AutomationComposition> getAcInstancesByCompositionId(UUID compositionId) {
         return ProviderUtils
-                .asEntityList(automationCompositionRepository.findByCompositionId(compositionId.toString()));
+            .asEntityList(automationCompositionRepository.findByCompositionId(compositionId.toString()));
     }
 
     /**
-     * Get all automation compositions in transition..
+     * Get all automation compositions in transition.
      *
      * @return all automation compositions found
      */
@@ -157,28 +161,29 @@ public class AutomationCompositionProvider {
         jpaList.addAll(automationCompositionRepository.findByLockStateIn(
             List.of(LockState.LOCKING, LockState.UNLOCKING)));
         jpaList.addAll(automationCompositionRepository.findBySubStateIn(
-                List.of(SubState.PREPARING, SubState.MIGRATION_PRECHECKING, SubState.REVIEWING)));
+            List.of(SubState.PREPARING, SubState.MIGRATION_PRECHECKING, SubState.REVIEWING)));
         return jpaList.stream().map(JpaAutomationComposition::getInstanceId)
-                .map(UUID::fromString).collect(Collectors.toSet());
+            .map(UUID::fromString).collect(Collectors.toSet());
     }
 
     /**
      * Get automation compositions.
      *
-     * @param name the name of the automation composition to get, null to get all automation compositions
-     * @param version the version of the automation composition to get, null to get all automation compositions
+     * @param name     the name of the automation composition to get, null to get all automation compositions
+     * @param version  the version of the automation composition to get, null to get all automation compositions
      * @param pageable the Pageable
      * @return the automation compositions found
      */
     @Transactional(readOnly = true)
     public List<AutomationComposition> getAutomationCompositions(@NonNull final UUID compositionId, final String name,
-            final String version, @NonNull final Pageable pageable) {
+                                                                 final String version,
+                                                                 @NonNull final Pageable pageable) {
         return ProviderUtils.asEntityList(automationCompositionRepository
-                .findAll(createExample(compositionId, name, version), pageable).toList());
+            .findAll(createExample(compositionId, name, version), pageable).toList());
     }
 
     private Example<JpaAutomationComposition> createExample(final UUID compositionId, final String name,
-            final String version) {
+                                                            final String version) {
         var example = new JpaAutomationComposition();
         example.setCompositionId(compositionId != null ? compositionId.toString() : null);
         example.setName(name);
@@ -201,7 +206,7 @@ public class AutomationCompositionProvider {
         var jpaDeleteAutomationComposition = automationCompositionRepository.findById(instanceId.toString());
         if (jpaDeleteAutomationComposition.isEmpty()) {
             var errorMessage = "delete of automation composition \"" + instanceId
-                    + "\" failed, automation composition does not exist";
+                + "\" failed, automation composition does not exist";
             throw new PfModelRuntimeException(Response.Status.NOT_FOUND, errorMessage);
         }
 
@@ -249,4 +254,16 @@ public class AutomationCompositionProvider {
         }
         return result;
     }
+
+    /**
+     * Save a copy of an automation composition to the copy table in case of a rollback.
+     *
+     * @param automationComposition the composition to be copied
+     */
+    public void copyAcElementsBeforeUpdate(AutomationComposition automationComposition) {
+        var copy = new AutomationCompositionRollback(automationComposition);
+        var jpaCopy = new JpaAutomationCompositionRollback(copy);
+        acRollbackRepository.save(jpaCopy);
+        acRollbackRepository.flush();
+    }
 }
index a6273a9..94d899e 100644 (file)
@@ -34,7 +34,7 @@ import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionRollback;
 import org.onap.policy.models.base.PfUtils;\r
 \r
 \r
-public class JpaAutomationCompositionRollbackTest {\r
+class JpaAutomationCompositionRollbackTest {\r
 \r
     private static final String NULL_INSTANCE_ID_ERROR = "instanceId is marked .*ull but is null";\r
     private static final String NULL_ERROR = " is marked .*ull but is null";\r
index c6ce2e0..7113476 100644 (file)
@@ -41,12 +41,13 @@ import org.onap.policy.clamp.models.acm.concepts.DeployState;
 import org.onap.policy.clamp.models.acm.concepts.LockState;
 import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationComposition;
 import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionElement;
+import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionRollback;
 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionElementRepository;
 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRepository;
+import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRollbackRepository;
 import org.onap.policy.common.utils.coder.Coder;
 import org.onap.policy.common.utils.coder.StandardCoder;
 import org.onap.policy.common.utils.resources.ResourceUtils;
-import org.springframework.data.domain.Example;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
@@ -58,28 +59,37 @@ class AutomationCompositionProviderTest {
 
     private static final Coder CODER = new StandardCoder();
     private static final String AUTOMATION_COMPOSITION_JSON =
-            "src/test/resources/providers/TestAutomationCompositions.json";
+        "src/test/resources/providers/TestAutomationCompositions.json";
 
     private AutomationCompositions inputAutomationCompositions;
     private List<JpaAutomationComposition> inputAutomationCompositionsJpa;
     private final String originalJson = ResourceUtils.getResourceAsString(AUTOMATION_COMPOSITION_JSON);
 
+    private AutomationCompositionProvider automationCompositionProvider;
+    private AutomationCompositionRepository automationCompositionRepository;
+    private AutomationCompositionElementRepository acElementRepository;
+    private AutomationCompositionRollbackRepository acRollbackRepository;
+
     @BeforeEach
     void beforeSetupDao() throws Exception {
         inputAutomationCompositions = CODER.decode(originalJson, AutomationCompositions.class);
         inputAutomationCompositionsJpa =
-                ProviderUtils.getJpaAndValidateList(inputAutomationCompositions.getAutomationCompositionList(),
-                        JpaAutomationComposition::new, "automation compositions");
+            ProviderUtils.getJpaAndValidateList(inputAutomationCompositions.getAutomationCompositionList(),
+                JpaAutomationComposition::new, "automation compositions");
+
+        // set mocks
+        automationCompositionRepository = mock(AutomationCompositionRepository.class);
+        acElementRepository = mock(AutomationCompositionElementRepository.class);
+        acRollbackRepository = mock(AutomationCompositionRollbackRepository.class);
+        automationCompositionProvider =
+            new AutomationCompositionProvider(automationCompositionRepository, acElementRepository,
+                acRollbackRepository);
     }
 
     @Test
     void testAutomationCompositionCreate() {
-        var automationCompositionRepository = mock(AutomationCompositionRepository.class);
-        var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
-                mock(AutomationCompositionElementRepository.class));
-
         when(automationCompositionRepository.save(any(JpaAutomationComposition.class)))
-                .thenReturn(inputAutomationCompositionsJpa.get(0));
+            .thenReturn(inputAutomationCompositionsJpa.get(0));
         var inputAc = inputAutomationCompositions.getAutomationCompositionList().get(0);
 
         var createdAutomationComposition = automationCompositionProvider.createAutomationComposition(inputAc);
@@ -90,56 +100,45 @@ class AutomationCompositionProviderTest {
 
     @Test
     void testAutomationCompositionUpdate() {
-        var automationCompositionRepository = mock(AutomationCompositionRepository.class);
-        var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
-                mock(AutomationCompositionElementRepository.class));
-
         assertThatThrownBy(() -> automationCompositionProvider.updateAutomationComposition(null))
-                .hasMessageMatching(AC_IS_NULL);
+            .hasMessageMatching(AC_IS_NULL);
 
         when(automationCompositionRepository.save(inputAutomationCompositionsJpa.get(0)))
-                .thenReturn(inputAutomationCompositionsJpa.get(0));
+            .thenReturn(inputAutomationCompositionsJpa.get(0));
 
         var createdAutomationComposition = automationCompositionProvider
-                .updateAutomationComposition(inputAutomationCompositions.getAutomationCompositionList().get(0));
+            .updateAutomationComposition(inputAutomationCompositions.getAutomationCompositionList().get(0));
 
         assertEquals(inputAutomationCompositions.getAutomationCompositionList().get(0), createdAutomationComposition);
     }
 
     @Test
     void testGetAutomationCompositionsWithNull() {
-        var automationCompositionProvider = new AutomationCompositionProvider(
-                mock(AutomationCompositionRepository.class), mock(AutomationCompositionElementRepository.class));
-
         assertThatThrownBy(() -> automationCompositionProvider
-                .getAutomationCompositions(UUID.randomUUID(), null, null, null))
-                .hasMessage("pageable is marked non-null but is null");
+            .getAutomationCompositions(UUID.randomUUID(), null, null, null))
+            .hasMessage("pageable is marked non-null but is null");
 
         assertThatThrownBy(() -> automationCompositionProvider
-                .getAutomationCompositions(null, null, null, Pageable.unpaged()))
-                .hasMessage("compositionId is marked non-null but is null");
+            .getAutomationCompositions(null, null, null, Pageable.unpaged()))
+            .hasMessage("compositionId is marked non-null but is null");
     }
 
     @Test
     void testGetAutomationCompositions() {
-        var automationCompositionRepository = mock(AutomationCompositionRepository.class);
-        var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
-                mock(AutomationCompositionElementRepository.class));
-
         var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
         when(automationCompositionRepository
-                .findAll(Mockito.<Example<JpaAutomationComposition>>any(), any(Pageable.class)))
-                .thenReturn(new PageImpl<>(inputAutomationCompositionsJpa));
+            .findAll(Mockito.any(), any(Pageable.class)))
+            .thenReturn(new PageImpl<>(inputAutomationCompositionsJpa));
         var acList = automationCompositionProvider.getAutomationCompositions(UUID.randomUUID(),
-                automationComposition.getName(), automationComposition.getVersion(), Pageable.unpaged());
+            automationComposition.getName(), automationComposition.getVersion(), Pageable.unpaged());
         assertThat(acList).hasSize(2);
 
         acList = automationCompositionProvider.getAutomationCompositions(automationComposition.getCompositionId(), null,
-                null, Pageable.unpaged());
+            null, Pageable.unpaged());
         assertThat(acList).hasSize(2);
 
         when(automationCompositionRepository
-            .findAll(Mockito.<Example<JpaAutomationComposition>>any(), Mockito.any(Pageable.class)))
+            .findAll(Mockito.any(), Mockito.any(Pageable.class)))
             .thenReturn(new PageImpl<>(inputAutomationCompositionsJpa));
         acList = automationCompositionProvider.getAutomationCompositions(automationComposition.getCompositionId(), null,
             null, PageRequest.of(0, 10));
@@ -148,27 +147,19 @@ class AutomationCompositionProviderTest {
 
     @Test
     void testGetAutomationComposition() {
-        var automationCompositionRepository = mock(AutomationCompositionRepository.class);
-        var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
-                mock(AutomationCompositionElementRepository.class));
-
         var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
         assertThatThrownBy(
-                () -> automationCompositionProvider.getAutomationComposition(automationComposition.getInstanceId()))
-                        .hasMessageMatching("AutomationComposition not found");
+            () -> automationCompositionProvider.getAutomationComposition(automationComposition.getInstanceId()))
+            .hasMessageMatching("AutomationComposition not found");
 
         when(automationCompositionRepository.findById(automationComposition.getInstanceId().toString()))
-                .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
+            .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
         var ac = automationCompositionProvider.getAutomationComposition(automationComposition.getInstanceId());
         assertEquals(automationComposition, ac);
     }
 
     @Test
     void testFindAutomationComposition() {
-        var automationCompositionRepository = mock(AutomationCompositionRepository.class);
-        var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
-                mock(AutomationCompositionElementRepository.class));
-
         var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
         var acOpt = automationCompositionProvider.findAutomationComposition(automationComposition.getInstanceId());
         assertThat(acOpt).isEmpty();
@@ -177,27 +168,23 @@ class AutomationCompositionProviderTest {
         assertThat(acOpt).isEmpty();
 
         when(automationCompositionRepository.findById(automationComposition.getInstanceId().toString()))
-                .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
+            .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
         acOpt = automationCompositionProvider.findAutomationComposition(automationComposition.getInstanceId());
         assertEquals(automationComposition, acOpt.get());
 
-        when(automationCompositionRepository.findOne(Mockito.<Example<JpaAutomationComposition>>any()))
-                .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
+        when(automationCompositionRepository.findOne(Mockito.any()))
+            .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
         acOpt = automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
         assertEquals(automationComposition, acOpt.get());
     }
 
     @Test
     void testGetAcInstancesByCompositionId() {
-        var automationCompositionRepository = mock(AutomationCompositionRepository.class);
-        var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
-                mock(AutomationCompositionElementRepository.class));
-
         var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
         when(automationCompositionRepository.findByCompositionId(automationComposition.getCompositionId().toString()))
-                .thenReturn(inputAutomationCompositionsJpa);
+            .thenReturn(inputAutomationCompositionsJpa);
         var acList =
-                automationCompositionProvider.getAcInstancesByCompositionId(automationComposition.getCompositionId());
+            automationCompositionProvider.getAcInstancesByCompositionId(automationComposition.getCompositionId());
         assertEquals(inputAutomationCompositions.getAutomationCompositionList(), acList);
     }
 
@@ -210,9 +197,7 @@ class AutomationCompositionProviderTest {
 
         List<JpaAutomationComposition> res1 = new ArrayList<>();
         res1.add(inputAutomationCompositionsJpa.get(0));
-        var automationCompositionRepository = mock(AutomationCompositionRepository.class);
-        var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
-            mock(AutomationCompositionElementRepository.class));
+
         when(automationCompositionRepository.findByDeployStateIn(List.of(DeployState.DEPLOYING,
             DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING)))
             .thenReturn(res1);
@@ -220,35 +205,28 @@ class AutomationCompositionProviderTest {
             .thenReturn(List.of(inputAutomationCompositionsJpa.get(1)));
         var acList = automationCompositionProvider.getAcInstancesInTransition();
         assertThat(acList).hasSize(2)
-                .contains(inputAutomationCompositions.getAutomationCompositionList().get(0).getInstanceId())
-                .contains(inputAutomationCompositions.getAutomationCompositionList().get(1).getInstanceId());
+            .contains(inputAutomationCompositions.getAutomationCompositionList().get(0).getInstanceId())
+            .contains(inputAutomationCompositions.getAutomationCompositionList().get(1).getInstanceId());
     }
 
     @Test
     void testDeleteAutomationComposition() {
-        var automationCompositionRepository = mock(AutomationCompositionRepository.class);
-        var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
-                mock(AutomationCompositionElementRepository.class));
-
         assertThatThrownBy(() -> automationCompositionProvider.deleteAutomationComposition(UUID.randomUUID()))
-                .hasMessageMatching(".*.failed, automation composition does not exist");
+            .hasMessageMatching(".*.failed, automation composition does not exist");
 
         var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
         when(automationCompositionRepository.findById(automationComposition.getInstanceId().toString()))
-                .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
+            .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
 
         var deletedAc =
-                automationCompositionProvider.deleteAutomationComposition(automationComposition.getInstanceId());
+            automationCompositionProvider.deleteAutomationComposition(automationComposition.getInstanceId());
         assertEquals(automationComposition, deletedAc);
     }
 
     @Test
     void testDeleteElementById() {
-        var acElementRepository = mock(AutomationCompositionElementRepository.class);
-        var automationCompositionProvider = new AutomationCompositionProvider(
-                mock(AutomationCompositionRepository.class), acElementRepository);
         assertThatThrownBy(() -> automationCompositionProvider.deleteAutomationCompositionElement(null))
-                .hasMessageMatching(ACELEMENT_ID_IS_NULL);
+            .hasMessageMatching(ACELEMENT_ID_IS_NULL);
         var elementId = UUID.randomUUID();
         automationCompositionProvider.deleteAutomationCompositionElement(elementId);
         verify(acElementRepository).deleteById(elementId.toString());
@@ -256,10 +234,6 @@ class AutomationCompositionProviderTest {
 
     @Test
     void testValidateElementIds() {
-        var acElementRepository = mock(AutomationCompositionElementRepository.class);
-        var automationCompositionProvider = new AutomationCompositionProvider(
-            mock(AutomationCompositionRepository.class), acElementRepository);
-
         var ac = inputAutomationCompositions.getAutomationCompositionList().get(0);
 
         var result = automationCompositionProvider.validateElementIds(ac);
@@ -283,4 +257,12 @@ class AutomationCompositionProviderTest {
         result = automationCompositionProvider.validateElementIds(ac);
         assertThat(result.isValid()).isTrue();
     }
+
+    @Test
+    void testCopyAcElements() {
+        var ac = inputAutomationCompositions.getAutomationCompositionList().get(0);
+        automationCompositionProvider.copyAcElementsBeforeUpdate(ac);
+
+        verify(acRollbackRepository).save(any(JpaAutomationCompositionRollback.class));
+    }
 }
index edb3386..0d3375b 100644 (file)
@@ -50,7 +50,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 /**
- * This class provides the create, read and delete actions on Commissioning of automation composition concepts in the
+ * This class provides the creation, read and delete actions on Commissioning of automation composition concepts in the
  * database to the callers.
  */
 @Service
@@ -202,7 +202,6 @@ public class CommissioningProvider {
 
             case DEPRIME:
                 deprime(acmDefinition);
-
                 break;
 
             default:
index c015ceb..59373e8 100644 (file)
@@ -73,7 +73,7 @@ public class AutomationCompositionInstantiationProvider {
     private static final String DO_NOT_MATCH = " do not match with ";
     private static final String ELEMENT_ID_NOT_PRESENT = "Element id not present ";
     private static final String NOT_VALID_ORDER =
-            "Not valid order %s; DeployState: %s; LockState: %s; SubState: %s; StateChangeResult: %s";
+        "Not valid order %s; DeployState: %s; LockState: %s; SubState: %s; StateChangeResult: %s";
 
     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionInstantiationProvider.class);
 
@@ -88,21 +88,18 @@ public class AutomationCompositionInstantiationProvider {
     /**
      * Create automation composition.
      *
-     * @param compositionId The UUID of the automation composition definition
+     * @param compositionId         The UUID of the automation composition definition
      * @param automationComposition the automation composition
      * @return the result of the instantiation operation
      */
     public InstantiationResponse createAutomationComposition(UUID compositionId,
-            AutomationComposition automationComposition) {
-        if (!compositionId.equals(automationComposition.getCompositionId())) {
-            throw new PfModelRuntimeException(Status.BAD_REQUEST,
-                    automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
-        }
+                                                             AutomationComposition automationComposition) {
+        validateCompositionRequested(compositionId, automationComposition);
         var checkAutomationCompositionOpt =
-                automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
+            automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
         if (checkAutomationCompositionOpt.isPresent()) {
             throw new PfModelRuntimeException(Status.BAD_REQUEST,
-                    automationComposition.getKey().asIdentifier() + " already defined");
+                automationComposition.getKey().asIdentifier() + " already defined");
         }
 
         var validationResult = validateAutomationComposition(automationComposition);
@@ -125,18 +122,15 @@ public class AutomationCompositionInstantiationProvider {
     /**
      * Update automation composition.
      *
-     * @param compositionId The UUID of the automation composition definition
+     * @param compositionId         The UUID of the automation composition definition
      * @param automationComposition the automation composition
      * @return the result of the update
      */
     public InstantiationResponse updateAutomationComposition(UUID compositionId,
-            AutomationComposition automationComposition) {
+                                                             AutomationComposition automationComposition) {
         var instanceId = automationComposition.getInstanceId();
         var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
-        if (!compositionId.equals(acToUpdate.getCompositionId())) {
-            throw new PfModelRuntimeException(Status.BAD_REQUEST,
-                    automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
-        }
+        validateCompositionRequested(compositionId, acToUpdate);
         if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
             acToUpdate.setElements(automationComposition.getElements());
             acToUpdate.setName(automationComposition.getName());
@@ -166,8 +160,8 @@ public class AutomationCompositionInstantiationProvider {
             }
         }
         var result = acInstanceStateResolver.resolve(deployOrder, LockOrder.NONE, subOrder,
-                acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
-                acToUpdate.getStateChangeResult());
+            acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
+            acToUpdate.getStateChangeResult());
         return switch (result) {
             case "UPDATE" -> updateDeployedAutomationComposition(automationComposition, acToUpdate);
 
@@ -176,7 +170,7 @@ public class AutomationCompositionInstantiationProvider {
             case "MIGRATE_PRECHECK" -> migratePrecheckAc(automationComposition, acToUpdate);
 
             default -> throw new PfModelRuntimeException(Status.BAD_REQUEST,
-                    "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
+                "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
         };
     }
 
@@ -184,11 +178,13 @@ public class AutomationCompositionInstantiationProvider {
      * Update deployed AC Element properties.
      *
      * @param automationComposition the automation composition
-     * @param acToBeUpdated the composition to be updated
+     * @param acToBeUpdated         the composition to be updated
      * @return the result of the update
      */
     private InstantiationResponse updateDeployedAutomationComposition(
-            AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
+        AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
+        // save copy in case of a rollback
+        automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
 
         // Iterate and update the element property values
         for (var element : automationComposition.getElements().entrySet()) {
@@ -223,33 +219,11 @@ public class AutomationCompositionInstantiationProvider {
             throw new PfModelRuntimeException(Status.BAD_REQUEST,
                 "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
         }
+        // make copy for rollback
+        automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
 
         // Iterate and update the element property values
-        for (var element : automationComposition.getElements().entrySet()) {
-            var elementId = element.getKey();
-            var dbAcElement = acToBeUpdated.getElements().get(elementId);
-            // Add additional elements if present for migration
-            if (dbAcElement == null) {
-                LOGGER.info("New Ac element {} added in Migration", elementId);
-                acToBeUpdated.getElements().put(elementId, element.getValue());
-            } else {
-                AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
-                var newDefinition = element.getValue().getDefinition().asConceptKey();
-                var dbElementDefinition = dbAcElement.getDefinition().asConceptKey();
-                checkCompatibility(newDefinition, dbElementDefinition, automationComposition.getInstanceId());
-                dbAcElement.setDefinition(element.getValue().getDefinition());
-            }
-        }
-        // Remove element which is not present in the new Ac instance
-        var elementsRemoved = getElementRemoved(acToBeUpdated, automationComposition);
-        elementsRemoved.forEach(uuid -> acToBeUpdated.getElements().remove(uuid));
-
-        var validationResult =
-                validateAutomationComposition(acToBeUpdated, automationComposition.getCompositionTargetId());
-        if (!validationResult.isValid()) {
-            throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
-        }
-        acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
+        var elementsRemoved = updateElementsProperties(automationComposition, acToBeUpdated);
         var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
 
         updateAcForMigration(acToBeUpdated, acDefinition);
@@ -281,7 +255,7 @@ public class AutomationCompositionInstantiationProvider {
 
     private List<UUID> getElementRemoved(AutomationComposition acFromDb, AutomationComposition acFromMigration) {
         return acFromDb.getElements().keySet().stream()
-                .filter(id -> acFromMigration.getElements().get(id) == null).toList();
+            .filter(id -> acFromMigration.getElements().get(id) == null).toList();
     }
 
     void checkCompatibility(PfConceptKey newDefinition, PfConceptKey dbElementDefinition,
@@ -289,46 +263,22 @@ public class AutomationCompositionInstantiationProvider {
         var compatibility = newDefinition.getCompatibility(dbElementDefinition);
         if (PfKey.Compatibility.DIFFERENT.equals(compatibility)) {
             throw new PfModelRuntimeException(Status.BAD_REQUEST,
-                    dbElementDefinition + " is not compatible with " + newDefinition);
+                dbElementDefinition + " is not compatible with " + newDefinition);
         }
         if (PfKey.Compatibility.MAJOR.equals(compatibility) || PfKey.Compatibility.MINOR
-                .equals(compatibility)) {
+            .equals(compatibility)) {
             LOGGER.warn("Migrate {}: Version {} has {} compatibility with {} ", instanceId, newDefinition,
-                    compatibility, dbElementDefinition);
+                compatibility, dbElementDefinition);
         }
     }
 
     private InstantiationResponse migratePrecheckAc(
-            AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
+        AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
 
         acToBeUpdated.setPrecheck(true);
         var copyAc = new AutomationComposition(acToBeUpdated);
         // Iterate and update the element property values
-        for (var element : automationComposition.getElements().entrySet()) {
-            var elementId = element.getKey();
-            var copyElement = copyAc.getElements().get(elementId);
-            // Add additional elements if present for migration
-            if (copyElement == null) {
-                LOGGER.info("New Ac element {} added in Migration", elementId);
-                copyAc.getElements().put(elementId, element.getValue());
-            } else {
-                AcmUtils.recursiveMerge(copyElement.getProperties(), element.getValue().getProperties());
-                var newDefinition = element.getValue().getDefinition().asConceptKey();
-                var copyElementDefinition = copyElement.getDefinition().asConceptKey();
-                checkCompatibility(newDefinition, copyElementDefinition, automationComposition.getInstanceId());
-                copyElement.setDefinition(element.getValue().getDefinition());
-            }
-        }
-        // Remove element which is not present in the new Ac instance
-        var elementsRemoved = getElementRemoved(copyAc, automationComposition);
-        elementsRemoved.forEach(uuid -> copyAc.getElements().remove(uuid));
-
-        var validationResult =
-                validateAutomationComposition(copyAc, automationComposition.getCompositionTargetId());
-        if (!validationResult.isValid()) {
-            throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
-        }
-        copyAc.setCompositionTargetId(automationComposition.getCompositionTargetId());
+        updateElementsProperties(automationComposition, copyAc);
 
         // Publish migrate event to the participants
         supervisionAcHandler.migratePrecheck(copyAc);
@@ -348,32 +298,32 @@ public class AutomationCompositionInstantiationProvider {
      * Validate AutomationComposition.
      *
      * @param automationComposition AutomationComposition to validate
-     * @param compositionId the composition id
+     * @param compositionId         the composition id
      * @return the result of validation
      */
     private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition,
-            UUID compositionId) {
+                                                               UUID compositionId) {
 
         var result = new BeanValidationResult("AutomationComposition", automationComposition);
         var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
         if (acDefinitionOpt.isEmpty()) {
             result.addResult(new ObjectValidationResult("ServiceTemplate", compositionId, ValidationStatus.INVALID,
-                    "Commissioned automation composition definition not found"));
+                "Commissioned automation composition definition not found"));
             return result;
         }
         if (!AcTypeState.PRIMED.equals(acDefinitionOpt.get().getState())) {
             result.addResult(new ObjectValidationResult("ServiceTemplate.state", acDefinitionOpt.get().getState(),
-                    ValidationStatus.INVALID, "Commissioned automation composition definition not primed"));
+                ValidationStatus.INVALID, "Commissioned automation composition definition not primed"));
             return result;
         }
         var participantIds = acDefinitionOpt.get().getElementStateMap().values().stream()
-                .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
+            .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
 
         participantProvider.verifyParticipantState(participantIds);
 
         result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
-                acDefinitionOpt.get().getServiceTemplate(),
-                acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
+            acDefinitionOpt.get().getServiceTemplate(),
+            acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
 
         result.addResult(automationCompositionProvider.validateElementIds(automationComposition));
 
@@ -393,7 +343,7 @@ public class AutomationCompositionInstantiationProvider {
         if (encryptionUtils.encryptionEnabled()) {
             var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
             acDefinitionOpt.ifPresent(acDefinition
-                    -> encryptionUtils.findAndEncryptSensitiveData(acDefinition, automationComposition));
+                -> encryptionUtils.findAndEncryptSensitiveData(acDefinition, automationComposition));
         }
     }
 
@@ -401,16 +351,16 @@ public class AutomationCompositionInstantiationProvider {
      * Get Automation Composition.
      *
      * @param compositionId The UUID of the automation composition definition
-     * @param instanceId The UUID of the automation composition instance
+     * @param instanceId    The UUID of the automation composition instance
      * @return the Automation Composition
      */
     @Transactional(readOnly = true)
     public AutomationComposition getAutomationComposition(@NonNull UUID compositionId, UUID instanceId) {
         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
         if (!compositionId.equals(automationComposition.getCompositionId())
-                        && !compositionId.equals(automationComposition.getCompositionTargetId())) {
+            && !compositionId.equals(automationComposition.getCompositionTargetId())) {
             throw new PfModelRuntimeException(Status.BAD_REQUEST,
-                    automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
+                automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
         }
         return automationComposition;
     }
@@ -419,27 +369,20 @@ public class AutomationCompositionInstantiationProvider {
      * Delete the automation composition with the given name and version.
      *
      * @param compositionId The UUID of the automation composition definition
-     * @param instanceId The UUID of the automation composition instance
+     * @param instanceId    The UUID of the automation composition instance
      * @return the result of the deletion
      */
     public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
-        if (!compositionId.equals(automationComposition.getCompositionId())) {
-            throw new PfModelRuntimeException(Status.BAD_REQUEST,
-                    automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
-        }
-        var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
-        var participantIds = acDefinition.getElementStateMap().values().stream()
-            .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
-        participantProvider.verifyParticipantState(participantIds);
+        var acDefinition = getAcDefinition(compositionId, automationComposition);
         var result = acInstanceStateResolver.resolve(DeployOrder.DELETE,
-                null, null,
-                automationComposition.getDeployState(), automationComposition.getLockState(),
-                automationComposition.getSubState(), automationComposition.getStateChangeResult());
+            null, null,
+            automationComposition.getDeployState(), automationComposition.getLockState(),
+            automationComposition.getSubState(), automationComposition.getStateChangeResult());
         if (!DeployOrder.DELETE.name().equals(result)) {
             var msg = String.format(NOT_VALID_ORDER, DeployOrder.DELETE,
-                    automationComposition.getDeployState(), automationComposition.getLockState(),
-                    automationComposition.getSubState(), automationComposition.getStateChangeResult());
+                automationComposition.getDeployState(), automationComposition.getLockState(),
+                automationComposition.getSubState(), automationComposition.getStateChangeResult());
             throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
         }
         supervisionAcHandler.delete(automationComposition, acDefinition);
@@ -449,17 +392,18 @@ public class AutomationCompositionInstantiationProvider {
     /**
      * Get the requested automation compositions.
      *
-     * @param name the name of the automation composition to get, null for all automation compositions
-     * @param version the version of the automation composition to get, null for all automation compositions
+     * @param name     the name of the automation composition to get, null for all automation compositions
+     * @param version  the version of the automation composition to get, null for all automation compositions
      * @param pageable the Pageable
      * @return the automation compositions
      */
     @Transactional(readOnly = true)
     public AutomationCompositions getAutomationCompositions(@NonNull final UUID compositionId,
-            final String name, final String version, @NonNull final Pageable pageable) {
+                                                            final String name, final String version,
+                                                            @NonNull final Pageable pageable) {
         var automationCompositions = new AutomationCompositions();
         automationCompositions.setAutomationCompositionList(
-                automationCompositionProvider.getAutomationCompositions(compositionId, name, version, pageable));
+            automationCompositionProvider.getAutomationCompositions(compositionId, name, version, pageable));
 
         return automationCompositions;
     }
@@ -467,27 +411,18 @@ public class AutomationCompositionInstantiationProvider {
     /**
      * Handle Composition Instance State.
      *
-     * @param compositionId the compositionId
-     * @param instanceId the instanceId
+     * @param compositionId         the compositionId
+     * @param instanceId            the instanceId
      * @param acInstanceStateUpdate the AcInstanceStateUpdate
      */
     public void compositionInstanceState(UUID compositionId, UUID instanceId,
-            @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
+                                         @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
-        if (!compositionId.equals(automationComposition.getCompositionId())) {
-            throw new PfModelRuntimeException(Status.BAD_REQUEST,
-                    automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
-        }
-        var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
-
-        var participantIds = acDefinition.getElementStateMap().values().stream()
-                .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
-
-        participantProvider.verifyParticipantState(participantIds);
+        var acDefinition = getAcDefinition(compositionId, automationComposition);
         var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
-                acInstanceStateUpdate.getLockOrder(), acInstanceStateUpdate.getSubOrder(),
-                automationComposition.getDeployState(), automationComposition.getLockState(),
-                automationComposition.getSubState(), automationComposition.getStateChangeResult());
+            acInstanceStateUpdate.getLockOrder(), acInstanceStateUpdate.getSubOrder(),
+            automationComposition.getDeployState(), automationComposition.getLockState(),
+            automationComposition.getSubState(), automationComposition.getStateChangeResult());
         switch (result) {
             case "DEPLOY":
                 supervisionAcHandler.deploy(automationComposition, acDefinition);
@@ -515,9 +450,59 @@ public class AutomationCompositionInstantiationProvider {
 
             default:
                 var msg = String.format(NOT_VALID_ORDER, acInstanceStateUpdate,
-                        automationComposition.getDeployState(), automationComposition.getLockState(),
-                        automationComposition.getSubState(), automationComposition.getStateChangeResult());
+                    automationComposition.getDeployState(), automationComposition.getLockState(),
+                    automationComposition.getSubState(), automationComposition.getStateChangeResult());
                 throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
         }
     }
+
+    private List<UUID> updateElementsProperties(AutomationComposition automationComposition,
+                                                AutomationComposition acToBeUpdated) {
+        for (var element : automationComposition.getElements().entrySet()) {
+            var elementId = element.getKey();
+            var dbAcElement = acToBeUpdated.getElements().get(elementId);
+            // Add additional elements if present for migration
+            if (dbAcElement == null) {
+                LOGGER.info("New Ac element {} added in Migration", elementId);
+                acToBeUpdated.getElements().put(elementId, element.getValue());
+            } else {
+                AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
+                var newDefinition = element.getValue().getDefinition().asConceptKey();
+                var dbElementDefinition = dbAcElement.getDefinition().asConceptKey();
+                checkCompatibility(newDefinition, dbElementDefinition, automationComposition.getInstanceId());
+                dbAcElement.setDefinition(element.getValue().getDefinition());
+            }
+        }
+        // Remove element which is not present in the new Ac instance
+        var elementsRemoved = getElementRemoved(acToBeUpdated, automationComposition);
+        elementsRemoved.forEach(uuid -> acToBeUpdated.getElements().remove(uuid));
+
+        var validationResult =
+            validateAutomationComposition(acToBeUpdated, automationComposition.getCompositionTargetId());
+        if (!validationResult.isValid()) {
+            throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
+        }
+        acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
+        return elementsRemoved;
+    }
+
+    private static void validateCompositionRequested(UUID compositionId,
+                                                     AutomationComposition automationComposition) {
+        if (!compositionId.equals(automationComposition.getCompositionId())) {
+            throw new PfModelRuntimeException(Status.BAD_REQUEST,
+                automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
+        }
+    }
+
+    private AutomationCompositionDefinition getAcDefinition(UUID compositionId,
+                                                            AutomationComposition automationComposition) {
+        validateCompositionRequested(compositionId, automationComposition);
+        var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
+
+        var participantIds = acDefinition.getElementStateMap().values().stream()
+            .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
+
+        participantProvider.verifyParticipantState(participantIds);
+        return acDefinition;
+    }
 }
index fa8e8b2..2bbfe3a 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START=======================================================
-#  Copyright (C) 2022-2023,2025 OpenInfra Foundation Europe. All rights reserved.
+#  Copyright (C) 2022-2023, 2025 OpenInfra Foundation Europe. All rights reserved.
 #  ================================================================================
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@ servers:
         description: This value is assigned by the service provider
 tags:
 - name: Participant Monitoring
-  description: Pariticipant Monitoring Controller, for monitoring of and requesting information from participants
+  description: Participant Monitoring Controller, for monitoring of and requesting information from participants
 - name: Automation Composition Definition
   description: Automation Composition Definition Controller, for definition and management of Automation Composition Types
 - name: Automation Composition Instance
@@ -44,7 +44,7 @@ paths:
     get:
       tags:
       - Participant Monitoring
-      summary: Query Particicpants
+      summary: Query Participants
       description: Query the participants that are registered on the ACM runtime
       operationId: queryParticipants
       parameters:
@@ -146,12 +146,12 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
     put:
       tags:
       - Participant Monitoring
-      summary: Order an immendiate Participant Report from all participants
+      summary: Order an immediate Participant Report from all participants
       description: Requests all participants to immediately generate a heartbeat report with their information and status
         and the information and status of all their AC Element Types and Instances. The results are published on subsequent
         GET REST requests on the "participants" endpoint.
@@ -226,8 +226,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
       x-codegen-request-body-name: body
   /participants/{participantId}:
     get:
@@ -235,7 +235,7 @@ paths:
       - Participant Monitoring
       summary: Get details of the requested participant
         definitions
-      description: Get details of the requested commissioned participant, returning all pariticipant details
+      description: Get details of the requested commissioned participant, returning all participant details
       operationId: getParticipant
       parameters:
       - name : participantId
@@ -341,12 +341,12 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
     put:
       tags:
       - Participant Monitoring
-      summary: Order an immendiate Participant Report from a participant
+      summary: Order an immediate Participant Report from a participant
       description: Requests the participants to immediately generate a heartbeat report with its information and status
         and the information and status of all its AC Element Types and Instances. The results are published on subsequent
         GET REST requests on the "participants" endpoint.
@@ -444,8 +444,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
       x-codegen-request-body-name: body
   /compositions:
     get:
@@ -549,8 +549,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
     post:
       tags:
       - Automation Composition Definition
@@ -657,8 +657,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
       x-codegen-request-body-name: body
   /compositions/{compositionId}:
     get:
@@ -760,8 +760,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
     put:
       tags:
       - Automation Composition Definition
@@ -877,8 +877,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
       x-codegen-request-body-name: body
     delete:
       tags:
@@ -992,8 +992,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
   /compositions/{compositionId}/instances:
     get:
       tags:
@@ -1116,8 +1116,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
     post:
       tags:
       - Automation Composition Instance
@@ -1258,8 +1258,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
       x-codegen-request-body-name: body
   /compositions/{compositionId}/instances/{instanceId}:
     get:
@@ -1365,8 +1365,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
     put:
       tags:
       - Automation Composition Instance
@@ -1491,8 +1491,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
       x-codegen-request-body-name: body
     delete:
       tags:
@@ -1613,8 +1613,8 @@ paths:
       security:
       - basicAuth: []
       x-interface info:
-        api-version: 1.0.0
-        last-mod-release: London
+        api-version: 8.2.1
+        last-mod-release: Paris
 
 components:
   securitySchemes: