Add migration support in ACM intermediary

Issue-ID: POLICY-4824
Change-Id: I4e9ef54be63a86b01c6e6fad4c78baa72e161eed
Signed-off-by: FrancescoFioraEst <francesco.fiora@est.tech>
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ParticipantIntermediaryApi.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ParticipantIntermediaryApi.java
index bca5f48..9b32792 100755
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ParticipantIntermediaryApi.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ParticipantIntermediaryApi.java
@@ -74,27 +74,59 @@
      */
     AutomationCompositionElement getAutomationCompositionElement(UUID automationCompositionId, UUID elementId);
 
+    /**
+     * Get a copy of all AutomationCompositionElementDefinition from all primed compositions.
+     *
+     * @return a Map by compositionId of Maps of AutomationCompositionElement
+     */
     Map<UUID, Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition>> getAcElementsDefinitions();
 
+    /**
+     * Get a copy of AutomationCompositionElementDefinitions of a composition.
+     *
+     * @param compositionId the composition id
+     * @return a Map by element definition Id of AutomationCompositionElementDefinitions
+     */
     Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> getAcElementsDefinitions(UUID compositionId);
 
-    AutomationCompositionElementDefinition getAcElementDefinition(UUID compositionId,
-            ToscaConceptIdentifier elementId);
+    /**
+     * Get a copy of the AutomationCompositionElementDefinition by compositionId and element definition Id.
+     *
+     * @param compositionId the composition id
+     * @param elementId the element definition Id
+     * @return the AutomationCompositionElementDefinition
+     */
+    AutomationCompositionElementDefinition getAcElementDefinition(UUID compositionId, ToscaConceptIdentifier elementId);
 
     /**
      * Send Automation Composition Element update Info to AC-runtime.
      *
      * @param automationCompositionId the ID of the automation composition to update the states
-     * @param id the ID of the automation composition element to update the states
+     * @param elementId the ID of the automation composition element to update the states
      * @param useState the use State
      * @param operationalState the operational State
      * @param outProperties the output Properties Map
      */
-    void sendAcElementInfo(UUID automationCompositionId, UUID id, String useState, String operationalState,
+    void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState, String operationalState,
             Map<String, Object> outProperties);
 
+    /**
+     * Send Automation Composition Definition update Info to AC-runtime.
+     *
+     * @param compositionId the composition id
+     * @param elementId the element definition Id
+     * @param outProperties the output Properties Map
+     */
     void sendAcDefinitionInfo(UUID compositionId, ToscaConceptIdentifier elementId, Map<String, Object> outProperties);
 
+    /**
+     * Update the state of a Automation Composition Definition.
+     *
+     * @param compositionId the composition id
+     * @param state the state of Automation Composition Definition
+     * @param stateChangeResult the indicator if error occurs
+     * @param message the message
+     */
     void updateCompositionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult,
             String message);
 }
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AutomationCompositionMigrationListener.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AutomationCompositionMigrationListener.java
new file mode 100755
index 0000000..265502e
--- /dev/null
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AutomationCompositionMigrationListener.java
@@ -0,0 +1,40 @@
+/*-

+ * ============LICENSE_START=======================================================

+ * Copyright (C) 2023 Nordix Foundation.

+ * ================================================================================

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ *

+ * SPDX-License-Identifier: Apache-2.0

+ * ============LICENSE_END=========================================================

+ */

+

+package org.onap.policy.clamp.acm.participant.intermediary.comm;

+

+import org.onap.policy.clamp.acm.participant.intermediary.handler.ParticipantHandler;

+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionMigration;

+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;

+import org.springframework.stereotype.Component;

+

+@Component

+public class AutomationCompositionMigrationListener extends ParticipantListener<AutomationCompositionMigration> {

+

+    protected AutomationCompositionMigrationListener(final ParticipantHandler participantHandler) {

+        super(AutomationCompositionMigration.class, participantHandler,

+                participantHandler::handleAutomationCompositionMigration);

+    }

+

+    @Override

+    public String getType() {

+        return ParticipantMessageType.AUTOMATION_COMPOSITION_MIGRATION.name();

+    }

+}

diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java
index c7cb548..02fce55 100755
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java
@@ -24,6 +24,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.UUID;
+import lombok.NonNull;
 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
