Introduce Instrumentation
[cps.git] / cps-ncmp-service / src / main / java / org / onap / cps / ncmp / api / impl / event / lcm / LcmEventsCmHandleStateHandlerImpl.java
index fd46ee8..6485fdf 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * Copyright (C) 2022-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.
@@ -25,7 +25,16 @@ import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED;
 import static org.onap.cps.ncmp.api.inventory.CmHandleState.LOCKED;
 import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY;
 
+import io.micrometer.core.annotation.Timed;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
 import lombok.RequiredArgsConstructor;
+import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
@@ -35,6 +44,7 @@ import org.onap.cps.ncmp.api.inventory.CompositeStateUtils;
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.ncmp.cmhandle.event.lcm.LcmEvent;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 @Slf4j
@@ -47,20 +57,113 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState
     private final LcmEventsService lcmEventsService;
 
     @Override
-    public void updateCmHandleState(final YangModelCmHandle yangModelCmHandle,
+    public void updateCmHandleState(final YangModelCmHandle updatedYangModelCmHandle,
             final CmHandleState targetCmHandleState) {
 
-        final CompositeState compositeState = yangModelCmHandle.getCompositeState();
+        final CompositeState compositeState = updatedYangModelCmHandle.getCompositeState();
 
-        if (compositeState != null && compositeState.getCmHandleState() == targetCmHandleState) {
-            log.debug("CmHandle with id : {} already in state : {}", yangModelCmHandle.getId(), targetCmHandleState);
+        if (isCompositeStateSame(compositeState, targetCmHandleState)) {
+            log.debug("CmHandle with id : {} already in state : {}", updatedYangModelCmHandle.getId(),
+                    targetCmHandleState);
         } else {
-            final NcmpServiceCmHandle existingNcmpServiceCmHandle =
-                    new NcmpServiceCmHandle(toNcmpServiceCmHandle(yangModelCmHandle));
-            updateToSpecifiedCmHandleState(yangModelCmHandle, targetCmHandleState);
-            final NcmpServiceCmHandle targetNcmpServiceCmHandle = toNcmpServiceCmHandle(yangModelCmHandle);
-            publishLcmEvent(targetNcmpServiceCmHandle, existingNcmpServiceCmHandle);
+            final YangModelCmHandle currentYangModelCmHandle = YangModelCmHandle.deepCopyOf(updatedYangModelCmHandle);
+            updateToSpecifiedCmHandleState(updatedYangModelCmHandle, targetCmHandleState);
+            persistCmHandle(updatedYangModelCmHandle, currentYangModelCmHandle);
+            publishLcmEventAsynchronously(toNcmpServiceCmHandle(updatedYangModelCmHandle),
+                    toNcmpServiceCmHandle(currentYangModelCmHandle));
         }
+    }
+
+    @Override
+    @Timed(value = "cps.ncmp.cmhandle.state.update.batch",
+        description = "Time taken to update a batch of cm handle states")
+    public void updateCmHandleStateBatch(final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle) {
+        final Collection<CmHandleTransitionPair> cmHandleTransitionPairs =
+                prepareCmHandleTransitionBatch(cmHandleStatePerCmHandle);
+        persistCmHandleBatch(cmHandleTransitionPairs);
+        publishLcmEventBatchAsynchronously(cmHandleTransitionPairs);
+    }
+
+    @Async("notificationExecutor")
+    @Override
+    public void publishLcmEventAsynchronously(final NcmpServiceCmHandle targetNcmpServiceCmHandle,
+            final NcmpServiceCmHandle currentNcmpServiceCmHandle) {
+        publishLcmEvent(targetNcmpServiceCmHandle, currentNcmpServiceCmHandle);
+    }
+
+    /**
+     * Publish LcmEvent in batches and in asynchronous manner.
+     *
+     * @param cmHandleTransitionPairs Pair of existing and modified cm handle represented as YangModelCmHandle
+     */
+    @Async("notificationExecutor")
+    public void publishLcmEventBatchAsynchronously(final Collection<CmHandleTransitionPair> cmHandleTransitionPairs) {
+        cmHandleTransitionPairs.forEach(cmHandleTransitionPair -> publishLcmEvent(
+                toNcmpServiceCmHandle(cmHandleTransitionPair.getTargetYangModelCmHandle()),
+                toNcmpServiceCmHandle(cmHandleTransitionPair.getCurrentYangModelCmHandle())));
+    }
+
+    private void publishLcmEvent(final NcmpServiceCmHandle targetNcmpServiceCmHandle,
+            final NcmpServiceCmHandle existingNcmpServiceCmHandle) {
+        final String cmHandleId = targetNcmpServiceCmHandle.getCmHandleId();
+        final LcmEvent lcmEvent =
+                lcmEventsCreator.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle);
+        lcmEventsService.publishLcmEvent(cmHandleId, lcmEvent);
+    }
+
+    private Collection<CmHandleTransitionPair> prepareCmHandleTransitionBatch(
+            final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle) {
+        final List<CmHandleTransitionPair> cmHandleTransitionPairs = new ArrayList<>(cmHandleStatePerCmHandle.size());
+        cmHandleStatePerCmHandle.forEach((yangModelCmHandle, targetCmHandleState) -> {
+
+            final CompositeState compositeState = yangModelCmHandle.getCompositeState();
+
+            if (isCompositeStateSame(compositeState, targetCmHandleState)) {
+                log.debug("CmHandle with id : {} already in state : {}", yangModelCmHandle.getId(),
+                        targetCmHandleState);
+            } else {
+                final CmHandleTransitionPair cmHandleTransitionPair = new CmHandleTransitionPair();
+                cmHandleTransitionPair.setCurrentYangModelCmHandle(YangModelCmHandle.deepCopyOf(yangModelCmHandle));
+                updateToSpecifiedCmHandleState(yangModelCmHandle, targetCmHandleState);
+                cmHandleTransitionPair.setTargetYangModelCmHandle(yangModelCmHandle);
+                cmHandleTransitionPairs.add(cmHandleTransitionPair);
+            }
+        });
+
+        return cmHandleTransitionPairs;
+    }
+
+
+    private void persistCmHandle(final YangModelCmHandle targetYangModelCmHandle,
+            final YangModelCmHandle currentYangModelCmHandle) {
+        if (isNew(currentYangModelCmHandle.getCompositeState(), targetYangModelCmHandle.getCompositeState())) {
+            log.debug("Registering a new cm handle {}", targetYangModelCmHandle.getId());
+            inventoryPersistence.saveCmHandle(targetYangModelCmHandle);
+        } else if (isDeleted(targetYangModelCmHandle.getCompositeState())) {
+            log.info("CmHandle with Id : {} is DELETED", targetYangModelCmHandle.getId());
+        } else {
+            inventoryPersistence.saveCmHandleState(targetYangModelCmHandle.getId(),
+                    targetYangModelCmHandle.getCompositeState());
+        }
+    }
+
+    private void persistCmHandleBatch(final Collection<CmHandleTransitionPair> cmHandleTransitionPairs) {
+
+        final List<YangModelCmHandle> newCmHandles = new ArrayList<>();
+        final Map<String, CompositeState> compositeStatePerCmHandleId = new LinkedHashMap<>();
+
+        cmHandleTransitionPairs.forEach(cmHandleTransitionPair -> {
+            if (isNew(cmHandleTransitionPair.getCurrentYangModelCmHandle().getCompositeState(),
+                    cmHandleTransitionPair.getTargetYangModelCmHandle().getCompositeState())) {
+                newCmHandles.add(cmHandleTransitionPair.getTargetYangModelCmHandle());
+            } else if (!isDeleted(cmHandleTransitionPair.getTargetYangModelCmHandle().getCompositeState())) {
+                compositeStatePerCmHandleId.put(cmHandleTransitionPair.getTargetYangModelCmHandle().getId(),
+                        cmHandleTransitionPair.getTargetYangModelCmHandle().getCompositeState());
+            }
+        });
+
+        inventoryPersistence.saveCmHandleBatch(newCmHandles);
+        inventoryPersistence.saveCmHandleStateBatch(compositeStatePerCmHandleId);
 
     }
 
@@ -68,52 +171,57 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState
             final CmHandleState targetCmHandleState) {
 
         if (READY == targetCmHandleState) {
-            CompositeStateUtils.setCompositeStateToReadyWithInitialDataStoreSyncState()
-                    .accept(yangModelCmHandle.getCompositeState());
-            inventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState());
+            setInitialStates(yangModelCmHandle);
         } else if (ADVISED == targetCmHandleState) {
             if (yangModelCmHandle.getCompositeState() == null) {
                 registerNewCmHandle(yangModelCmHandle);
             } else if (yangModelCmHandle.getCompositeState().getCmHandleState() == LOCKED) {
                 retryCmHandle(yangModelCmHandle);
             }
-        } else if (DELETED == targetCmHandleState) {
-            setCmHandleState(yangModelCmHandle, targetCmHandleState);
         } else {
-            updateAndSaveCmHandleState(yangModelCmHandle, targetCmHandleState);
+            setCmHandleState(yangModelCmHandle, targetCmHandleState);
         }
     }
 
