[SLICEMS] Add bw decrease logics and enhance runtime config feature

Add closed loop assurance decrease bw logics. Add a thread transfers
latest data from cbs client configs to corresponding value. Add runtime
configuration function. Fix the bug that cll service info didn't get updated when a cll service is deleted.

Issue-ID: DCAEGEN2-3240
Issue-ID: DCAEGEN2-3264
Issue-ID: DCAEGEN2-3255
Issue-ID: DCAEGEN2-3238
Signed-off-by: qingshuting <qingshuting1@huawei.com>
Change-Id: Id611d10973fca1e1715e9e220819dfcf51bbd1ba
diff --git a/components/slice-analysis-ms/ChangeLog.md b/components/slice-analysis-ms/ChangeLog.md
index f3152d3..0796670 100644
--- a/components/slice-analysis-ms/ChangeLog.md
+++ b/components/slice-analysis-ms/ChangeLog.md
@@ -4,13 +4,21 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
-## [1.1.5] - 2022/08/27
+## [1.1.5] - 2022/09/14
          - [DCAEGEN2-3221](https://jira.onap.org/browse/DCAEGEN2-3221) - Slice-Analysis-Ms vulnerability updates
 
          - [DCAEGEN2-3195](https://jira.onap.org/browse/DCAEGEN2-3195) - CCVPN Kohn Enhancements for Intent-based Cloud Leased Line and Transport Slicing
 
          - [DCAEGEN2-3239](https://jira.onap.org/browse/DCAEGEN2-3239) - Enhance BandwidthEvaluator to listen on user's bandwidth threshold
 
+         - [DCAEGEN2-3238](https://jira.onap.org/browse/DCAEGEN2-3238) - Enhance BandwidthEvaluator in slice-analysis-ms to support detailed bandwidth adjustment
+
+         - [DCAEGEN2-3255](https://jira.onap.org/browse/DCAEGEN2-3255) - Fix bug of application failed to start
+
+         - [DCAEGEN2-3264](https://jira.onap.org/browse/DCAEGEN2-3264) - Fix bug that cll service instance info didn't get updated when a cll service is deleted
+    
+         - [DCAEGEN2-3240](https://jira.onap.org/browse/DCAEGEN2-3240) - Implement runtime service configuration
+
 ## [1.1.4] - 2022/07/28
          - [DCAEGEN2-3120](https://jira.onap.org/browse/DCAEGEN2-3120) - Enhance sliceanalysis MS to use DCAE SDK dmaap-client lib
 
diff --git a/components/slice-analysis-ms/pom.xml b/components/slice-analysis-ms/pom.xml
index 3b2cfcd..15ae6ed 100644
--- a/components/slice-analysis-ms/pom.xml
+++ b/components/slice-analysis-ms/pom.xml
@@ -7,6 +7,7 @@
  *  Copyright (C) 2020-2022 Wipro Limited.
  *  Copyright (C) 2022 Huawei Canada Limited.
  *  Copyright (C) 2022 CTC, Inc.
+ *  Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *  ================================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -316,7 +317,7 @@
                 <dependency>
                         <groupId>org.apache.tomcat.embed</groupId>
                         <artifactId>tomcat-embed-core</artifactId>
-                        <version>10.0.21</version>
+                        <version>9.0.65</version>
                 </dependency>
                 <!-- https://mvnrepository.com/artifact/nl.jqno.equalsverifier/equalsverifier -->
                 <dependency>
diff --git a/components/slice-analysis-ms/src/main/docker/config/sliceanalysisms/config_all.json b/components/slice-analysis-ms/src/main/docker/config/sliceanalysisms/config_all.json
index 12e9d08..9e23353 100644
--- a/components/slice-analysis-ms/src/main/docker/config/sliceanalysisms/config_all.json
+++ b/components/slice-analysis-ms/src/main/docker/config/sliceanalysisms/config_all.json
@@ -106,11 +106,12 @@
     "sliceanalysisms.aaiNotif.targetSource" : "UUI",
     "sliceanalysisms.aaiNotif.targetEntity" : "service-instance",
     "sliceanalysisms.ccvpnEvalInterval": 5,
-    "sliceanalysisms.ccvpnEvalThreshold": 0.8,
     "sliceanalysisms.ccvpnEvalPrecision": 100.0,
     "sliceanalysisms.ccvpnEvalPeriodicCheckOn": true,
     "sliceanalysisms.ccvpnEvalOnDemandCheckOn": true,
     "sliceanalysisms.ccvpnEvalStrategy" : "FlexibleThresholdStrategy",
+    "sliceanalysisms.ccvpnEvalUpperThreshold": 0.8,
+    "sliceanalysisms.ccvpnEvalLowerThreshold": 0.3,
     "service_calls": {
       "policy-req": []
     },
diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/MainThread.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/MainThread.java
index 57a831e..4456663 100644
--- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/MainThread.java
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/MainThread.java
@@ -1,51 +1,55 @@
 /*******************************************************************************
  *  ============LICENSE_START=======================================================
- *  son-handler
+ *  slice-analysis-ms
  *  ================================================================================
  *   Copyright (C) 2019-2020 Wipro Limited.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *   ==============================================================================
  *     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.
  *     ============LICENSE_END=========================================================
- *  
+ *
  *******************************************************************************/
 
 package org.onap.slice.analysis.ms;
 
+import org.onap.slice.analysis.ms.service.ConfigThread;
 import org.onap.slice.analysis.ms.service.ConsumerThread;
 import org.onap.slice.analysis.ms.service.PmThread;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/** 
+/**
  * This class starts the pm thread and consumer thread
  */
 public class MainThread {
 
-	private static Logger log = LoggerFactory.getLogger(MainThread.class);
-	
-	private MainThread() {
-		
-	}
-	
-	/**
-	 * main thread initialization.
-	 */
-	public static void initiateThreads() {
-		log.debug("initializing Pm thread & Consumer thread");
-		Thread pmThread = new Thread(new PmThread());
-		pmThread.start();
-		Thread consumerThread = new Thread(new ConsumerThread());
-		consumerThread.start();
-	}
+    private static Logger log = LoggerFactory.getLogger(MainThread.class);
+
+    private MainThread() {
+
+    }
+
+    /**
+     * main thread initialization.
+    */
+    public static void initiateThreads() {
+        log.debug("initializing Pm thread & Consumer thread");
+        Thread pmThread = new Thread(new PmThread());
+        pmThread.start();
+        Thread consumerThread = new Thread(new ConsumerThread());
+        consumerThread.start();
+        Thread configThread = new Thread(new ConfigThread());
+        configThread.start();
+    }
 
 }
diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/aai/AaiService.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/aai/AaiService.java
index 9459b64..b68373d 100644
--- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/aai/AaiService.java
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/aai/AaiService.java
@@ -4,6 +4,7 @@
  *  ================================================================================
  *   Copyright (C) 2021-2022 Wipro Limited.
  *   Copyright (C) 2022 Huawei Canada Limited.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *   ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -26,10 +27,12 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
+import java.util.Set;
 import org.json.JSONArray;
 import org.json.JSONObject;
 import org.onap.slice.analysis.ms.models.Configuration;
@@ -111,6 +114,39 @@
     }
 
     /**
+     * fetch all valid cll instances
+     * @return
+     */
+    public Set<String> fetchAllCllInstances() {
+        globalSubscriberId = "IBNCustomer";
+        subscriptionServiceType = "IBN";
+        String serviceReqUrl = aaiBaseUrl + "/business/customers/customer/" + globalSubscriberId
+            + "/service-subscriptions/service-subscription/" + subscriptionServiceType + "/service-instances";
+        log.info("serviceReqUrl {}", serviceReqUrl);
+        Set<String> cllInstances = new HashSet<>();
+        try {
+            String serviceInstance =
+                restclient.sendGetRequest(serviceReqUrl, new ParameterizedTypeReference<String>() {}).getBody();
+            log.debug("The service instance response msg are :{}", serviceInstance);
+            JSONObject serviceInstanceJson = new JSONObject(serviceInstance);
+            JSONArray serviceInstanceArray = serviceInstanceJson.getJSONArray("service-instance");
+            for (int i = 0; i < serviceInstanceArray.length(); i++) {
+                JSONObject serviceObj = serviceInstanceArray.getJSONObject(i);
+                String serviceId = serviceObj.getString("service-instance-id");
+                log.debug("Jsonobject {}", serviceObj);
+                if(serviceId.startsWith("cll")){
+                    cllInstances.add(serviceId);
+                    log.debug("Add {} to latest service id list", serviceId);
+                }
+            }
+            return cllInstances;
+        } catch (Exception e) {
+            log.error("Exception while fetching serviceDetails: " + e);
+        }
+        return new HashSet<>();
+    }
+
+    /**
      * Fetches the current configuration of a Slice from AAI
      *
      * @param snssai SNSSAI ID
@@ -210,7 +246,7 @@
     /**
      * Fetches the SNSSIs of a serviceInstanceId
      *
-     * @param serviceInstanceId service instance ID
+     * @param sliceInstanceId service instance ID
      * @return snssaiList contains list of SNSSAIs
      */
     public List<String> getSnssaiList(String sliceInstanceId) {
diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/controller/ConfigFetchFromCbs.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/controller/ConfigFetchFromCbs.java
index 2bdb050..e69d45f 100644
--- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/controller/ConfigFetchFromCbs.java
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/controller/ConfigFetchFromCbs.java
@@ -97,8 +97,8 @@
 
                 Type mapType = new TypeToken<Map<String, Object>>() {
                 }.getType();
-
                 if (jsonObject.getAsJsonObject("policies") != null) {
+                    log.info("Policy file exist");
                     if(jsonObject.getAsJsonObject("policies").getAsJsonArray("items").size() == 0) {
                         log.error("No policy in policy drool pdp engine, nothing to update.");
                     } else {
diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallback.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallback.java
index 584da7b..4b880e3 100644
--- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallback.java
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallback.java
@@ -3,6 +3,7 @@
  *  slice-analysis-ms
  *  ================================================================================
  *  Copyright (C) 2022 Huawei Canada Limited.
+ *  Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *  ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -21,9 +22,10 @@
 
 package org.onap.slice.analysis.ms.dmaap;
 
-import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.Set;
+import org.onap.slice.analysis.ms.aai.AaiService;
 import org.onap.slice.analysis.ms.models.Configuration;
 import org.onap.slice.analysis.ms.models.vesnotification.NotificationFields;
 
@@ -51,6 +53,9 @@
     @Autowired
     CCVPNPmDatastore ccvpnPmDatastore;
 
+    @Autowired
+    AaiService aaiService;
+
     private static Logger log = LoggerFactory.getLogger(VesNotificationCallback.class);
 
     /**
@@ -86,6 +91,7 @@
         String uniId = null;
         String bw = null;
         try {
+            updateCllInstance();
             JsonNode node = obj.readTree(msg);
             JsonNode notificationNode = node.get(EVENT).get(NOTIFICATIONFIELDS);
             output = obj.treeToValue(notificationNode, NotificationFields.class);
@@ -104,11 +110,18 @@
             log.error("Error converting VES msg to object, {}", e.getMessage());
         }
         if (cllId != null && uniId != null && bw != null){
-            log.info("Saving new CCVPN service usage data into ccvpnPmDatastore");
             log.debug("new bandwidth data -- serviceId: {}, uniId: {}, bw: {}", cllId, uniId, bw);
             ccvpnPmDatastore.addUsedBwToEndpoint(cllId, uniId, bw);
         }
+    }
 
+    /**
+     * Get latest services list, and update local related variables.
+     */
+    public void updateCllInstance(){
+        Set<String> instances = aaiService.fetchAllCllInstances();
+        log.error("instances {}", instances);
+        ccvpnPmDatastore.updateCllInstances(instances);
     }
 
 }
diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/models/Configuration.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/models/Configuration.java
index 4b5fe2e..c159951 100644
--- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/models/Configuration.java
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/models/Configuration.java
@@ -4,6 +4,7 @@
  *  ================================================================================
  *   Copyright (C) 2020-2022 Wipro Limited.
  *   Copyright (C) 2022 Huawei Canada Limited.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *   ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -69,12 +70,12 @@
     private String rannfnssiDetailsTemplateId;
     private String desUrl;
     private int pmDataDurationInWeeks;
-
     private int vesNotifPollingInterval;
     private String vesNotifChangeIdentifier;
     private String vesNotifChangeType;
     private int ccvpnEvalInterval;
-    private double ccvpnEvalThreshold;
+    private double ccvpnEvalUpperThreshold;
+    private double ccvpnEvalLowerThreshold;
     private double ccvpnEvalPrecision;
     private String aaiNotifTargetAction;
     private String aaiNotifTargetSource;
@@ -108,15 +109,21 @@
 
     @Override
     public String toString() {
-        return "Configuration [pgHost=" + pgHost + ", pgPort=" + pgPort + ", pgUsername=" + pgUsername + ", pgPassword="
-                + pgPassword + ", dmaapServers=" + dmaapServers + ", configDbService=" + configDbService + ", cpsUrl="
-                + cpsUrl + ", aaiUrl=" + aaiUrl + ", configDbEnabled=" + configDbEnabled + ", cg=" + cg + ", cid=" + cid
-                + ", pollingInterval=" + pollingInterval + ", pollingTimeout=" + pollingTimeout + ", aafUsername="
-                + aafUsername + ", aafPassword=" + aafPassword + ", streamsSubscribes=" + streamsSubscribes
-                + ", streamsPublishes=" + streamsPublishes + ", samples=" + samples + ", minPercentageChange="
-                + minPercentageChange + ", initialDelaySeconds=" + initialDelaySeconds + ", rannfnssiDetailsTemplateId="
-                + rannfnssiDetailsTemplateId + ", desUrl=" + desUrl + ", pmDataDurationInWeeks=" + pmDataDurationInWeeks
-                + "]";
+        return "Configuration [pgHost=" + pgHost + ", pgPort=" + pgPort + ", pgUsername=" + pgUsername +
+            ", dmaapServers=" + dmaapServers + ", configDbService=" + configDbService + ", cpsUrl="
+            + cpsUrl + ", aaiUrl=" + aaiUrl + ", configDbEnabled=" + configDbEnabled + ", cg=" + cg + ", cid=" + cid
+            + ", pollingInterval=" + pollingInterval + ", pollingTimeout=" + pollingTimeout + ", aafUsername="
+            + aafUsername + ", streamsSubscribes=" + streamsSubscribes
+            + ", streamsPublishes=" + streamsPublishes + ", samples=" + samples + ", minPercentageChange="
+            + minPercentageChange + ", initialDelaySeconds=" + initialDelaySeconds + ", rannfnssiDetailsTemplateId="
+            + rannfnssiDetailsTemplateId + ", desUrl=" + desUrl + ", pmDataDurationInWeeks=" + pmDataDurationInWeeks
+            + ", vesNotifPollingInterval=" + vesNotifPollingInterval + ", vesNotifChangeIdentifier="
+            + vesNotifChangeIdentifier + ", vesNotifChangeIdentifier=" + vesNotifChangeType + ", ccvpnEvalInterval=" +
+            ccvpnEvalInterval + ", ccvpnEvalUpperThreshold=" + ccvpnEvalUpperThreshold + ", ccvpnEvalLowerThreshold=" +
+            ccvpnEvalLowerThreshold + ", ccvpnEvalPrecision=" + ccvpnEvalPrecision + ", aaiNotifTargetAction=" +
+            aaiNotifTargetAction + ", aaiNotifTargetSource=" + aaiNotifTargetSource + ", aaiNotifTargetEntity=" +
+            aaiNotifTargetEntity + ", ccvpnEvalPeriodicCheckOn=" + ccvpnEvalPeriodicCheckOn +
+            ", ccvpnEvalOnDemandCheckOn=" + ccvpnEvalOnDemandCheckOn + ", ccvpnEvalStrategy=" + ccvpnEvalStrategy + "]";
     }
 
     /**
@@ -126,7 +133,8 @@
 
         log.info("Updating configuration from CBS");
 
-        Type mapType = new TypeToken<Map<String, Object>>() {}.getType();
+        Type mapType = new TypeToken<Map<String, Object>>() {
+        }.getType();
 
         JsonObject subscribes = jsonObject.getAsJsonObject("streams_subscribes");
         streamsSubscribes = new Gson().fromJson(subscribes, mapType);
@@ -141,7 +149,8 @@
         pgHost = jsonObject.get("postgres.host").getAsString();
 
         JsonArray servers = jsonObject.getAsJsonArray("sliceanalysisms.dmaap.server");
-        Type listType = new TypeToken<List<String>>() {}.getType();
+        Type listType = new TypeToken<List<String>>() {
+        }.getType();
         dmaapServers = new Gson().fromJson(servers, listType);
 
         cg = jsonObject.get("sliceanalysisms.cg").getAsString();
@@ -165,7 +174,8 @@
         aaiNotifTargetSource = jsonObject.get("sliceanalysisms.aaiNotif.targetSource").getAsString();
         aaiNotifTargetEntity = jsonObject.get("sliceanalysisms.aaiNotif.targetEntity").getAsString();
         ccvpnEvalInterval = jsonObject.get("sliceanalysisms.ccvpnEvalInterval").getAsInt();
-        ccvpnEvalThreshold = jsonObject.get("sliceanalysisms.ccvpnEvalThreshold").getAsDouble();
+        ccvpnEvalUpperThreshold = jsonObject.get("sliceanalysisms.ccvpnEvalUpperThreshold").getAsDouble();
+        ccvpnEvalLowerThreshold = jsonObject.get("sliceanalysisms.ccvpnEvalLowerThreshold").getAsDouble();
         ccvpnEvalPrecision = jsonObject.get("sliceanalysisms.ccvpnEvalPrecision").getAsDouble();
         ccvpnEvalPeriodicCheckOn = jsonObject.get("sliceanalysisms.ccvpnEvalPeriodicCheckOn").getAsBoolean();
         ccvpnEvalOnDemandCheckOn = jsonObject.get("sliceanalysisms.ccvpnEvalOnDemandCheckOn").getAsBoolean();
@@ -191,6 +201,6 @@
         } else {
             cpsUrl = jsonObject.get("sliceanalysisms.cps.url").getAsString();
         }
-        log.info("configuration from CBS {}", this);
+        log.info("configuration from CBS has been updated to {}", this);
     }
 }
diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ConfigThread.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ConfigThread.java
new file mode 100644
index 0000000..61e445d
--- /dev/null
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ConfigThread.java
@@ -0,0 +1,77 @@
+/*******************************************************************************

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

+ *  slice-analysis-ms

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

+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.

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

+ *     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.

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

+ *

+ *******************************************************************************/

+

+package org.onap.slice.analysis.ms.service;

+

+import org.onap.slice.analysis.ms.models.ConfigPolicy;

+import org.onap.slice.analysis.ms.service.ccvpn.CCVPNPmDatastore;

+import org.onap.slice.analysis.ms.utils.SpringContextUtil;

+import org.slf4j.Logger;

+import org.slf4j.LoggerFactory;

+

+/**

+ * This thread is used to convert ccvpn runtime configurations from policy to our local memory CCVPNPmDatastore

+ */

+public class ConfigThread extends Thread{

+

+    CCVPNPmDatastore ccvpnPmDatastore = (CCVPNPmDatastore) SpringContextUtil.getBean(CCVPNPmDatastore.class);

+    private static Logger log = LoggerFactory.getLogger(ConfigThread.class);

+

+

+    public ConfigThread () {

+        super();

+    }

+

+    public void run() {

+        log.info("Config Thread is starting...");

+        boolean done = false;

+        while(!done) {

+            try {

+                Thread.sleep(1000);

+                ConfigPolicy configPolicy = ConfigPolicy.getInstance();

+                if(configPolicy != null) {

+                    // config content

+                    String cllId = null;

+                    Boolean clBwAssuranceStatus = null;

+                    int originalBw = 0;

+                    if(configPolicy.getConfig().containsKey("cllId")){

+                        cllId = String.valueOf(configPolicy.getConfig().get("cllId"));

+                    }

+                    if(configPolicy.getConfig().containsKey("closedLoopStatus")){

+                        clBwAssuranceStatus = String.valueOf(configPolicy.getConfig().get("closedLoopStatus")).equalsIgnoreCase("true");

+                    }

+                    if(configPolicy.getConfig().containsKey("originalBw")){

+                        originalBw = Integer.parseInt(String.valueOf(configPolicy.getConfig().get("originalBw")));

+                    }

+                    if(cllId!=null && clBwAssuranceStatus!=null){

+                        ccvpnPmDatastore.updateConfigFromPolicy(cllId, clBwAssuranceStatus, originalBw);

+                    }

+                } else {

+                    log.debug("Config policy is empty, nothing to update.");

+                }

+

+            } catch (Exception e) {

+                log.error("Exception in Config Thread ", e);

+                done = true;

+            }

+        }

+    }

+}

diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/BandwidthEvaluator.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/BandwidthEvaluator.java
index 4339180..7ca100d 100644
--- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/BandwidthEvaluator.java
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/BandwidthEvaluator.java
@@ -3,6 +3,7 @@
  *  slice-analysis-ms
  *  ================================================================================
  *   Copyright (C) 2022 Huawei Canada Limited.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *  ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -64,7 +65,6 @@
     private static final Event KILL_PILL = new SimpleEvent(null, 0);
     private static final int DEFAULT_EVAL_INTERVAL = 5;
     private static final String DEFAULT_STRATEGY_NAME = "FixedUpperBoundStrategy";
-
     /**
      * Interval of each round of evaluation, defined in config_all.json
      */
@@ -86,6 +86,7 @@
         strategyName = (strategyName != null)? strategyName : DEFAULT_STRATEGY_NAME;
         evaluationInterval = (evaluationInterval == 0)? DEFAULT_EVAL_INTERVAL : evaluationInterval;
         EvaluationStrategy strategy = strategyFactory.getStrategy(strategyName);
+        log.info("{} is utilized as the bandwidth evaluatior strategy", strategyName);
 
         /**
          * Evalution main loop
@@ -117,6 +118,7 @@
                             log.info("Service modification complete; serviceId: {} with new bandwidth: {}", serviceId, bwValue);
                             ccvpnPmDatastore.updateProvBw(serviceId, bwValue, true);
                             ccvpnPmDatastore.updateSvcState(serviceId, ServiceState.RUNNING);
+                            log.debug("Service state of {} is changed to running", serviceId);
                         }
                     }
                     log.debug("=== Processing AAI network policy query complete ===");
@@ -160,7 +162,7 @@
      * @param event event object
      */
     public void post(@NonNull Event event){
-        log.debug("A new event triggered, type: {}, subject: {}, at time: {}",
+        log.info("A new event triggered, type: {}, subject: {}, at time: {}",
                 event.type(), event.subject(), event.time());
         if (event.type() == SimpleEvent.Type.AAI_BW_REQ) {
             aaiEventLoop.add(event);
@@ -171,10 +173,12 @@
         }
     }
 
+    // update configuration
     private void loadConfig() {
         configuration = Configuration.getInstance();
         evaluationInterval = configuration.getCcvpnEvalInterval();
         strategyName = configuration.getCcvpnEvalStrategy();
+        log.info("Evaluation loop configs has been loaded. Strategy {}.", strategyName);
     }
 
     /**
diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastore.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastore.java
index 6d9b960..5f3ce31 100644
--- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastore.java
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastore.java
@@ -3,6 +3,7 @@
  *  slice-analysis-ms
  *  ================================================================================
  *   Copyright (C) 2022 Huawei Canada Limited.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *  ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -20,6 +21,11 @@
  *******************************************************************************/
 package org.onap.slice.analysis.ms.service.ccvpn;
 
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import lombok.Getter;
+import lombok.Setter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
@@ -42,13 +48,23 @@
     private static Logger log = LoggerFactory.getLogger(CCVPNPmDatastore.class);
     private static final Pattern pattern = Pattern.compile("([0-9.]+)\\s*(kb|Kb|mb|Mb|Gb|gb)*");
     private static final int WINDOW_SIZE = 5;
+    @Getter
     private final ConcurrentMap<String, ServiceState> svcStatus = new ConcurrentHashMap<>();
     // Provisioned bandwidth of each endpoint
+    @Getter
     private final ConcurrentMap<String, Integer> endpointToProvBw = new ConcurrentHashMap<>();
     // Max bandwidth (upper-bound) of each endpoint
+    @Getter
     private final ConcurrentMap<String, Integer> upperBoundBw = new ConcurrentHashMap<>();
     // Current bandwidth usage data list from customers
+    @Getter
     private final ConcurrentMap<Endpointkey, EvictingQueue<Integer>> endpointToUsedBw = new ConcurrentHashMap<>();
+    // Original bandwidth of each endpoint
+    @Getter
+    private final ConcurrentMap<String, Integer> endpointToOriginalBw = new ConcurrentHashMap<>();
+    // Assurance Status of each endpoint
+    @Getter
+    private final ConcurrentMap<String, Boolean> closedLoopBwAssuranceStatus = new ConcurrentHashMap<>();
 
     /**
      * Given a cllId, return a map between Endpointkey and their corresponding UsedBw Queue.
@@ -88,11 +104,30 @@
         return svcStatus.getOrDefault(cllId, ServiceState.UNKNOWN);
     }
 
+    /**
+     * If ccvpn flexible threshold is on, then bandwidth can be assured within scope.
+     * @param cllId
+     * @return
+     */
     public Integer getUpperBoundBwOfSvc(String cllId){
         return upperBoundBw.getOrDefault(cllId, Integer.MAX_VALUE);
     }
 
     /**
+     * Get closed loop check status of this cll service
+     * @param cllId
+     * @return
+     */
+    public Boolean getClosedloopStatus(String cllId){
+        return closedLoopBwAssuranceStatus.getOrDefault(cllId,true);
+    }
+
+    public int getOriginalBw(String cllId) {
+        return endpointToOriginalBw.getOrDefault(cllId, 0);
+    }
+
+
+    /**
      * return the complete map of cll service status
      * @return complete map of serviceStatusMap
      */
@@ -121,6 +156,35 @@
     }
 
     /**
+     * Update the status, whether close loop bw modification of this cll service is on.
+     * @param cllId
+     * @param status
+     */
+    public void updateClosedloopStatus(String cllId, Boolean status){
+        closedLoopBwAssuranceStatus.put(cllId, status);
+    }
+
+    /**
+     * Update cll original bw, which will not influenced by closed loop bw assurance
+     * @param cllId
+     * @param originalBw
+     */
+    public void updateOriginalBw(String cllId, int originalBw){
+        endpointToOriginalBw.put(cllId, originalBw);
+    }
+
+    /**
+     * Update runtime configurations;
+     * @param cllId
+     * @param closedLoopBwAssuranceStatus
+     * @param originalBw
+     */
+    public void updateConfigFromPolicy(String cllId, Boolean closedLoopBwAssuranceStatus, int originalBw) {
+        updateClosedloopStatus(cllId, closedLoopBwAssuranceStatus);
+        updateOriginalBw(cllId, originalBw);
+    }
+
+    /**
      * Update upper bound bandwidth value to given bandwidth
      * @param cllId target cll instance id
      * @param bw new bandwidth
@@ -130,6 +194,47 @@
     }
 
     /**
+     * Update local service related variables in case cll is deleted.
+     * @param allValidCllInstances
+     */
+    public void updateCllInstances(Set<String> allValidCllInstances){
+        Set<String> invalidCllIds;
+        invalidCllIds= filterInvalidCllIds(allValidCllInstances, svcStatus.keySet());
+        svcStatus.keySet().removeAll(invalidCllIds);
+        invalidCllIds = filterInvalidCllIds(allValidCllInstances, endpointToProvBw.keySet());
+        endpointToProvBw.keySet().removeAll(invalidCllIds);
+        invalidCllIds = filterInvalidCllIds(allValidCllInstances, upperBoundBw.keySet());
+        upperBoundBw.keySet().removeAll(invalidCllIds);
+        invalidCllIds = filterInvalidCllIds(allValidCllInstances, endpointToOriginalBw.keySet());
+        endpointToOriginalBw.keySet().removeAll(invalidCllIds);
+        invalidCllIds = filterInvalidCllIds(allValidCllInstances, closedLoopBwAssuranceStatus.keySet());
+        closedLoopBwAssuranceStatus.keySet().removeAll(invalidCllIds);
+        for(String invalidCllId : invalidCllIds) {
+            log.debug("drop {} from endpointToUsedBw", invalidCllId);
+            endpointToUsedBw.entrySet().stream().dropWhile(map -> map.getKey().getCllId().equalsIgnoreCase(invalidCllId));
+            Iterator<Map.Entry<Endpointkey, EvictingQueue<Integer>>> iterator = endpointToUsedBw.entrySet().iterator();
+            while(iterator.hasNext()) {
+                Endpointkey endpointkey = iterator.next().getKey();
+                if(endpointkey.getCllId().equalsIgnoreCase(invalidCllId)) {
+                    endpointToUsedBw.remove(endpointkey);
+                }
+            }
+        }
+    }
+
+    /**
+     * Filter out cllId to be deleted
+     * @param allValidCllInstances
+     * @param currentCllInstances
+     * @return
+     */
+    public Set<String> filterInvalidCllIds(Set<String> allValidCllInstances, Set<String> currentCllInstances) {
+        Set<String> invalidCllInstances = new HashSet<>(currentCllInstances);
+        invalidCllInstances.removeAll(allValidCllInstances);
+        return invalidCllInstances;
+    }
+
+    /**
      * Update provisioned bandwidth to given bandwidth value;
      * if @param{override} is false, only write the bandwidth if it is absent.
      * Otherwise override the old value no matter if it exists or not
@@ -141,8 +246,7 @@
      * @return whether bandwidth value is changed or not.
      */
     public boolean updateProvBw(String cllId, int bw, boolean override){
-        if (!override && !endpointToProvBw.containsKey(cllId)){
-            endpointToProvBw.put(cllId, bw);
+        if ( endpointToProvBw.putIfAbsent(cllId, bw) == null || !override){
             return true;
         } else {
             if (endpointToProvBw.get(cllId) == bw){
diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FixedUpperBoundStrategy.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FixedUpperBoundStrategy.java
index 874e327..ec864aa 100644
--- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FixedUpperBoundStrategy.java
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FixedUpperBoundStrategy.java
@@ -3,6 +3,7 @@
  *  slice-analysis-ms
  *  ================================================================================
  *   Copyright (C) 2022 Huawei Canada Limited.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *  ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -34,6 +35,10 @@
 import java.util.TreeMap;
 import java.util.stream.Collectors;
 
+/**
+ * Threshold strategy can be configured via configuration
+ * If "sliceanalysisms.ccvpnEvalStrategy" is set to "FixedUpperBoundStrategy", then this class is triggered.
+ */
 @Component
 public class FixedUpperBoundStrategy implements EvaluationStrategy{
     private static Logger log = LoggerFactory.getLogger(FixedUpperBoundStrategy.class);
@@ -46,7 +51,7 @@
     /**
      * Percentage threshold of bandwidth adjustment.
      */
-    private static double threshold;
+    private static double upperThreshold;
 
     /**
      * Precision of bandwidth evaluation and adjustment.
@@ -67,6 +72,11 @@
         loadConfig();
     }
 
+    /**
+     * Periodically ensure endpoint bw adjustment is under assurance.
+     * This method will be invoked when FixedUpperBoundStrategy is set.
+     * @param event
+     */
     @Override
     public void execute(Event event){
         if (event.type() == SimpleEvent.Type.PERIODIC_CHECK && isPeriodicCheckOn()){
@@ -77,14 +87,18 @@
                 String serviceId = entry.getKey().getCllId();
                 Object[] usedBws = entry.getValue().tryReadToArray();
 
+                if (!ccvpnPmDatastore.getClosedloopStatus(serviceId)) {
+                    log.info("CCVPN Evaluator Output: service {}, closed loop bw modification is off.", serviceId);
+                    continue;
+                }
                 if (usedBws == null) {
                     // No enough data for evaluating
-                    log.debug("CCVPN Evaluator Output: service {}, not enough data to evaluate", serviceId);
+                    log.info("CCVPN Evaluator Output: service {}, not enough data to evaluate", serviceId);
                     continue;
                 }
                 if (ccvpnPmDatastore.getProvBwOfSvc(serviceId) == 0) {
                     // Max bandwidth not cached yet
-                    log.debug("CCVPN Evaluator Output: service {}, max bandwidth not cached, wait for next round", serviceId);
+                    log.info("CCVPN Evaluator Output: service {}, max bandwidth not cached, wait for next round", serviceId);
                     post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, serviceId));
                     continue;
                 }
@@ -110,33 +124,39 @@
             // fetch the provisioned bandwidth info if underMaintenance; otherwise send modification request
             for(Map.Entry<String, Integer> entry: candidate.entrySet()) {
                 //still doing adjustment
-                if (isServiceUnderMaintenance(entry.getKey())) {
-                    if (entry.getValue() == 0){
-                        log.debug("CCVPN Evaluator Output: service {}," +
-                                " is in maintenance state, fetching bandwidth info from AAI", entry.getKey());
+                String cllId = entry.getKey();
+                Integer newBw = entry.getValue();
+                if(!ccvpnPmDatastore.getClosedloopStatus(cllId)) {
+                    log.info("CCVPN Evaluator Output: service {} is not under closed loop assurance", cllId);
+                    continue;
+                }
+                if (isServiceUnderMaintenance(cllId)) {
+                    if (newBw == 0){
+                        log.info("CCVPN Evaluator Output: service {}," +
+                            " is in maintenance state, fetching bandwidth info from AAI", cllId);
                     } else {
-                        log.debug("CCVPN Evaluator Output: candidate {}," +
-                                " need an adjustment, but skipped due to in maintenance state", entry.getKey());
+                        log.info("CCVPN Evaluator Output: candidate {}," +
+                            " need an adjustment, but skipped due to in maintenance state", cllId);
                     }
-                    post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, entry.getKey()));
+                    post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, cllId));
                     continue;
                 }
                 //not in the mid of adjustment; we are free to adjust.
                 log.info("CCVPN Evaluator Output: candidate {}," +
-                        " need an adjustment, sending request to policy", entry.getKey());
+                    " need an adjustment, sending request to policy", entry.getKey());
                 ccvpnPmDatastore.updateSvcState(entry.getKey(), ServiceState.UNDER_MAINTENANCE);
-                sendModifyRequest(entry.getKey(), entry.getValue(), RequestOwner.DCAE);
+                sendModifyRequest(entry.getKey(), newBw, RequestOwner.DCAE);
             }
             log.debug("=== Processing periodic check complete ===");
         }
         if (event.type() == SimpleEvent.Type.ONDEMAND_CHECK && isOnDemandCheckOn()) {
-            log.debug("=== Processing upperbound adjustment request: {} ===", event.time());
+            log.info("=== Processing upperbound adjustment request: {} ===", event.time());
             JsonObject payload = (JsonObject) event.subject();
             String serviceId = payload.get(SERVICE_INSTANCE_LOCATION_ID).getAsString();
             int newBandwidth = payload.get(BANDWIDTH_TOTAL).getAsInt();
             log.info("Update service {} bandwidth upperbound to {} ", serviceId, newBandwidth);
             ccvpnPmDatastore.updateUpperBoundBw(serviceId, newBandwidth);
-            log.debug("=== Processing upperbound adjustment complete ===");
+            log.info("=== Processing upperbound adjustment complete ===");
         }
     }
 
@@ -155,7 +175,7 @@
 
     private void loadConfig() {
         configuration = Configuration.getInstance();
-        threshold = configuration.getCcvpnEvalThreshold();
+        upperThreshold = configuration.getCcvpnEvalUpperThreshold();
         precision = configuration.getCcvpnEvalPrecision(); // in Mbps;
     }
 
@@ -179,9 +199,9 @@
     }
     // check if an adjustment is necessary
     private boolean needAdjust(String serivceId, double used, int provBandwidth, int upper){
-        log.debug("CCVPN Service Usage Analysis: usage: {}, threshold: {}, currentProvisioned {}, upperbound {}",
-                used, threshold, provBandwidth, upper);
-        return provBandwidth > upper || used > threshold * provBandwidth;
+        log.info("CCVPN Service Usage Analysis: usage: {}, threshold: {}, currentProvisioned {}, upperbound {}",
+            used, upperThreshold, provBandwidth, upper);
+        return provBandwidth > upper || used > upperThreshold * provBandwidth;
     }
 
     // calculate new bandwidth to accomodate customer
@@ -189,7 +209,7 @@
         if (cur >= upper){
             return upper;
         }
-        int expected = (int) (Math.ceil((used / threshold) * 1.2 / precision) * precision);
+        int expected = (int) (Math.ceil((used / upperThreshold) * 1.2 / precision) * precision);
         return Math.min(expected, upper);
     }
     // check is service under maint
diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategy.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategy.java
index d60c3ea..261794c 100644
--- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategy.java
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategy.java
@@ -3,6 +3,7 @@
  *  slice-analysis-ms
  *  ================================================================================
  *   Copyright (C) 2022 Huawei Canada Limited.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *  ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -20,18 +21,220 @@
  *******************************************************************************/
 package org.onap.slice.analysis.ms.service.ccvpn;
 
+import com.google.gson.JsonObject;
+import org.onap.slice.analysis.ms.models.Configuration;
+import org.onap.slice.analysis.ms.service.PolicyService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.PostConstruct;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+/**
+ * Threshold strategy can be configured via configuration
+ * If "sliceanalysisms.ccvpnEvalStrategy" is set to "FlexibleThresholdStrategy", then this class is triggered.
+ */
 @Component
-public class FlexibleThresholdStrategy implements EvaluationStrategy {
+public class FlexibleThresholdStrategy implements EvaluationStrategy{
+    private static Logger log = LoggerFactory.getLogger(FixedUpperBoundStrategy.class);
+    private Configuration configuration;
     private static final String TYPE_NAME = "FlexibleThresholdStrategy";
+    private static final String SERVICE_INSTANCE_LOCATION_ID = "service-instance-location-id";
+    private static final String BANDWIDTH_TOTAL = "bandwidth-total";
+
+    /**
+     * Percentage threshold of bandwidth increase adjustment.
+     */
+    private static double upperThreshold;
+
+    /**
+     * Percentage threshold of bandwidth decrease adjustment.
+     */
+    private static double lowerThreshold;
+
+    /**
+     * Precision of bandwidth evaluation and adjustment.
+     */
+    private static double precision; // in Mbps;
+
+    @Autowired
+    BandwidthEvaluator bandwidthEvaluator;
+
+    @Autowired
+    CCVPNPmDatastore ccvpnPmDatastore;
+
+    @Autowired
+    PolicyService policyService;
+
+    @PostConstruct
+    public void init() {
+        loadConfig();
+    }
+
+    /**
+     * Periodically ensure endpoint bw adjustment is under assurance.
+     * This method will be invoked when FlexibleThresholdStrategy is set.
+     * @param event
+     */
     @Override
-    public void execute(Event event) {
-        return;
+    public void execute(Event event){
+        if (event.type() == SimpleEvent.Type.PERIODIC_CHECK && isPeriodicCheckOn()){
+            log.info("=== Processing new periodic check request: {} ===", event.time());
+            Map<Endpointkey, CCVPNPmDatastore.EvictingQueue<Integer>> usedBwMap = ccvpnPmDatastore.getUsedBwMap();
+            Map<String, Integer> candidate = new TreeMap<>();
+            for(Map.Entry<Endpointkey, CCVPNPmDatastore.EvictingQueue<Integer>> entry: usedBwMap.entrySet()) {
+                String serviceId = entry.getKey().getCllId();
+                Object[] usedBws = entry.getValue().tryReadToArray();
+                // Judge whether this cll is under closed loop assurance
+                if (!ccvpnPmDatastore.getClosedloopStatus(serviceId)) {
+                    log.info("CCVPN Evaluator Output: service {}, closed loop bw modification is off.", serviceId);
+                    continue;
+                }
+                if (usedBws == null) {
+                    // Not enough data for evaluating
+                    log.info("CCVPN Evaluator Output: service {}, not enough data to evaluate", serviceId);
+                    continue;
+                }
+                if (ccvpnPmDatastore.getProvBwOfSvc(serviceId) == 0) {
+                    // Max bandwidth not cached yet
+                    log.info("CCVPN Evaluator Output: service {}, max bandwidth not cached, wait for next round", serviceId);
+                    post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, serviceId));
+                    continue;
+                }
+                double avg = Arrays.stream(usedBws)
+                    .mapToInt(o -> (int) o)
+                    .summaryStatistics()
+                    .getAverage();
+                int provBw = ccvpnPmDatastore.getProvBwOfSvc(serviceId);
+                int originalBw = ccvpnPmDatastore.getOriginalBw(serviceId);
+
+                if(needIncrease(serviceId, avg, provBw)){
+                    int newBw = (int) (Math.ceil((avg / upperThreshold) * 1.2 / precision) * precision);
+                    log.info("For cll {}, going to increase bw to {}", serviceId, newBw);
+                    candidate.put(serviceId, Math.max(candidate.getOrDefault(serviceId, 0), newBw));
+                } else {
+                    if(needDecrease(serviceId, avg, provBw, originalBw)) {
+                        int newBw = Math.max((int) (Math.ceil(provBw * 0.5)), originalBw);
+                        log.info("For cll {}, going to decrease bw to {}", serviceId, newBw);
+                        candidate.put(serviceId, Math.max(candidate.getOrDefault(serviceId, 0), newBw));
+                    }
+                }
+            }
+            // check svc under maintenance
+            Map<String , ServiceState> svcUnderMaintenance = getServicesUnderMaintenance();
+            for (Map.Entry<String, ServiceState> entry: svcUnderMaintenance.entrySet()){
+                candidate.putIfAbsent(entry.getKey(), 0);
+            }
+            // fetch the provisioned bandwidth info if underMaintenance; otherwise send modification request
+            for(Map.Entry<String, Integer> entry: candidate.entrySet()) {
+                //still doing adjustment
+                String cllId = entry.getKey();
+                Integer newBw = entry.getValue();
+                if(!ccvpnPmDatastore.getClosedloopStatus(cllId)) {
+                    log.info("CCVPN Evaluator Output: service {} is not under closed loop assurance", cllId);
+                    continue;
+                }
+                if (isServiceUnderMaintenance(cllId)) {
+                    if (newBw == 0){
+                        log.info("CCVPN Evaluator Output: service {}," +
+                            " is in maintenance state, fetching bandwidth info from AAI", cllId);
+                    } else {
+                        log.info("CCVPN Evaluator Output: candidate {}," +
+                            " need an adjustment, but skipped due to in maintenance state", cllId);
+                    }
+                    post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, cllId));
+                    continue;
+                }
+                //not in the mid of adjustment; we are free to adjust.
+                log.info("CCVPN Evaluator Output: candidate {}," +
+                    " need an adjustment, sending request to policy, service state changed to under maintenance", entry.getKey());
+                ccvpnPmDatastore.updateSvcState(entry.getKey(), ServiceState.UNDER_MAINTENANCE);
+                sendModifyRequest(entry.getKey(), newBw, RequestOwner.DCAE);
+            }
+            log.debug("=== Processing periodic check complete ===");
+        } else if (event.type() == SimpleEvent.Type.ONDEMAND_CHECK && isOnDemandCheckOn()) {
+            log.info("=== Processing upperbound adjustment request: {} ===", event.time());
+            JsonObject payload = (JsonObject) event.subject();
+            String serviceId = payload.get(SERVICE_INSTANCE_LOCATION_ID).getAsString();
+            int newBandwidth = payload.get(BANDWIDTH_TOTAL).getAsInt();
+            log.info("Update service {} bandwidth upperbound to {} ", serviceId, newBandwidth);
+            ccvpnPmDatastore.updateUpperBoundBw(serviceId, newBandwidth);
+            log.debug("=== Processing upperbound adjustment complete ===");
+        }
     }
 
     @Override
     public String getName() {
         return TYPE_NAME;
     }
+
+    /**
+     * Post/broadcast event to the BandwidthEvaluator
+     * @param event event object
+     */
+    private void post(Event event){
+        bandwidthEvaluator.post(event);
+    }
+
+    private void loadConfig() {
+        configuration = Configuration.getInstance();
+        upperThreshold = configuration.getCcvpnEvalUpperThreshold();
+        lowerThreshold = configuration.getCcvpnEvalLowerThreshold();
+        precision = configuration.getCcvpnEvalPrecision(); // in Mbps;
+    }
+
+    private boolean isPeriodicCheckOn() {
+        configuration = Configuration.getInstance();
+        return configuration.isCcvpnEvalPeriodicCheckOn();
+    }
+
+    private boolean isOnDemandCheckOn() {
+        configuration = Configuration.getInstance();
+        return configuration.isCcvpnEvalOnDemandCheckOn();
+    }
+
+    // send modification requestion
+    private void sendModifyRequest(String cllId, Integer newBandwidth, RequestOwner owner) {
+        log.info("Sending modification request to policy. RequestOwner: {} - Service: {} change to bw: {}",
+            owner, cllId, newBandwidth);
+        policyService.sendOnsetMessageToPolicy(
+            policyService.formPolicyOnsetMessageForCCVPN(cllId, newBandwidth, owner)
+        );
+    }
+
+    private boolean needIncrease(String serviceId, double currAvgUsage, int provBw) {
+        log.info("For service {} judge whether to increase, currAvg bw {}, maxBw {}", serviceId, currAvgUsage, provBw);
+        if ( currAvgUsage > upperThreshold * provBw ) {
+            log.info("decide to increase");
+            return true;
+        }
+        return false;
+    }
+
+    private boolean needDecrease(String serviceId, double currAvgUsage, int provBw, int originalBw) {
+        log.info("For service {} judge whether to decrease, original bw {}, currAvg bw {}, prov {}", serviceId, originalBw, currAvgUsage, provBw);
+        if( currAvgUsage < lowerThreshold * provBw) {
+            log.info("decide to decrease");
+            return true;
+        }
+        return false;
+    }
+
+    // check is service under maintenance
+    private boolean isServiceUnderMaintenance(String serivceId) {
+        return ccvpnPmDatastore.getStatusOfSvc(serivceId) == ServiceState.UNDER_MAINTENANCE;
+    }
+
+    // get a collection of service under maintenance
+    private Map<String, ServiceState> getServicesUnderMaintenance(){
+        return ccvpnPmDatastore.getSvcStatusMap().entrySet()
+            .stream()
+            .filter(e -> e.getValue() == ServiceState.UNDER_MAINTENANCE)
+            .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));
+    }
 }
diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/utils/SpringContextUtil.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/utils/SpringContextUtil.java
new file mode 100644
index 0000000..ebe227d
--- /dev/null
+++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/utils/SpringContextUtil.java
@@ -0,0 +1,52 @@
+/*******************************************************************************

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

+ *   slice-analysis-ms

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

+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.

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

+ *     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.

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

+ *

+ *******************************************************************************/

+

+package org.onap.slice.analysis.ms.utils;

+

+import org.springframework.beans.BeansException;

+import org.springframework.context.ApplicationContext;

+import org.springframework.context.ApplicationContextAware;

+import org.springframework.context.annotation.Configuration;

+

+/**

+ * This is provided for threads to get bean.

+ */

+@Configuration

+public class SpringContextUtil implements ApplicationContextAware {

+    private static ApplicationContext applicationContext = null;

+

+    @Override

+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

+        SpringContextUtil.applicationContext = applicationContext;

+    }

+

+    public static ApplicationContext getApplicationContext() {

+        return applicationContext;

+    }

+

+    public static Object getBean(String beanName) {

+        return applicationContext.getBean(beanName);

+    }

+

+    public static Object getBean(Class c) {

+        return applicationContext.getBean(c);

+    }

+}

diff --git a/components/slice-analysis-ms/src/main/resources/logback.xml b/components/slice-analysis-ms/src/main/resources/logback.xml
index d727d05..134c25d 100644
--- a/components/slice-analysis-ms/src/main/resources/logback.xml
+++ b/components/slice-analysis-ms/src/main/resources/logback.xml
@@ -7,6 +7,7 @@
  *   Copyright (C) 2020 Wipro Limited.
  *   Copyright (C) 2022 Huawei Canada Limited.
  *   Copyright (C) 2022 CTC, Inc.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *   ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -33,7 +34,7 @@
         </layout>
     </appender>
 
-    <root level="debug">
+    <root level="info">
         <appender-ref ref="CONSOLE"/>
     </root>
 
diff --git a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/AaiEventNotificationCallbackTest.java b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/AaiEventNotificationCallbackTest.java
index 1674519..9fce12f 100644
--- a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/AaiEventNotificationCallbackTest.java
+++ b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/AaiEventNotificationCallbackTest.java
@@ -4,6 +4,7 @@
  *  ================================================================================
  *  Copyright (C) 2022 Huawei Canada Limited.
  *  Copyright (C) 2022 CTC, Inc.
+ *  Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *  ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -83,7 +84,8 @@
         jsonObject.addProperty("sliceanalysisms.vesNotifChangeType", "1");
         jsonObject.addProperty("sliceanalysisms.vesNotifPollingInterval", "1");
         jsonObject.addProperty("sliceanalysisms.ccvpnEvalInterval", "1");
-        jsonObject.addProperty("sliceanalysisms.ccvpnEvalThreshold", "1");
+        jsonObject.addProperty("sliceanalysisms.ccvpnEvalUpperThreshold", "1");
+        jsonObject.addProperty("sliceanalysisms.ccvpnEvalLowerThreshold", "1");
         jsonObject.addProperty("sliceanalysisms.ccvpnEvalPrecision", "1");
         jsonObject.addProperty("sliceanalysisms.ccvpnEvalPeriodicCheckOn", "1");
         jsonObject.addProperty("sliceanalysisms.ccvpnEvalOnDemandCheckOn", "1");
diff --git a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallbackTest.java b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallbackTest.java
index 74f75a8..97ee9fa 100644
--- a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallbackTest.java
+++ b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallbackTest.java
@@ -4,6 +4,7 @@
  *  ================================================================================
  *   Copyright (C) 2020 Wipro Limited.
  *   Copyright (C) 2022 Huawei Canada Limited.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *   ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -22,12 +23,20 @@
 package org.onap.slice.analysis.ms.dmaap;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.HashSet;
+import java.util.Set;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
+import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.Spy;
+import org.onap.slice.analysis.ms.aai.AaiService;
+import org.onap.slice.analysis.ms.service.ccvpn.CCVPNPmDatastore;
+import org.powermock.api.mockito.PowerMockito;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.IOException;
@@ -39,6 +48,12 @@
 public class VesNotificationCallbackTest {
     ObjectMapper obj = new ObjectMapper();
 
+    @Mock
+    AaiService aaiService;
+
+    @Mock
+    CCVPNPmDatastore ccvpnPmDatastore;
+
     @Spy
     @InjectMocks
     VesNotificationCallback vesNotificationCallback;
@@ -57,6 +72,11 @@
         } catch (IOException e) {
             e.printStackTrace();
         }
+        Set<String> cllInstances = new HashSet<>();
+        cllInstances.add("cll-01");
+        cllInstances.add("cll-02");
+        Mockito.when(aaiService.fetchAllCllInstances()).thenReturn(cllInstances);
+        Mockito.doNothing().when(ccvpnPmDatastore).updateCllInstances(Mockito.any());
         vesNotificationCallback.activateCallBack(input);
         Mockito.verify(vesNotificationCallback, Mockito.atLeastOnce()).activateCallBack(Mockito.anyString());
     }
diff --git a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/models/ConfigurationTest.java b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/models/ConfigurationTest.java
index 3d9b58d..7837909 100644
--- a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/models/ConfigurationTest.java
+++ b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/models/ConfigurationTest.java
@@ -4,6 +4,7 @@
  *  ================================================================================
  *   Copyright (C) 2020-2021 Wipro Limited.
  *   Copyright (C) 2022 Huawei Canada Limited.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *   ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -58,7 +59,9 @@
         configuration.setVesNotifChangeType("BandwidthChanged");
         configuration.setCcvpnEvalInterval(5);
         configuration.setCcvpnEvalPrecision(100);
-        configuration.setCcvpnEvalThreshold(0.8);
+        configuration.setCcvpnEvalUpperThreshold(0.8);
+        configuration.setCcvpnEvalLowerThreshold(0.3);
+        configuration.setCcvpnEvalStrategy("FlexibleThresholdStrategy");
         assertEquals(true,configuration.isSecured());
         assertEquals("user", configuration.getAafUsername());
         assertEquals("password", configuration.getAafPassword());
@@ -85,6 +88,8 @@
         assertEquals("BandwidthChanged", configuration.getVesNotifChangeType());
         assertEquals(5, configuration.getCcvpnEvalInterval());
         assertEquals(100.0, configuration.getCcvpnEvalPrecision(), 0.001);
-        assertEquals(0.8, configuration.getCcvpnEvalThreshold(), 0.001);
+        assertEquals(0.8, configuration.getCcvpnEvalUpperThreshold(), 0.001);
+        assertEquals(0.3, configuration.getCcvpnEvalLowerThreshold(), 0.001);
+        assertEquals("FlexibleThresholdStrategy", configuration.getCcvpnEvalStrategy());
     }
 }