@@ -37,6 +38,7 @@
 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeployAck;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionMigration;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
@@ -194,7 +196,8 @@
         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
 
-                updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy);
+                updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy,
+                        DeployState.UPDATING);
 
                 callParticipantUpdateProperty(updateMsg.getMessageId(), participantDeploy.getAcElementList(),
                         updateMsg.getAutomationCompositionId());
@@ -245,11 +248,13 @@
         }
     }
 
-    private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy) {
+    private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy,
+            DeployState deployState) {
         var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements();
         for (var element : participantDeploy.getAcElementList()) {
             var acElement = acElementList.get(element.getId());
             acElement.getProperties().putAll(element.getProperties());
+            acElement.setDeployState(deployState);
         }
     }
 
@@ -360,4 +365,40 @@
         }
         listener.restarted(messageId, compositionId, list, state, automationCompositionList);
     }
+
+    /**
+     * Handles AutomationComposition Migration.
+     *
+     * @param migrationMsg the AutomationCompositionMigration
+     */
+    public void handleAutomationCompositionMigration(AutomationCompositionMigration migrationMsg) {
+        if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) {
+            return;
+        }
+
+        var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
+        if (automationComposition == null) {
+            LOGGER.debug("Automation composition {} does not use this participant",
+                    migrationMsg.getAutomationCompositionId());
+            return;
+        }
+        automationComposition.setCompositionTargetId(migrationMsg.getCompositionTargetId());
+        for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
+            if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
+
+                updateExistingElementsOnThisParticipant(migrationMsg.getAutomationCompositionId(), participantDeploy,
+                        DeployState.MIGRATING);
+
+                callParticipantMigrate(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
+                        migrationMsg.getAutomationCompositionId(), migrationMsg.getCompositionTargetId());
+            }
+        }
+    }
+
+    private void callParticipantMigrate(UUID messageId, List<AcElementDeploy> acElements, UUID instanceId,
+            UUID compositionTargetId) {
+        for (var element : acElements) {
+            listener.migrate(messageId, instanceId, element, compositionTargetId, element.getProperties());
+        }
+    }
 }
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandler.java
index 7e4fedb..e2e93da 100755
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandler.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandler.java
@@ -123,6 +123,11 @@
         var checkOpt = automationComposition.getElements().values().stream()
                 .filter(acElement -> !deployState.equals(acElement.getDeployState())).findAny();
         if (checkOpt.isEmpty()) {
+            if (DeployState.MIGRATING.equals(automationComposition.getDeployState())) {
+                // migration scenario
+                automationComposition.setCompositionId(automationComposition.getCompositionTargetId());
+                automationComposition.setCompositionTargetId(null);
+            }
             automationComposition.setDeployState(deployState);
             automationComposition.setLockState(element.getLockState());
 
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java
index 6b025c7..8d33b3e 100755
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java
@@ -31,6 +31,7 @@
 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionMigration;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantAckMessage;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantDeregister;
@@ -56,7 +57,6 @@
     private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantHandler.class);
 
     private final AutomationCompositionHandler automationCompositionHandler;
-    private final AutomationCompositionOutHandler automationCompositionOutHandler;
     private final ParticipantMessagePublisher publisher;
     private final CacheProvider cacheProvider;
 