+    private void setInitialStates(final YangModelCmHandle yangModelCmHandle) {
+        CompositeStateUtils.setInitialDataStoreSyncState().accept(yangModelCmHandle.getCompositeState());
+        CompositeStateUtils.setCompositeState(READY).accept(yangModelCmHandle.getCompositeState());
+    }
+
     private void retryCmHandle(final YangModelCmHandle yangModelCmHandle) {
         CompositeStateUtils.setCompositeStateForRetry().accept(yangModelCmHandle.getCompositeState());
-        inventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState());
     }
 
     private void registerNewCmHandle(final YangModelCmHandle yangModelCmHandle) {
         yangModelCmHandle.setCompositeState(new CompositeState());
         setCmHandleState(yangModelCmHandle, ADVISED);
-        inventoryPersistence.saveCmHandle(yangModelCmHandle);
     }
 
-    private void publishLcmEvent(final NcmpServiceCmHandle targetNcmpServiceCmHandle,
-            final NcmpServiceCmHandle existingNcmpServiceCmHandle) {
-        final String cmHandleId = targetNcmpServiceCmHandle.getCmHandleId();
-        final LcmEvent lcmEvent =
-                lcmEventsCreator.populateLcmEvent(cmHandleId, targetNcmpServiceCmHandle, existingNcmpServiceCmHandle);
-        lcmEventsService.publishLcmEvent(cmHandleId, lcmEvent);
+    private void setCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState targetCmHandleState) {
+        CompositeStateUtils.setCompositeState(targetCmHandleState).accept(yangModelCmHandle.getCompositeState());
     }
 