diff --git a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastoreTest.java b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastoreTest.java
index 673ec6a..8b0b99f 100644
--- a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastoreTest.java
+++ b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastoreTest.java
@@ -3,6 +3,7 @@
  *  slice-analysis-ms
  *  ================================================================================
  *   Copyright (C) 2022 Huawei Canada Limited.
+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.
  *   ==============================================================================
  *     Licensed under the Apache License, Version 2.0 (the "License");
  *     you may not use this file except in compliance with the License.
@@ -21,6 +22,8 @@
 
 package org.onap.slice.analysis.ms.service.ccvpn;
 
+import java.util.HashSet;
+import java.util.Set;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
@@ -119,4 +122,28 @@
                 .mapToInt(o -> (int)o)
                 .sum() == 300602 );
     }
+
+    @Test
+    public void updateCllInstancesTest() {
+        datastore.addUsedBwToEndpoint("cll-01", "uni-n1", "300Mb");
+        datastore.updateUpperBoundBw("cll-01", 300);
+        datastore.updateProvBw("cll-01", "300");
+        datastore.updateSvcState("cll-01", ServiceState.RUNNING);
+        datastore.updateOriginalBw("cll-01", 1000);
+        datastore.updateClosedloopStatus("cll-01", true);
+        datastore.addUsedBwToEndpoint("cll-02", "uni-n2", "300Mb");
+        datastore.updateUpperBoundBw("cll-02", 300);
+        datastore.updateProvBw("cll-02", "300");
+        datastore.updateSvcState("cll-02", ServiceState.RUNNING);
+        datastore.updateOriginalBw("cll-02", 1000);
+        datastore.updateClosedloopStatus("cll-02", true);
+        Set<String> cllId = new HashSet<>();
+        cllId.add("cll-01");
+        datastore.updateCllInstances(cllId);
+        assertEquals(datastore.getEndpointToUsedBw().keySet().size(), 1);
+        assertEquals(datastore.getUpperBoundBw().keySet().equals(cllId), true);
+        assertEquals(datastore.getEndpointToProvBw().keySet().equals(cllId), true);
+        assertEquals(datastore.getSvcStatus().keySet().equals(cllId), true);
+        assertEquals(datastore.getEndpointToOriginalBw().keySet().equals(cllId), true);
+    }
 }