@@ -95,6 +95,18 @@
     }
 
     /**
+     * Handle a automation composition migration message.
+     *
+     * @param migrationMsg the migration message
+     */
+    @Timed(
+            value = "listener.automation_composition_migration",
+            description = "AUTOMATION_COMPOSITION_MIGRATION messages received")
+    public void handleAutomationCompositionMigration(AutomationCompositionMigration migrationMsg) {
+        automationCompositionHandler.handleAutomationCompositionMigration(migrationMsg);
+    }
+
+    /**
      * Handle a automation composition property update message.
      *
      * @param propertyUpdateMsg the property update message
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java
old mode 100644
new mode 100755
index 2018d43..e29562a
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java
@@ -328,4 +328,31 @@
     public void close() throws IOException {
         executor.shutdown();
     }
+
+    /**
+     * Handles AutomationComposition Migration.
+     *
+     * @param messageId the messageId
+     * @param instanceId the automationComposition Id
+     * @param element the information on the automation composition element
+     * @param compositionTargetId the composition to migrate
+     */
+    public void migrate(UUID messageId, UUID instanceId, AcElementDeploy element, UUID compositionTargetId,
+            Map<String, Object> properties) {
+        cleanExecution(element.getId(), messageId);
+        var result = executor.submit(() -> this.migrateProcess(instanceId, element, compositionTargetId, properties));
+        executionMap.put(element.getId(), result);
+    }
+
+    private void migrateProcess(UUID instanceId, AcElementDeploy element, UUID compositionTargetId,
+            Map<String, Object> properties) {
+        try {
+            listener.migrate(instanceId, element, compositionTargetId, properties);
+        } catch (PfModelException e) {
+            LOGGER.error("Automation composition element migrate failed {} {}", instanceId, e.getMessage());
+            intermediaryApi.updateAutomationCompositionElementState(instanceId, element.getId(), DeployState.DEPLOYED,
+                    null, StateChangeResult.FAILED, "Automation composition element migrate failed");
+        }
+        executionMap.remove(element.getId());
+    }
 }
diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/comm/ParticipantCommTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/comm/ParticipantCommTest.java
index e959d13..de94820 100755
--- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/comm/ParticipantCommTest.java
+++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/comm/ParticipantCommTest.java
@@ -81,6 +81,9 @@
         var participantRestartListener = new ParticipantRestartListener(participantHandler);
         assertEquals(ParticipantMessageType.PARTICIPANT_RESTART.name(),
                 participantRestartListener.getType());
+
+        var acMigrationListener = new AutomationCompositionMigrationListener(participantHandler);
+        assertEquals(ParticipantMessageType.AUTOMATION_COMPOSITION_MIGRATION.name(), acMigrationListener.getType());
     }
 
     @Test
diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java
index cb7e560..5f7d71e 100755
--- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java
+++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java
@@ -23,6 +23,7 @@
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -43,6 +44,7 @@
 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeployAck;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionMigration;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
@@ -90,7 +92,7 @@
         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
         verify(listener, times(automationComposition.getElements().size())).undeploy(any(), any(), any());
-        for (var element: automationComposition.getElements().values()) {
+        for (var element : automationComposition.getElements().values()) {
             assertEquals(DeployState.UNDEPLOYING, element.getDeployState());
         }
     }
@@ -110,7 +112,7 @@
         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
         verify(listener, times(automationComposition.getElements().size())).lock(any(), any(), any());
-        for (var element: automationComposition.getElements().values()) {
+        for (var element : automationComposition.getElements().values()) {
             assertEquals(LockState.LOCKING, element.getLockState());
         }
     }
@@ -130,7 +132,7 @@
         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
         verify(listener, times(automationComposition.getElements().size())).unlock(any(), any(), any());
-        for (var element: automationComposition.getElements().values()) {
+        for (var element : automationComposition.getElements().values()) {
             assertEquals(LockState.UNLOCKING, element.getLockState());
         }
     }
@@ -150,7 +152,7 @@
         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
         verify(listener, times(automationComposition.getElements().size())).delete(any(), any(), any());
-        for (var element: automationComposition.getElements().values()) {
+        for (var element : automationComposition.getElements().values()) {
             assertEquals(DeployState.DELETING, element.getDeployState());
         }
     }
@@ -241,8 +243,7 @@
     void restartedTest() {
         var listener = mock(ThreadHandler.class);
         var cacheProvider = mock(CacheProvider.class);
-        var ach = new AutomationCompositionHandler(cacheProvider, mock(ParticipantMessagePublisher.class),
-                listener);
+        var ach = new AutomationCompositionHandler(cacheProvider, mock(ParticipantMessagePublisher.class), listener);
 
         var compositionId = UUID.randomUUID();
         var messageId = UUID.randomUUID();
@@ -254,4 +255,32 @@
         verify(cacheProvider).initializeAutomationComposition(compositionId, participantRestartAc);
         verify(listener).restarted(messageId, compositionId, list, state, automationCompositionList);
     }