-    private void updateAndSaveCmHandleState(final YangModelCmHandle yangModelCmHandle,
-            final CmHandleState targetCmHandleState) {
-        setCmHandleState(yangModelCmHandle, targetCmHandleState);
-        inventoryPersistence.saveCmHandleState(yangModelCmHandle.getId(), yangModelCmHandle.getCompositeState());
+    private boolean isNew(final CompositeState existingCompositeState, final CompositeState targetCompositeState) {
+        return (existingCompositeState == null && targetCompositeState.getCmHandleState() == ADVISED);
     }
 
-    private void setCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState targetCmHandleState) {
-        CompositeStateUtils.setCompositeState(targetCmHandleState).accept(yangModelCmHandle.getCompositeState());
+    private boolean isDeleted(final CompositeState targetCompositeState) {
+        return targetCompositeState.getCmHandleState() == DELETED;
+    }
+
+    private boolean isCompositeStateSame(final CompositeState compositeState, final CmHandleState targetCmHandleState) {
+        return (compositeState != null && compositeState.getCmHandleState() == targetCmHandleState);
     }
 
     private NcmpServiceCmHandle toNcmpServiceCmHandle(final YangModelCmHandle yangModelCmHandle) {
         return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle);
     }
+
+    @Getter
+    @Setter
+    @NoArgsConstructor
+    static class CmHandleTransitionPair {
+        private YangModelCmHandle currentYangModelCmHandle;
+        private YangModelCmHandle targetYangModelCmHandle;
+    }
 }