diff --git a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategyTest.java b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategyTest.java
new file mode 100644
index 0000000..4002892
--- /dev/null
+++ b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategyTest.java
@@ -0,0 +1,69 @@
+/*******************************************************************************

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

+ *  slice-analysis-ms

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

+ *   Copyright (C) 2022 Huawei Technologies Co., Ltd.

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

+ *     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.

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

+ *

+ *******************************************************************************/

+package org.onap.slice.analysis.ms.service.ccvpn;

+

+import org.junit.Before;

+import org.junit.Test;

+import org.junit.runner.RunWith;

+import org.mockito.InjectMocks;

+import org.mockito.Mockito;

+import org.mockito.MockitoAnnotations;

+import org.mockito.Spy;

+import org.springframework.boot.test.context.SpringBootTest;

+import org.springframework.test.context.junit4.SpringRunner;

+

+@RunWith(SpringRunner.class)

+@SpringBootTest(classes = FixedUpperBoundStrategyTest.class)

+public class FlexibleThresholdStrategyTest {

+

+    @Spy

+    @InjectMocks

+    BandwidthEvaluator bandwidthEvaluator;

+

+    @Spy

+    @InjectMocks

+    FlexibleThresholdStrategy flexibleThresholdStrategy;

+

+    @Before

+    public void setUp() throws Exception {

+        MockitoAnnotations.initMocks(this);

+    }

+

+    @Test

+    public void initTest() {

+        flexibleThresholdStrategy.init();

+        Mockito.verify(flexibleThresholdStrategy, Mockito.atLeastOnce()).init();

+    }

+

+    @Test

+    public void executeTest() {

+        Event evt = new SimpleEvent(null, "{}");

+        flexibleThresholdStrategy.execute(evt);

+        Mockito.verify(flexibleThresholdStrategy, Mockito.atLeastOnce())

+            .execute(Mockito.any(Event.class));

+    }

+

+    @Test

+    public void getNameTest() {

+        flexibleThresholdStrategy.getName();

+        Mockito.verify(flexibleThresholdStrategy, Mockito.atLeastOnce()).getName();

+    }

+}

diff --git a/components/slice-analysis-ms/src/test/resources/config_all.json b/components/slice-analysis-ms/src/test/resources/config_all.json
index f37e438..fc18cc1 100644
--- a/components/slice-analysis-ms/src/test/resources/config_all.json
+++ b/components/slice-analysis-ms/src/test/resources/config_all.json
@@ -106,7 +106,8 @@
     "sliceanalysisms.aaiNotif.targetSource" : "UUI",
     "sliceanalysisms.aaiNotif.targetEntity" : "service-instance",
     "sliceanalysisms.ccvpnEvalInterval": 5,
-    "sliceanalysisms.ccvpnEvalThreshold": 0.8,
+    "sliceanalysisms.ccvpnEvalUpperThreshold": 0.8,
+    "sliceanalysisms.ccvpnEvalLowerThreshold": 0.3,
     "sliceanalysisms.ccvpnEvalPrecision": 100.0,
     "sliceanalysisms.ccvpnEvalPeriodicCheckOn": true,
     "sliceanalysisms.ccvpnEvalOnDemandCheckOn": true,