+
+    @Test
+    void handleAutomationCompositionMigrationTest() {
+        var listener = mock(ThreadHandler.class);
+        var cacheProvider = mock(CacheProvider.class);
+        var ach = new AutomationCompositionHandler(cacheProvider, mock(ParticipantMessagePublisher.class), listener);
+        var migrationMsg = new AutomationCompositionMigration();
+        assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(migrationMsg));
+        var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
+        migrationMsg.setCompositionTargetId(UUID.randomUUID());
+        migrationMsg.setAutomationCompositionId(automationComposition.getInstanceId());
+        assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(migrationMsg));
+        when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
+                .thenReturn(automationComposition);
+        var participantDeploy = new ParticipantDeploy();
+        participantDeploy.setParticipantId(CommonTestData.getParticipantId());
+        when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId());
+        migrationMsg.getParticipantUpdatesList().add(participantDeploy);
+        for (var element : automationComposition.getElements().values()) {
+            var acElementDeploy = new AcElementDeploy();
+            acElementDeploy.setProperties(Map.of());
+            acElementDeploy.setId(element.getId());
+            participantDeploy.getAcElementList().add(acElementDeploy);
+        }
+
+        ach.handleAutomationCompositionMigration(migrationMsg);
+        verify(listener, times(automationComposition.getElements().size())).migrate(any(), any(), any(), any(), any());
+    }
 }
diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandlerTest.java
index c45be4e..cbd236e 100755
--- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandlerTest.java
+++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandlerTest.java
@@ -22,6 +22,7 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -174,8 +175,7 @@
         var publisher = mock(ParticipantMessagePublisher.class);
         var acOutHandler = new AutomationCompositionOutHandler(publisher, cacheProvider);
         var compositionId = UUID.randomUUID();
-        acOutHandler.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.NO_ERROR,
-                "Primed");
+        acOutHandler.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.NO_ERROR, "Primed");
         verify(publisher).sendParticipantPrimeAck(any(ParticipantPrimeAck.class));
         verify(cacheProvider, times(0)).removeElementDefinition(compositionId);
     }
@@ -217,4 +217,29 @@
         acOutHandler.sendAcDefinitionInfo(compositionId, elementId, Map.of());
         verify(publisher).sendHeartbeat(any(ParticipantStatus.class));
     }
+
+    @Test
+    void updateMigrationStatusTest() {
+        var cacheProvider = mock(CacheProvider.class);
+        when(cacheProvider.getParticipantId()).thenReturn(UUID.randomUUID());
+        var publisher = mock(ParticipantMessagePublisher.class);
+        var acOutHandler = new AutomationCompositionOutHandler(publisher, cacheProvider);
+
+        var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
+        when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
+                .thenReturn(automationComposition);
+
+        var compositionTarget = UUID.randomUUID();
+        automationComposition.setCompositionTargetId(compositionTarget);
+        automationComposition.setDeployState(DeployState.MIGRATING);
+        when(cacheProvider.getAcElementsDefinitions()).thenReturn(Map.of(compositionTarget, Map.of()));
+
+        for (var element : automationComposition.getElements().values()) {
+            acOutHandler.updateAutomationCompositionElementState(automationComposition.getInstanceId(), element.getId(),
+                    DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "");
+        }
+        verify(publisher, times(automationComposition.getElements().size()))
+                .sendAutomationCompositionAck(any(AutomationCompositionDeployAck.class));
+        assertEquals(compositionTarget, automationComposition.getCompositionId());
+    }
 }
diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandlerTest.java
index c558e66..7a0b048 100755
--- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandlerTest.java
+++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandlerTest.java
@@ -37,6 +37,7 @@
 import org.onap.policy.clamp.models.acm.concepts.ParticipantDefinition;
 import org.onap.policy.clamp.models.acm.concepts.ParticipantSupportedElementType;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionMigration;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantAckMessage;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantDeregister;
@@ -57,8 +58,8 @@
     void handleParticipantStatusReqTest() {
         var publisher = mock(ParticipantMessagePublisher.class);
         var cacheProvider = mock(CacheProvider.class);
-        var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class),
-                mock(AutomationCompositionOutHandler.class), publisher, cacheProvider);
+        var participantHandler =
+                new ParticipantHandler(mock(AutomationCompositionHandler.class), publisher, cacheProvider);
         participantHandler.handleParticipantStatusReq(new ParticipantStatusReq());
         verify(publisher).sendParticipantStatus(any(ParticipantStatus.class));
     }
@@ -66,8 +67,8 @@
     @Test
     void handleAutomationCompositionDeployTest() {
         var acHandler = mock(AutomationCompositionHandler.class);
-        var participantHandler = new ParticipantHandler(acHandler, mock(AutomationCompositionOutHandler.class),
-                mock(ParticipantMessagePublisher.class), mock(CacheProvider.class));
+        var participantHandler =
+                new ParticipantHandler(acHandler, mock(ParticipantMessagePublisher.class), mock(CacheProvider.class));
         var automationCompositionDeploy = new AutomationCompositionDeploy();
         participantHandler.handleAutomationCompositionDeploy(automationCompositionDeploy);
         verify(acHandler).handleAutomationCompositionDeploy(automationCompositionDeploy);
@@ -76,18 +77,28 @@
     @Test
     void handleAutomationCompositionStateChangeTest() {
         var acHandler = mock(AutomationCompositionHandler.class);
-        var participantHandler = new ParticipantHandler(acHandler, mock(AutomationCompositionOutHandler.class),
-                mock(ParticipantMessagePublisher.class), mock(CacheProvider.class));
+        var participantHandler =
+                new ParticipantHandler(acHandler, mock(ParticipantMessagePublisher.class), mock(CacheProvider.class));
         var acStateChange = new AutomationCompositionStateChange();
         participantHandler.handleAutomationCompositionStateChange(acStateChange);
         verify(acHandler).handleAutomationCompositionStateChange(acStateChange);
     }
 
     @Test
+    void handleAutomationCompositionMigrationTest() {
+        var acHandler = mock(AutomationCompositionHandler.class);
+        var participantHandler =
+                new ParticipantHandler(acHandler, mock(ParticipantMessagePublisher.class), mock(CacheProvider.class));
+        var migrationMsg = new AutomationCompositionMigration();
+        participantHandler.handleAutomationCompositionMigration(migrationMsg);
+        verify(acHandler).handleAutomationCompositionMigration(migrationMsg);
+    }
+
+    @Test
     void handleAcPropertyUpdateTest() {
         var acHandler = mock(AutomationCompositionHandler.class);
-        var participantHandler = new ParticipantHandler(acHandler, mock(AutomationCompositionOutHandler.class),
-                mock(ParticipantMessagePublisher.class), mock(CacheProvider.class));
+        var participantHandler =
+                new ParticipantHandler(acHandler, mock(ParticipantMessagePublisher.class), mock(CacheProvider.class));
         var propertyUpdateMsg = new PropertiesUpdate();
         participantHandler.handleAcPropertyUpdate(propertyUpdateMsg);
         verify(acHandler).handleAcPropertyUpdate(propertyUpdateMsg);
@@ -98,7 +109,7 @@
         var cacheProvider = mock(CacheProvider.class);
         when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId());
         var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class),
-                mock(AutomationCompositionOutHandler.class), mock(ParticipantMessagePublisher.class), cacheProvider);
+                mock(ParticipantMessagePublisher.class), cacheProvider);
 
         var participantAckMsg = new ParticipantAckMessage(ParticipantMessageType.AUTOMATION_COMPOSITION_DEPLOY);
         assertTrue(participantHandler.appliesTo(participantAckMsg));
@@ -116,8 +127,8 @@
         var cacheProvider = mock(CacheProvider.class);
         when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId());
         when(cacheProvider.getSupportedAcElementTypes()).thenReturn(List.of(new ParticipantSupportedElementType()));
-        var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class),
-                mock(AutomationCompositionOutHandler.class), publisher, cacheProvider);
+        var participantHandler =
+                new ParticipantHandler(mock(AutomationCompositionHandler.class), publisher, cacheProvider);
 
         participantHandler.sendParticipantRegister();
         verify(publisher).sendParticipantRegister(any(ParticipantRegister.class));
@@ -128,8 +139,8 @@
         var publisher = mock(ParticipantMessagePublisher.class);
         var cacheProvider = mock(CacheProvider.class);
         when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId());
-        var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class),
-                mock(AutomationCompositionOutHandler.class), publisher, cacheProvider);
+        var participantHandler =
+                new ParticipantHandler(mock(AutomationCompositionHandler.class), publisher, cacheProvider);
 
         participantHandler.handleParticipantRegisterAck(new ParticipantRegisterAck());
         verify(publisher).sendParticipantStatus(any(ParticipantStatus.class));
@@ -140,8 +151,8 @@
         var publisher = mock(ParticipantMessagePublisher.class);
         var cacheProvider = mock(CacheProvider.class);
         when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId());
-        var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class),
-                mock(AutomationCompositionOutHandler.class), publisher, cacheProvider);
+        var participantHandler =
+                new ParticipantHandler(mock(AutomationCompositionHandler.class), publisher, cacheProvider);
 
         participantHandler.sendParticipantDeregister();
         verify(publisher).sendParticipantDeregister(any(ParticipantDeregister.class));
@@ -150,8 +161,7 @@
     @Test
     void handleParticipantDeregisterAckTest() {
         var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class),
-                mock(AutomationCompositionOutHandler.class), mock(ParticipantMessagePublisher.class),
-                mock(CacheProvider.class));
+                mock(ParticipantMessagePublisher.class), mock(CacheProvider.class));
         var participantDeregisterAck = new ParticipantDeregisterAck();
         assertDoesNotThrow(() -> participantHandler.handleParticipantDeregisterAck(participantDeregisterAck));
     }
@@ -168,8 +178,7 @@
 
         var publisher = mock(ParticipantMessagePublisher.class);
         var acHandler = mock(AutomationCompositionHandler.class);
-        var participantHandler = new ParticipantHandler(acHandler, mock(AutomationCompositionOutHandler.class),
-                publisher, cacheProvider);
+        var participantHandler = new ParticipantHandler(acHandler, publisher, cacheProvider);
 
         participantHandler.handleParticipantPrime(participantPrime);
         verify(cacheProvider).addElementDefinition(any(), any());
@@ -186,8 +195,7 @@
         var cacheProvider = mock(CacheProvider.class);
         var publisher = mock(ParticipantMessagePublisher.class);
         var acHandler = mock(AutomationCompositionHandler.class);
-        var participantHandler = new ParticipantHandler(acHandler, mock(AutomationCompositionOutHandler.class),
-                publisher, cacheProvider);
+        var participantHandler = new ParticipantHandler(acHandler, publisher, cacheProvider);
 
         participantHandler.handleParticipantRestart(participantRestartMsg);
         verify(cacheProvider).addElementDefinition(any(), any());
@@ -200,8 +208,7 @@
         when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId());
         var publisher = mock(ParticipantMessagePublisher.class);
         var acHandler = mock(AutomationCompositionHandler.class);
-        var participantHandler = new ParticipantHandler(acHandler, mock(AutomationCompositionOutHandler.class),
-                publisher, cacheProvider);
+        var participantHandler = new ParticipantHandler(acHandler, publisher, cacheProvider);
         var participantPrime = new ParticipantPrime();
         var compositionId = UUID.randomUUID();
         participantPrime.setCompositionId(compositionId);
@@ -218,8 +225,8 @@
         when(cacheProvider.getAutomationCompositions()).thenReturn(CommonTestData.getTestAutomationCompositionMap());
         var publisher = mock(ParticipantMessagePublisher.class);
         when(publisher.isActive()).thenReturn(true);
-        var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class),
-                mock(AutomationCompositionOutHandler.class), publisher, cacheProvider);
+        var participantHandler =
+                new ParticipantHandler(mock(AutomationCompositionHandler.class), publisher, cacheProvider);
         participantHandler.sendHeartbeat();
         verify(publisher).sendHeartbeat(any(ParticipantStatus.class));
     }
diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java
index 16334f5..2ac3c8d 100755
--- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java
+++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java
@@ -75,6 +75,11 @@
             verify(listener, timeout(TIMEOUT)).update(instanceId, element, properties);
 
             clearInvocations(listener);
+            var compositionTargetId = UUID.randomUUID();
+            threadHandler.migrate(messageId, instanceId, element, compositionTargetId, properties);
+            verify(listener, timeout(TIMEOUT)).migrate(instanceId, element, compositionTargetId, properties);
+
+            clearInvocations(listener);
             threadHandler.lock(messageId, instanceId, elementId);
             verify(listener, timeout(TIMEOUT)).lock(instanceId, elementId);